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
110 lines
3.5 KiB
PHP
110 lines
3.5 KiB
PHP
<?php
|
|
// Rewrite a *_SCRIPTS array in master.conf with a new script order.
|
|
// POST: array_name (e.g. "DAILY_SCRIPTS"), scripts (JSON: [{"id":"rel/path.sh","enabled":true}, ...])
|
|
// Preserves original entry lines (including inline flags/args) where possible.
|
|
// Scripts absent from the new list are dropped; new scripts are added as fresh entries.
|
|
header('Content-Type: application/json');
|
|
require_once dirname(__DIR__) . '/include/config.php';
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
echo json_encode(['ok' => false, 'error' => 'POST only']);
|
|
exit;
|
|
}
|
|
|
|
$arrayName = trim($_POST['array_name'] ?? '');
|
|
$raw = $_POST['scripts'] ?? '';
|
|
$decoded = json_decode($raw, true);
|
|
|
|
if (!$arrayName || !preg_match('/^[A-Z_]+_SCRIPTS$/', $arrayName)) {
|
|
echo json_encode(['ok' => false, 'error' => 'Invalid array_name']);
|
|
exit;
|
|
}
|
|
if (!is_array($decoded)) {
|
|
echo json_encode(['ok' => false, 'error' => 'Invalid scripts JSON']);
|
|
exit;
|
|
}
|
|
|
|
// Validate each entry
|
|
$order = [];
|
|
foreach ($decoded as $item) {
|
|
$id = trim((string)($item['id'] ?? ''));
|
|
$enabled = (bool)($item['enabled'] ?? true);
|
|
if (!$id || str_contains($id, '..') || !preg_match('/^[A-Za-z0-9_.\-\/]+\.sh$/', $id)) continue;
|
|
$order[] = ['id' => $id, 'enabled' => $enabled];
|
|
}
|
|
|
|
$confPath = CONF_DIR . '/master.conf';
|
|
if (!file_exists($confPath)) {
|
|
echo json_encode(['ok' => false, 'error' => 'master.conf not found']);
|
|
exit;
|
|
}
|
|
|
|
$lines = file($confPath, FILE_KEEP_BLANK_LINES);
|
|
if (!$lines) {
|
|
echo json_encode(['ok' => false, 'error' => 'Could not read master.conf']);
|
|
exit;
|
|
}
|
|
|
|
// Find the array block and extract original entry lines keyed by script path.
|
|
$arrayEsc = preg_quote($arrayName, '/');
|
|
$blockStart = null;
|
|
$blockEnd = null;
|
|
$depth = 0;
|
|
$origEntries = []; // path → original trimmed content line (e.g. '"Daily/script.sh --flag"')
|
|
|
|
foreach ($lines as $i => $line) {
|
|
if ($blockStart === null) {
|
|
if (preg_match('/^\s*' . $arrayEsc . '\s*=\s*\(/', $line)) {
|
|
$blockStart = $i;
|
|
$depth = 1;
|
|
}
|
|
continue;
|
|
}
|
|
$depth += substr_count($line, '(');
|
|
$depth -= substr_count($line, ')');
|
|
if ($depth <= 0) {
|
|
$blockEnd = $i;
|
|
break;
|
|
}
|
|
// Collect entries (enabled and commented)
|
|
if (preg_match('/^\s*(?:#\s*)?"([^"]+)"/', $line, $m)) {
|
|
$parts = preg_split('/\s+/', trim($m[1]));
|
|
$path = $parts[0] ?? '';
|
|
if (substr($path, -3) === '.sh' && !isset($origEntries[$path])) {
|
|
// Store the full quoted expression (may include flags after the path)
|
|
$origEntries[$path] = '"' . $m[1] . '"';
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($blockStart === null || $blockEnd === null) {
|
|
echo json_encode(['ok' => false, 'error' => "Array $arrayName not found in master.conf"]);
|
|
exit;
|
|
}
|
|
|
|
// Build replacement block lines
|
|
$newBlockLines = [];
|
|
// Preserve the opening line exactly (e.g. "DAILY_SCRIPTS=(")
|
|
$newBlockLines[] = $lines[$blockStart];
|
|
|
|
foreach ($order as $item) {
|
|
$id = $item['id'];
|
|
$enabled = $item['enabled'];
|
|
$entry = $origEntries[$id] ?? '"' . $id . '"';
|
|
$prefix = $enabled ? ' ' : ' # ';
|
|
$newBlockLines[] = $prefix . $entry . "\n";
|
|
}
|
|
|
|
// Preserve the closing line exactly
|
|
$newBlockLines[] = $lines[$blockEnd];
|
|
|
|
// Replace the original block in $lines
|
|
array_splice($lines, $blockStart, $blockEnd - $blockStart + 1, $newBlockLines);
|
|
|
|
if (file_put_contents($confPath, implode('', $lines)) === false) {
|
|
echo json_encode(['ok' => false, 'error' => 'Write failed']);
|
|
exit;
|
|
}
|
|
|
|
echo json_encode(['ok' => true]);
|