&1"); $data = @json_decode(trim($out), true); echo json_encode($data ?: ['ok' => false, 'raw' => substr($out, 0, 500)], JSON_PRETTY_PRINT); break; case 'publish_due': // Runs full scheduled queue through browser $out = shell_exec("cd /tmp && timeout 180 python3 $script publish_due 2>&1"); $data = @json_decode(trim($out), true); echo json_encode($data ?: ['ok' => false, 'raw' => substr($out, 0, 500)], JSON_PRETTY_PRINT); break; case 'publish_id': $id = escapeshellarg($_GET['id'] ?? $_POST['id'] ?? ''); $out = shell_exec("cd /tmp && timeout 90 python3 $script publish_id $id 2>&1"); $data = @json_decode(trim($out), true); echo json_encode($data ?: ['ok' => false, 'raw' => substr($out, 0, 500)], JSON_PRETTY_PRINT); break; case 'session_status': // Check if persistent Chromium context has valid LinkedIn session $cookies_file = "$session_dir/Default/Cookies"; $exists = file_exists($cookies_file); $size = $exists ? filesize($cookies_file) : 0; $mtime = $exists ? filemtime($cookies_file) : 0; echo json_encode([ 'session_exists' => $exists, 'cookies_file' => $cookies_file, 'size_bytes' => $size, 'last_update' => $mtime ? date('c', $mtime) : null, 'age_hours' => $mtime ? round((time() - $mtime) / 3600, 1) : null, 'instructions' => !$exists ? 'One-time login: run /api/v98-linkedin-browser.php?action=init_session on a server with display OR visit from your logged-in browser to feed cookies' : 'Session ready', ], JSON_PRETTY_PRINT); break; case 'log': $tail = @shell_exec('tail -50 /var/log/v98-linkedin-browser.log 2>/dev/null') ?: ''; echo json_encode(['log' => $tail], JSON_PRETTY_PRINT); break; default: echo json_encode(['err' => 'unknown', 'available' => ['check_session', 'publish_due', 'publish_id', 'session_status', 'log']]); }