false, 'error' => 'Invalid id']); exit; } $path = CUSTOM_SCRIPTS_DIR . '/' . substr($id, strlen('Custom/')); echo json_encode(['ok' => true, 'content' => file_exists($path) ? file_get_contents($path) : '']); exit; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = trim($_POST['action'] ?? 'save'); $name = trim($_POST['name'] ?? ''); $content = $_POST['content'] ?? ''; if (!$name || !preg_match('/^[a-zA-Z0-9_\-]+$/', $name)) { echo json_encode(['ok' => false, 'error' => 'Name must be letters, numbers, _ or - only']); exit; } $id = 'Custom/' . $name . '.sh'; $path = CUSTOM_SCRIPTS_DIR . '/' . $name . '.sh'; if ($action === 'delete') { if (!file_exists($path)) { echo json_encode(['ok' => false, 'error' => 'Script not found']); exit; } unlink($path); $schedule = vv_schedule_load(); unset($schedule[$id]); vv_schedule_save($schedule); vv_cron_rebuild($schedule); echo json_encode(['ok' => true]); exit; } $dir = CUSTOM_SCRIPTS_DIR; if (!is_dir($dir)) mkdir($dir, 0755, true); if (file_put_contents($path, $content) === false) { echo json_encode(['ok' => false, 'error' => 'Failed to write script']); exit; } chmod($path, 0755); // Ensure schedule.json has an entry so the script appears in the job list $schedule = vv_schedule_load(); if (!isset($schedule[$id])) { $schedule[$id] = ['id' => $id, 'enabled' => false, 'cron' => '', 'log_enabled' => false, 'updated' => date('c')]; vv_schedule_save($schedule); } echo json_encode(['ok' => true, 'id' => $id]); exit; } echo json_encode(['ok' => false, 'error' => 'Method not allowed']);