From ce9748096c2652433576d2b0045e6c8f79503cd6 Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Fri, 29 May 2026 23:56:15 -0400 Subject: [PATCH] Scheduler: extra args input on script rows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tools and Custom: args input always visible (translucent at rest, full on hover) - Orch children: args input hidden when orch is on, shown when orch is off (same toggle as the cron field — orch off = standalone mode) - vvRunJob/vvDryRun: pick up .vv-script-args value, POST as extra_args - run.php / dryrun.php: accept extra_args, validate against shell metacharacters, append to run_job.sh invocation (flows through SCRIPT_ARGS to the script) - CSS: .vv-script-args — 30% opacity at rest, 100% on hover/focus --- Plugin/unraid/api/dryrun.php | 15 +++++++++---- Plugin/unraid/api/run.php | 27 +++++++++++++++++++---- Plugin/unraid/css/varaverk.css | 6 ++++++ Plugin/unraid/pages/scheduler.php | 36 +++++++++++++++++++++---------- 4 files changed, 65 insertions(+), 19 deletions(-) diff --git a/Plugin/unraid/api/dryrun.php b/Plugin/unraid/api/dryrun.php index dce4766..eb37c0d 100644 --- a/Plugin/unraid/api/dryrun.php +++ b/Plugin/unraid/api/dryrun.php @@ -25,9 +25,16 @@ if ($location && (!str_starts_with($location, '/') || str_contains($location, '. exit; } -$runner = dirname(__DIR__) . '/run_job.sh'; -$flags = vv_job_flags($id); -$locArg = $location ? ' ' . escapeshellarg('--location=' . $location) : ''; -exec('nohup bash ' . escapeshellarg($runner) . ' ' . escapeshellarg($id) . ' ' . escapeshellarg($script) . ' --dry-run' . ($flags ? " $flags" : '') . ' --manual' . $locArg . ' >> ' . escapeshellarg($logFile) . ' 2>&1 \\\\"\']/', $extra_args)) { + echo json_encode(['ok' => false, 'error' => 'Invalid extra_args']); + exit; +} + +$runner = dirname(__DIR__) . '/run_job.sh'; +$flags = vv_job_flags($id); +$locArg = $location ? ' ' . escapeshellarg('--location=' . $location) : ''; +$extraStr = $extra_args ? ' ' . $extra_args : ''; +exec('nohup bash ' . escapeshellarg($runner) . ' ' . escapeshellarg($id) . ' ' . escapeshellarg($script) . ' --dry-run' . ($flags ? " $flags" : '') . ' --manual' . $locArg . $extraStr . ' >> ' . escapeshellarg($logFile) . ' 2>&1 true]); diff --git a/Plugin/unraid/api/run.php b/Plugin/unraid/api/run.php index f56e573..d2025da 100644 --- a/Plugin/unraid/api/run.php +++ b/Plugin/unraid/api/run.php @@ -25,9 +25,28 @@ if ($location && (!str_starts_with($location, '/') || str_contains($location, '. exit; } -$runner = dirname(__DIR__) . '/run_job.sh'; -$flags = vv_job_flags($id); -$locArg = $location ? ' ' . escapeshellarg('--location=' . $location) : ''; -exec('nohup bash ' . escapeshellarg($runner) . ' ' . escapeshellarg($id) . ' ' . escapeshellarg($script) . ($flags ? " $flags" : '') . ' --manual' . $locArg . ' >> ' . escapeshellarg($logFile) . ' 2>&1 \\\\"\']/', $extra_args)) { + echo json_encode(['ok' => false, 'error' => 'Invalid extra_args']); + exit; +} + +// Refuse if already running — scripts will lock-exit anyway, but surface it clearly. +$statFile = vv_job_stat_path($id); +if (file_exists($statFile)) { + $stat = json_decode(file_get_contents($statFile), true) ?: []; + $pid = $stat['pid'] ?? null; + $status = $stat['status'] ?? ''; + if ($status === 'running' && $pid && file_exists("/proc/{$pid}")) { + echo json_encode(['ok' => false, 'already_running' => true, 'error' => 'Already running']); + exit; + } +} + +$runner = dirname(__DIR__) . '/run_job.sh'; +$flags = vv_job_flags($id); +$locArg = $location ? ' ' . escapeshellarg('--location=' . $location) : ''; +$extraStr = $extra_args ? ' ' . $extra_args : ''; +exec('nohup bash ' . escapeshellarg($runner) . ' ' . escapeshellarg($id) . ' ' . escapeshellarg($script) . ($flags ? " $flags" : '') . ' --manual' . $locArg . $extraStr . ' >> ' . escapeshellarg($logFile) . ' 2>&1 true]); diff --git a/Plugin/unraid/css/varaverk.css b/Plugin/unraid/css/varaverk.css index 4dcad05..34b4967 100644 --- a/Plugin/unraid/css/varaverk.css +++ b/Plugin/unraid/css/varaverk.css @@ -761,5 +761,11 @@ code.vv-unknown-var { color: #ff9800; background: #1f130d; } padding: 2px 6px; border-radius: 3px; } .vv-rsync-location:focus { border-color: #555; outline: none; } .vv-rsync-location::placeholder { color: #444; } +.vv-script-args { flex: 1 1 0; min-width: 60px; max-width: 180px; font-size: 11px; font-family: monospace; + background: #111; border: 1px solid #2a2a2a; color: #aaa; + padding: 2px 6px; border-radius: 3px; + opacity: 0.3; transition: opacity 0.15s; } +.vv-script-args:hover, .vv-script-args:focus { opacity: 1; border-color: #555; outline: none; } +.vv-script-args::placeholder { color: #3a3a3a; } .vv-rsync-save-btn { background: #1a2e1a; border-color: #2a4a2a; color: #6aaa6a; } .vv-rsync-save-btn:hover { background: #22382a; } diff --git a/Plugin/unraid/pages/scheduler.php b/Plugin/unraid/pages/scheduler.php index 139b26c..3377179 100644 --- a/Plugin/unraid/pages/scheduler.php +++ b/Plugin/unraid/pages/scheduler.php @@ -185,6 +185,8 @@ $runningScripts = array_unique($runningScripts); onchange="vvSaveJob(this)"> Verbose + @@ -236,6 +238,7 @@ $runningScripts = array_unique($runningScripts); onchange="vvSaveJob(this)"> Verbose + @@ -293,6 +296,7 @@ $runningScripts = array_unique($runningScripts); + @@ -335,6 +339,7 @@ $runningScripts = array_unique($runningScripts); onchange="vvSaveJob(this)"> Verbose + @@ -1268,13 +1273,16 @@ function vvGitPull(btn) { } function vvRunJob(btn) { - const job = btn.closest('[data-id]'); - const id = job.dataset.id; - const location = job.querySelector('.vv-rsync-location')?.value.trim() || ''; + const job = btn.closest('[data-id]'); + const id = job.dataset.id; + const location = job.querySelector('.vv-rsync-location')?.value.trim() || ''; + const extra_args = job.querySelector('.vv-script-args')?.value.trim() || ''; vvOpenRight(id); vvSetDot(id); vvRunningSet.add(id); - const data = location ? {id, location} : {id}; + const data = {id}; + if (location) data.location = location; + if (extra_args) data.extra_args = extra_args; vvPost('/plugins/varaverk/api/run.php', data) .then(d => { if (!d.ok) { @@ -1286,13 +1294,16 @@ function vvRunJob(btn) { } function vvDryRun(btn) { - const job = btn.closest('[data-id]'); - const id = job.dataset.id; - const location = job.querySelector('.vv-rsync-location')?.value.trim() || ''; + const job = btn.closest('[data-id]'); + const id = job.dataset.id; + const location = job.querySelector('.vv-rsync-location')?.value.trim() || ''; + const extra_args = job.querySelector('.vv-script-args')?.value.trim() || ''; vvOpenRight(id); vvSetDot(id); vvRunningSet.add(id); - const data = location ? {id, location} : {id}; + const data = {id}; + if (location) data.location = location; + if (extra_args) data.extra_args = extra_args; vvPost('/plugins/varaverk/api/dryrun.php', data) .then(d => { if (!d.ok) { @@ -1395,18 +1406,21 @@ function vvApplyOrchState(orchCard, orchEnabled) { const confManaged = child.dataset.confManaged === '1'; const confEnabled = child.dataset.confEnabled === '1'; + const argsInput = child.querySelector('.vv-script-args'); if (orchEnabled) { // Orch is god: set toggle from master.conf state; dim independent cron. // If not conf-managed (no *_SCRIPTS array, e.g. transcode), orch hardcodes the call — // show as enabled so the user sees the script is active. toggle.checked = confManaged ? confEnabled : true; toggle.disabled = false; - if (cronInput) { cronInput.disabled = true; cronInput.style.opacity = '0.35'; } + if (cronInput) { cronInput.disabled = true; cronInput.style.opacity = '0.35'; } + if (argsInput) { argsInput.style.display = 'none'; } } else { - // Orch off: all children switch off; cron field becomes active + // Orch off: all children switch off; cron and args become active toggle.checked = false; toggle.disabled = false; - if (cronInput) { cronInput.disabled = false; cronInput.style.opacity = ''; } + if (cronInput) { cronInput.disabled = false; cronInput.style.opacity = ''; } + if (argsInput) { argsInput.style.display = ''; } // Persist the off state to schedule.json so cron rebuild reflects it const cid = child.dataset.id; const ccron = cronInput?.value.trim() ?? '';