Auth stack certs tab, arrs db fallbacks, cert monitor cache, conf parser fix
- Auth stack: fold cert monitor into Auth Stack page as fourth tab (Certs); remove standalone cert page and top-level tab - cert_monitor.sh: write JSON status cache to State_Files/cert_status.json after each run; expose per-domain days/expiry via _CERT_DAYS/_CERT_EXPIRY globals - api/cert.php: new — serves cached cert status; falls back to configured domains as UNKN when no cache exists; POST action=run triggers live check - arrs db fallbacks: vv_arr_cleanup_stats/discovery_stats/recovery_stats now read from data/*.db files when log JSON files don't yet exist - config.php vv_conf_vars(): unescape bash \$ → $ so passwords with dollar signs read correctly from conf files - host1.conf: fill in HOST1_NPM_USER/PASS and HOST1_LLDAP_USER/PASS - Partnership adapter pattern: Unraid-specific container logic extracted to Plugin/unraid/Partnership/; platform-agnostic structure stays in Partnership/ - First-run wizard: uniform multi-step flow for all hosts; HOST2 pull moved to checklist; auto SSH keygen and API key creation on save - api/checklist.php: live setup checklist with pull_master action - Fullscreen toggle: hide Unraid header/menu; state persists via localStorage
This commit is contained in:
+103
-37
@@ -131,29 +131,51 @@ function vv_arr_cleanup_stats(string $type): array {
|
||||
'orphans' => 0, 'orphans_sz' => '0B', 'junk' => 0];
|
||||
|
||||
$jf = $base . '.json';
|
||||
if (!file_exists($jf)) return $out;
|
||||
$meta = json_decode(file_get_contents($jf), true) ?: [];
|
||||
$out['last_run'] = $meta['start'] ?? null;
|
||||
$out['end'] = $meta['end'] ?? null;
|
||||
$out['status'] = $meta['status'] ?? null;
|
||||
if (file_exists($jf)) {
|
||||
$meta = json_decode(file_get_contents($jf), true) ?: [];
|
||||
$out['last_run'] = $meta['start'] ?? null;
|
||||
$out['end'] = $meta['end'] ?? null;
|
||||
$out['status'] = $meta['status'] ?? null;
|
||||
|
||||
$lf = $base . '.log';
|
||||
if (!file_exists($lf)) return $out;
|
||||
$log = file_get_contents($lf);
|
||||
$parts = preg_split('/━{3,}[^\n]*SUMMARY[^\n]*/u', $log);
|
||||
$blk = count($parts) > 1 ? end($parts) : $log;
|
||||
$lf = $base . '.log';
|
||||
if (file_exists($lf)) {
|
||||
$log = file_get_contents($lf);
|
||||
$parts = preg_split('/━{3,}[^\n]*SUMMARY[^\n]*/u', $log);
|
||||
$blk = count($parts) > 1 ? end($parts) : $log;
|
||||
|
||||
if (preg_match('/Tracked:\s*([\d,]+)\s*files\s*\(([\d,]+)/u', $blk, $m)) {
|
||||
$out['tracked'] = (int)str_replace(',', '', $m[1]);
|
||||
$out['total'] = (int)str_replace(',', '', $m[2]);
|
||||
if (preg_match('/Tracked:\s*([\d,]+)\s*files\s*\(([\d,]+)/u', $blk, $m)) {
|
||||
$out['tracked'] = (int)str_replace(',', '', $m[1]);
|
||||
$out['total'] = (int)str_replace(',', '', $m[2]);
|
||||
}
|
||||
if (preg_match('/Orphans:\s*([\d,]+)\s*files\s*\(([^)]+)\)/u', $blk, $m)) {
|
||||
$out['orphans'] = (int)str_replace(',', '', $m[1]);
|
||||
$out['orphans_sz'] = trim($m[2]);
|
||||
}
|
||||
if (preg_match('/Junk:\s*([\d,]+)\s*files/u', $blk, $m)) {
|
||||
$out['junk'] = (int)str_replace(',', '', $m[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (preg_match('/Orphans:\s*([\d,]+)\s*files\s*\(([^)]+)\)/u', $blk, $m)) {
|
||||
$out['orphans'] = (int)str_replace(',', '', $m[1]);
|
||||
$out['orphans_sz'] = trim($m[2]);
|
||||
}
|
||||
if (preg_match('/Junk:\s*([\d,]+)\s*files/u', $blk, $m)) {
|
||||
$out['junk'] = (int)str_replace(',', '', $m[1]);
|
||||
|
||||
// Fallback: daily aggregate db — date|arr|orphan_count|orphan_bytes|junk_count|junk_bytes|recent_count|tracked_count
|
||||
if ($out['last_run'] === null) {
|
||||
$dbFile = DATA_DIR . '/arr_cleanup_stats.db';
|
||||
if (file_exists($dbFile)) {
|
||||
$last = null;
|
||||
foreach (file($dbFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
|
||||
$p = explode('|', $line);
|
||||
if (count($p) >= 8 && $p[1] === $type) $last = $p;
|
||||
}
|
||||
if ($last) {
|
||||
$out['last_run'] = strtotime($last[0] . ' 23:59:00') ?: null;
|
||||
$out['status'] = 'ok';
|
||||
$out['orphans'] = (int)$last[2];
|
||||
$out['junk'] = (int)$last[4];
|
||||
$out['tracked'] = (int)$last[7];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
@@ -165,17 +187,39 @@ function vv_arr_discovery_stats(string $type): array {
|
||||
$out = ['last_run' => null, 'status' => null, 'added' => null];
|
||||
|
||||
$jf = $base . '.json';
|
||||
if (!file_exists($jf)) return $out;
|
||||
$meta = json_decode(file_get_contents($jf), true) ?: [];
|
||||
$out['last_run'] = $meta['start'] ?? null;
|
||||
$out['status'] = $meta['status'] ?? null;
|
||||
if (file_exists($jf)) {
|
||||
$meta = json_decode(file_get_contents($jf), true) ?: [];
|
||||
$out['last_run'] = $meta['start'] ?? null;
|
||||
$out['status'] = $meta['status'] ?? null;
|
||||
|
||||
$lf = $base . '.log';
|
||||
if (file_exists($lf)) {
|
||||
$log = file_get_contents($lf);
|
||||
if (preg_match('/Added[:\s]+(\d+)/i', $log, $m)) $out['added'] = (int)$m[1];
|
||||
elseif (preg_match('/(\d+)\s+added/i', $log, $m)) $out['added'] = (int)$m[1];
|
||||
$lf = $base . '.log';
|
||||
if (file_exists($lf)) {
|
||||
$log = file_get_contents($lf);
|
||||
if (preg_match('/Added[:\s]+(\d+)/i', $log, $m)) $out['added'] = (int)$m[1];
|
||||
elseif (preg_match('/(\d+)\s+added/i', $log, $m)) $out['added'] = (int)$m[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: per-title history db — status|id|date[|title]
|
||||
if ($out['last_run'] === null) {
|
||||
$dbFile = DATA_DIR . '/' . $type . '_discovery_history.db';
|
||||
if (file_exists($dbFile)) {
|
||||
$lastDate = null; $added = 0;
|
||||
foreach (file($dbFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
|
||||
$p = explode('|', $line);
|
||||
if (count($p) < 3) continue;
|
||||
$date = $p[2];
|
||||
if ($date !== $lastDate) { $lastDate = $date; $added = 0; }
|
||||
if ($p[0] === 'ACCEPT') $added++;
|
||||
}
|
||||
if ($lastDate) {
|
||||
$out['last_run'] = strtotime($lastDate . ' 23:59:00') ?: null;
|
||||
$out['status'] = 'ok';
|
||||
$out['added'] = $added;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
@@ -214,17 +258,39 @@ function vv_arr_recovery_stats(): array {
|
||||
$out = ['last_run' => null, 'status' => null, 'fixed' => 0, 'searched' => 0];
|
||||
|
||||
$jf = $base . '.json';
|
||||
if (!file_exists($jf)) return $out;
|
||||
$meta = json_decode(file_get_contents($jf), true) ?: [];
|
||||
$out['last_run'] = $meta['start'] ?? null;
|
||||
$out['status'] = $meta['status'] ?? null;
|
||||
if (file_exists($jf)) {
|
||||
$meta = json_decode(file_get_contents($jf), true) ?: [];
|
||||
$out['last_run'] = $meta['start'] ?? null;
|
||||
$out['status'] = $meta['status'] ?? null;
|
||||
|
||||
$lf = $base . '.log';
|
||||
if (file_exists($lf)) {
|
||||
$log = file_get_contents($lf);
|
||||
if (preg_match('/Removed[:\s]+(\d+)/i', $log, $m)) $out['fixed'] = (int)$m[1];
|
||||
if (preg_match('/Re-searched[:\s]+(\d+)/i',$log, $m)) $out['searched'] = (int)$m[1];
|
||||
$lf = $base . '.log';
|
||||
if (file_exists($lf)) {
|
||||
$log = file_get_contents($lf);
|
||||
if (preg_match('/Removed[:\s]+(\d+)/i', $log, $m)) $out['fixed'] = (int)$m[1];
|
||||
if (preg_match('/Re-searched[:\s]+(\d+)/i',$log, $m)) $out['searched'] = (int)$m[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: daily aggregate db — date|time|count|bytes
|
||||
if ($out['last_run'] === null) {
|
||||
$dbFile = DATA_DIR . '/arr_recovery_stats.db';
|
||||
if (file_exists($dbFile)) {
|
||||
$lines = file($dbFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
$last = $lines ? end($lines) : null;
|
||||
if ($last) {
|
||||
$p = explode('|', $last);
|
||||
if (count($p) >= 3) {
|
||||
$ts = strtotime(($p[0] ?? '') . ' ' . ($p[1] ?? '00:00')) ?: null;
|
||||
if ($ts) {
|
||||
$out['last_run'] = $ts;
|
||||
$out['status'] = 'ok';
|
||||
$out['fixed'] = (int)($p[2] ?? 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user