Varaverk: arrange mode, folder management, rsync standalone, layout fixes
Scheduler UI: - Arrange mode: drag scripts between orchs and reorder within arrays; right panel shows unassigned script pool; Save Arrangement commits to master.conf - + Folder: named collapsible subfolders for Custom Scripts stored in schedule.json - Rsync children: hide Run/Dry Run/Log/location when orch is ON; show standalone location + cron controls when orch is OFF; cron only fires when both filled - Non-conf-managed children (transcode): toggles now show enabled when orch is on - Right panel height sync: fix ResizeObserver feedback loop via align-self:flex-start on left panel and left.offsetHeight in vvFitRight - How do I use this: updated to cover arrange, folders, rsync standalone, transcode New API endpoints: - board.php, clearlock.php, movescript.php, rawconf.php, readscript.php - reorderarray.php, rsync_standalone.php, savefolders.php run.php / dryrun.php: accept optional --location= arg for standalone rsync calls
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// Live board data: locks, recent errors, partner reachability.
|
||||
header('Content-Type: application/json');
|
||||
require_once dirname(__DIR__) . '/include/config.php';
|
||||
|
||||
$out = ['ok' => true];
|
||||
|
||||
// ── Active locks ──────────────────────────────────────────────────────────
|
||||
$lockDir = '/tmp/unraid_locks';
|
||||
$locks = [];
|
||||
if (is_dir($lockDir)) {
|
||||
foreach (glob($lockDir . '/*.lock') ?: [] as $lf) {
|
||||
$name = basename($lf, '.lock');
|
||||
$age = time() - (int)filemtime($lf);
|
||||
$content = trim(file_get_contents($lf) ?: '');
|
||||
// content is "PID:scriptname" — extract PID
|
||||
$pid = preg_match('/^(\d+)/', $content, $pm) ? $pm[1] : '';
|
||||
// Skip if PID is still alive (it's legitimately running)
|
||||
if ($pid && file_exists("/proc/$pid")) continue;
|
||||
$locks[] = ['name' => $name, 'file' => basename($lf), 'age' => $age];
|
||||
}
|
||||
}
|
||||
$out['locks'] = $locks;
|
||||
|
||||
// ── Recent errors ──────────────────────────────────────────────────────────
|
||||
$errors = [];
|
||||
if (is_dir(LOG_DIR)) {
|
||||
$cutoff = time() - 7 * 86400; // only logs touched in last 7 days
|
||||
foreach (glob(LOG_DIR . '/*.log') ?: [] as $lf) {
|
||||
if (filemtime($lf) < $cutoff) continue;
|
||||
$script = basename($lf, '.log');
|
||||
$lines = array_slice(@file($lf) ?: [], -200);
|
||||
$lastErr = null;
|
||||
foreach (array_reverse($lines) as $raw) {
|
||||
// Strip ANSI escape codes
|
||||
$clean = preg_replace('/\033\[[0-9;]*[mK]/', '', rtrim($raw));
|
||||
if (!$clean) continue;
|
||||
if (preg_match('/\[(?:ERROR|WARN|CRITICAL|FAILED)\]/i', $clean) ||
|
||||
preg_match('/\b(?:ERROR|CRITICAL|FAILED):\s/i', $clean) ||
|
||||
str_contains($clean, '✗') ||
|
||||
(str_contains($clean, '⚠') && !str_contains($clean, '♥'))) {
|
||||
$lastErr = mb_substr($clean, 0, 220);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($lastErr !== null) {
|
||||
$errors[] = ['script' => $script, 'line' => $lastErr, 'ts' => (int)filemtime($lf)];
|
||||
}
|
||||
}
|
||||
usort($errors, fn($a, $b) => $b['ts'] - $a['ts']);
|
||||
}
|
||||
$out['errors'] = array_slice($errors, 0, 20);
|
||||
|
||||
// ── Partner reachability ───────────────────────────────────────────────────
|
||||
$cacheFile = '/tmp/vv_partner_cache.json';
|
||||
$cacheTtl = 30;
|
||||
$partnerData = null;
|
||||
|
||||
if (file_exists($cacheFile) && (time() - (int)filemtime($cacheFile)) < $cacheTtl) {
|
||||
$partnerData = json_decode(file_get_contents($cacheFile), true);
|
||||
} else {
|
||||
$confRaw = vv_read_conf_raw('master.conf');
|
||||
preg_match('/^\s*HOST1(?:_NAME)?\s*=\s*["\']?(\S+?)["\']?\s*(?:#.*)?$/m', $confRaw, $m1);
|
||||
preg_match('/^\s*HOST2(?:_NAME)?\s*=\s*["\']?(\S+?)["\']?\s*(?:#.*)?$/m', $confRaw, $m2);
|
||||
$host1 = $m1[1] ?? '';
|
||||
$host2 = $m2[1] ?? '';
|
||||
$mine = vv_get_hostname();
|
||||
$partnerHost = null;
|
||||
if ($mine && $host1 && strcasecmp($mine, $host1) === 0) $partnerHost = $host2;
|
||||
if ($mine && $host2 && strcasecmp($mine, $host2) === 0) $partnerHost = $host1;
|
||||
|
||||
if ($partnerHost) {
|
||||
$start = microtime(true);
|
||||
$result = shell_exec('ping -c1 -W1 ' . escapeshellarg($partnerHost) . ' 2>&1');
|
||||
$elapsed = (int)round((microtime(true) - $start) * 1000);
|
||||
$reached = str_contains((string)$result, '1 received')
|
||||
|| str_contains((string)$result, '1 packets received');
|
||||
$partnerData = [
|
||||
'host' => $partnerHost,
|
||||
'reachable' => $reached,
|
||||
'latency' => $reached ? $elapsed : null,
|
||||
];
|
||||
@file_put_contents($cacheFile, json_encode($partnerData));
|
||||
}
|
||||
}
|
||||
$out['partner'] = $partnerData;
|
||||
|
||||
echo json_encode($out);
|
||||
Reference in New Issue
Block a user