From 04c9574a56f244fd2823b781555cffae1f825c0f Mon Sep 17 00:00:00 2001 From: hbrain Date: Wed, 24 Jun 2026 21:58:34 +0200 Subject: [PATCH] Fixed (hopefully) enabled render/preview on initial dir upload --- admin.php | 159 +++++++++++++++++++++++++------------------------ job_status.php | 59 +++++++++++++++--- 2 files changed, 133 insertions(+), 85 deletions(-) diff --git a/admin.php b/admin.php index f985b58..7611602 100644 --- a/admin.php +++ b/admin.php @@ -925,12 +925,47 @@ function set_input_dir_visible($dir, $visible){ if ($visible) { if (is_file($path)) unlink($path); } else { file_put_contents($path, "hidden\n"); @chmod($path, 0664); } } -function input_dir_permalink($dir){ return is_file($dir . '/' . PERMALINK_FILE); } -function input_dir_can_permalink($dir, $config){ +function input_dir_has_full_output($dir, $config){ $state = input_dir_state($dir); $output = basename((string)($state['output'] ?? '')); - return $output !== '' && is_file($config['videos_dir'] . '/' . $output) && !input_dir_preview($dir); + return $output !== '' && is_file($config['videos_dir'] . '/' . $output) && !preg_match('/_preview\.(mp4|webm|mov|m4v)$/i', $output); } +function input_dir_can_show($dir, $config){ return input_dir_has_full_output($dir, $config) && !input_dir_preview($dir); } +function input_dir_effective_visible($dir, $config){ return input_dir_can_show($dir, $config) && input_dir_visible($dir); } +function input_dir_permalink($dir){ return is_file($dir . '/' . PERMALINK_FILE); } +function input_dir_can_permalink($dir, $config){ return input_dir_can_show($dir, $config); } +function input_dir_ui_state($dir, $config){ + $preview = input_dir_preview($dir); + $enabled = input_dir_enabled($dir); + $canShow = input_dir_can_show($dir, $config); + $visible = $canShow && input_dir_visible($dir); + $permalink = input_dir_permalink($dir); + $canPermalink = input_dir_can_permalink($dir, $config); + return [ + 'enabled' => $enabled, + 'preview' => $preview, + 'visible' => $visible, + 'permalink' => $permalink, + 'can_show' => $canShow, + 'can_permalink' => $canPermalink, + 'public_locked' => $visible || $permalink, + ]; +} +function input_dir_public_locked($dir, $config){ $s = input_dir_ui_state($dir, $config); return !empty($s['public_locked']); } +function input_dir_switch_payload($dir, $config, $articleId = ''){ + $s = input_dir_ui_state($dir, $config); + $s['dir'] = basename((string)$dir); + $s['id'] = $articleId !== '' ? $articleId : read_article_id($dir); + return $s; +} +function initialize_input_dir_defaults($dir, $config){ + // Directly uploaded directories do not have admin marker files yet. + // Keep them private by default so Show is off, Permalink is off, and Preview/Render stay available. + if (!is_file($dir . '/.mvlog-hidden') && !input_dir_permalink($dir) && !input_dir_has_full_output($dir, $config)) { + set_input_dir_visible($dir, false); + } +} +function initialize_input_dirs_defaults($dirs, $config){ foreach ($dirs as $dir) initialize_input_dir_defaults($dir, $config); } function set_input_dir_permalink($dir, $permalink){ $path = $dir . '/' . PERMALINK_FILE; if ($permalink) { file_put_contents($path, "permalink\n"); @chmod($path, 0664); } @@ -1132,7 +1167,9 @@ function save_uploads($field, $dest, $allowed){ $msg = $_GET['msg'] ?? null; $err = null; $allowedMedia = ['jpg','jpeg','png','webp','gif','mp4','mov','m4v','avi','mkv','webm']; $allowedAudio = ['mp3','wav','m4a','aac','ogg','flac']; -$articleIndex = load_articles_index($config['uploads_dir']); +$initialDirs = input_dirs($config['uploads_dir']); +initialize_input_dirs_defaults($initialDirs, $config); +$articleIndex = load_articles_index($config['uploads_dir'], $initialDirs); try { if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? 'create'; @@ -1166,55 +1203,37 @@ try { } elseif ($action === 'set_enabled') { $dir = resolve_input_dir_from_request($config['uploads_dir'], $_POST['id'] ?? '', $_POST['dir'] ?? '', $articleIndex); $articleId = ensure_state_article_id($dir); - if (input_dir_visible($dir) || input_dir_permalink($dir)) throw new RuntimeException('Disable Show and Permalink before changing render.'); + initialize_input_dir_defaults($dir, $config); + if (input_dir_public_locked($dir, $config)) throw new RuntimeException('Disable Show and Permalink before changing render.'); $enabledNow = !empty($_POST['enabled']); set_input_dir_enabled($dir, $enabledNow); if ($enabledNow) { set_input_dir_preview($dir, false); } - $state = input_dir_state($dir); - $output = basename((string)($state['output'] ?? '')); - $canShow = $output !== '' && is_file($config['videos_dir'].'/'.$output) && !input_dir_preview($dir); - if (!$canShow) set_input_dir_visible($dir, false); + if (!input_dir_can_show($dir, $config)) set_input_dir_visible($dir, false); $message = ($enabledNow ? 'Enabled rendering for: in-dir/' : 'Disabled rendering for: in-dir/') . basename($dir); if (!empty($_POST['ajax'])) { - ajax_json([ - 'ok' => true, - 'enabled' => $enabledNow, - 'preview' => input_dir_preview($dir), - 'visible' => input_dir_visible($dir) && $canShow, - 'can_show' => $canShow, - 'can_permalink' => input_dir_can_permalink($dir, $config), - 'dir' => basename($dir), - 'id' => $articleId, - 'message' => $message, - ]); + $payload = input_dir_switch_payload($dir, $config, $articleId); + $payload['ok'] = true; + $payload['message'] = $message; + ajax_json($payload); } header('Location: admin.php?tab=edit&msg=' . rawurlencode($message)); exit; } elseif ($action === 'set_preview') { $dir = resolve_input_dir_from_request($config['uploads_dir'], $_POST['id'] ?? '', $_POST['dir'] ?? '', $articleIndex); $articleId = ensure_state_article_id($dir); - if (input_dir_visible($dir) || input_dir_permalink($dir)) throw new RuntimeException('Disable Show and Permalink before changing preview.'); + initialize_input_dir_defaults($dir, $config); + if (input_dir_public_locked($dir, $config)) throw new RuntimeException('Disable Show and Permalink before changing preview.'); $previewNow = !empty($_POST['preview']); set_input_dir_preview($dir, $previewNow); if ($previewNow) { set_input_dir_enabled($dir, false); set_input_dir_visible($dir, false); } - $state = input_dir_state($dir); - $output = basename((string)($state['output'] ?? '')); - $canShow = $output !== '' && is_file($config['videos_dir'].'/'.$output) && !input_dir_preview($dir); $message = ($previewNow ? 'Enabled preview for: in-dir/' : 'Disabled preview for: in-dir/') . basename($dir); if (!empty($_POST['ajax'])) { - ajax_json([ - 'ok' => true, - 'preview' => $previewNow, - 'enabled' => input_dir_enabled($dir), - 'visible' => input_dir_visible($dir) && $canShow, - 'can_show' => $canShow, - 'can_permalink' => input_dir_can_permalink($dir, $config), - 'dir' => basename($dir), - 'id' => $articleId, - 'message' => $message, - ]); + $payload = input_dir_switch_payload($dir, $config, $articleId); + $payload['ok'] = true; + $payload['message'] = $message; + ajax_json($payload); } header('Location: admin.php?tab=edit&msg=' . rawurlencode($message)); exit; @@ -1225,9 +1244,7 @@ try { $sendImmediately = !empty($_POST['send_immediately']); $articleAlreadyAnnounced = mvlog_announcement_sent(__DIR__, $articleId, basename($dir)); if ($articleAlreadyAnnounced) $sendImmediately = false; - $state = input_dir_state($dir); - $output = basename((string)($state['output'] ?? '')); - $canShow = $output !== '' && is_file($config['videos_dir'].'/'.$output) && !input_dir_preview($dir); + $canShow = input_dir_can_show($dir, $config); $canPermalink = input_dir_can_permalink($dir, $config); if ($visibleNow && !$canShow) throw new RuntimeException('Only finished full-quality videos can be shown.'); if ($visibleNow && !$canPermalink) throw new RuntimeException('Only finished full-quality videos can use permalinks.'); @@ -1245,19 +1262,12 @@ try { } $message = ($visibleNow ? 'Shown: in-dir/' : 'Hidden: in-dir/') . basename($dir); - $currentVisible = input_dir_visible($dir) && $canShow; if (!empty($_POST['ajax'])) { - ajax_json([ - 'ok' => true, - 'visible' => $currentVisible, - 'permalink' => input_dir_permalink($dir), - 'can_show' => $canShow, - 'can_permalink' => $canPermalink, - 'announced' => mvlog_announcement_sent(__DIR__, $articleId, basename($dir)), - 'dir' => basename($dir), - 'id' => $articleId, - 'message' => $message, - ]); + $payload = input_dir_switch_payload($dir, $config, $articleId); + $payload['ok'] = true; + $payload['announced'] = mvlog_announcement_sent(__DIR__, $articleId, basename($dir)); + $payload['message'] = $message; + ajax_json($payload); } header('Location: admin.php?tab=edit&msg=' . rawurlencode($message)); exit; @@ -1269,41 +1279,29 @@ try { if ($permalinkNow && !$canPermalink) throw new RuntimeException('Only finished full-quality videos can use permalinks.'); set_input_dir_permalink($dir, $permalinkNow && $canPermalink); if (!$permalinkNow) set_input_dir_visible($dir, false); - $currentPermalink = input_dir_permalink($dir); - $state = input_dir_state($dir); - $output = basename((string)($state['output'] ?? '')); - $canShow = $output !== '' && is_file($config['videos_dir'].'/'.$output) && !input_dir_preview($dir); - $currentVisible = input_dir_visible($dir) && $canShow; $message = ($permalinkNow ? 'Permalink enabled for: in-dir/' : 'Permalink disabled for: in-dir/') . basename($dir); if (!empty($_POST['ajax'])) { - ajax_json([ - 'ok' => true, - 'permalink' => $currentPermalink, - 'visible' => $currentVisible, - 'can_show' => $canShow, - 'can_permalink' => $canPermalink, - 'dir' => basename($dir), - 'id' => $articleId, - 'message' => $message, - ]); + $payload = input_dir_switch_payload($dir, $config, $articleId); + $payload['ok'] = true; + $payload['message'] = $message; + ajax_json($payload); } header('Location: admin.php?tab=edit&msg=' . rawurlencode($message)); exit; } elseif ($action === 'set_map_hidden') { $dir = resolve_input_dir_from_request($config['uploads_dir'], $_POST['id'] ?? '', $_POST['dir'] ?? '', $articleIndex); $articleId = ensure_state_article_id($dir); - if (input_dir_visible($dir) || input_dir_permalink($dir)) throw new RuntimeException('Disable Show and Permalink before changing map visibility.'); + initialize_input_dir_defaults($dir, $config); + if (input_dir_public_locked($dir, $config)) throw new RuntimeException('Disable Show and Permalink before changing map visibility.'); $mapHiddenNow = !empty($_POST['map_hidden']); set_input_dir_map_hidden($dir, $mapHiddenNow); $message = ($mapHiddenNow ? 'Map hidden on index for: in-dir/' : 'Map visible on index for: in-dir/') . basename($dir); if (!empty($_POST['ajax'])) { - ajax_json([ - 'ok' => true, - 'map_hidden' => $mapHiddenNow, - 'dir' => basename($dir), - 'id' => $articleId, - 'message' => $message, - ]); + $payload = input_dir_switch_payload($dir, $config, $articleId); + $payload['ok'] = true; + $payload['map_hidden'] = $mapHiddenNow; + $payload['message'] = $message; + ajax_json($payload); } header('Location: admin.php?tab=edit&msg=' . rawurlencode($message)); exit; @@ -1470,6 +1468,7 @@ try { $err = $e->getMessage(); } $dirs = input_dirs($config['uploads_dir']); +initialize_input_dirs_defaults($dirs, $config); $articleIndex = load_articles_index($config['uploads_dir'], $dirs); $dirInfo = load_input_dir_cache($dirs); sort_input_dirs_by_metadata_date($dirs, $dirInfo); @@ -1502,8 +1501,8 @@ if ($keywordValue !== '' || $statusFilterActive) { $displayOutput = ($preview && $hasPreviewVideo) ? $previewOutput : ($hasFullVideo ? $fullOutput : ($hasPreviewVideo ? $previewOutput : '')); $hasVideo = $displayOutput !== ''; $enabled = input_dir_enabled($dir); - $canShow = $hasFullVideo && !$preview; - $visible = $canShow && input_dir_visible($dir); + $canShow = input_dir_can_show($dir, $config); + $visible = input_dir_effective_visible($dir, $config); if ($statusFilterActive) { $statusMatch = false; @@ -1545,7 +1544,7 @@ $runningJobs = active_worker_jobs($config);

Videos without input dir

No orphan videos.


MB
-

No input directories yet.

(string)($data['title'] ?? ''),'teaser'=>(string)($data['teaser'] ?? ''),'date'=>(string)($data['date'] ?? ''),'location'=>(string)($data['place'] ?? ''),'quote_da'=>(string)($data['quote_da'] ?? ''),'description'=>(string)($data['description'] ?? '')]; $currentSignature=$info['signature'] ?? ''; $fullFingerprint=is_array($state)?(string)($state['fingerprint'] ?? ''):''; $previewFingerprint=is_array($state)?(string)($state['preview_fingerprint'] ?? ''):''; $editedSinceRender=$hasFullVideo && $currentSignature !== '' && $fullFingerprint !== '' && $currentSignature !== $fullFingerprint; $editedSincePreview=!$hasFullVideo && $previewVideo && $currentSignature !== '' && $previewFingerprint !== '' && $currentSignature !== $previewFingerprint; $staleLabel=$editedSinceRender ? 'Edited since render' : ($editedSincePreview ? 'Edited since preview' : ''); ?>
Map
No video yet
Map

Thumb source:

+

No input directories yet.

(string)($data['title'] ?? ''),'teaser'=>(string)($data['teaser'] ?? ''),'date'=>(string)($data['date'] ?? ''),'location'=>(string)($data['place'] ?? ''),'quote_da'=>(string)($data['quote_da'] ?? ''),'description'=>(string)($data['description'] ?? '')]; $currentSignature=$info['signature'] ?? ''; $fullFingerprint=is_array($state)?(string)($state['fingerprint'] ?? ''):''; $previewFingerprint=is_array($state)?(string)($state['preview_fingerprint'] ?? ''):''; $editedSinceRender=$hasFullVideo && $currentSignature !== '' && $fullFingerprint !== '' && $currentSignature !== $fullFingerprint; $editedSincePreview=!$hasFullVideo && $previewVideo && $currentSignature !== '' && $previewFingerprint !== '' && $currentSignature !== $previewFingerprint; $staleLabel=$editedSinceRender ? 'Edited since render' : ($editedSincePreview ? 'Edited since preview' : ''); ?>
Map
No video yet
Map

Thumb source:

@@ -2086,7 +2085,7 @@ function updateAdminRowTitleLink(row){ } function rowPublicLocked(row){ - return !!row && (row.dataset.permalink === '1' || row.dataset.visible === '1' || row.classList.contains('shown')); + return !!row && row.dataset.publicLocked === '1'; } function updatePublicLockedControls(row){ if(!row) return; @@ -2147,6 +2146,11 @@ function applySwitchPayload(payload){ row.classList.toggle('shown', !!payload.visible); row.dataset.visible = payload.visible ? '1' : '0'; } + if('public_locked' in payload){ + row.dataset.publicLocked = payload.public_locked ? '1' : '0'; + }else{ + row.dataset.publicLocked = (row.dataset.permalink === '1' || row.dataset.visible === '1') ? '1' : '0'; + } if('can_show' in payload){ const showInput = row.querySelector('form[data-switch="show"] input[type="checkbox"]'); if(showInput){ @@ -2156,6 +2160,7 @@ function applySwitchPayload(payload){ showInput.dataset.state = '0'; row.classList.remove('shown'); row.dataset.visible = '0'; + if(!('public_locked' in payload)) row.dataset.publicLocked = (row.dataset.permalink === '1') ? '1' : '0'; } } } diff --git a/job_status.php b/job_status.php index 1b8cba4..25916cf 100644 --- a/job_status.php +++ b/job_status.php @@ -41,6 +41,54 @@ function mvlog_rm_rf(string $path): void { @rmdir($path); } +function mvlog_input_dir_state(string $dir): array { + $stateFile = $dir . '/.movmaker-state.json'; + $state = is_file($stateFile) ? json_decode((string)@file_get_contents($stateFile), true) : []; + return is_array($state) ? $state : []; +} +function mvlog_input_dir_preview(string $dir): bool { + if (is_file($dir . '/.movmaker-preview')) return true; + $state = mvlog_input_dir_state($dir); + return !empty($state['preview']); +} +function mvlog_input_dir_enabled(string $dir): bool { return is_file($dir . '/.movmaker-enabled'); } +function mvlog_input_dir_visible_marker(string $dir): bool { return !is_file($dir . '/.mvlog-hidden'); } +function mvlog_set_input_dir_visible(string $dir, bool $visible): void { + $path = $dir . '/.mvlog-hidden'; + if ($visible) { if (is_file($path)) @unlink($path); } + else { @file_put_contents($path, "hidden +"); @chmod($path, 0664); } +} +function mvlog_input_dir_permalink(string $dir): bool { return is_file($dir . '/.mvlog-permalink'); } +function mvlog_input_dir_has_full_output(string $dir, array $config): bool { + $state = mvlog_input_dir_state($dir); + $output = basename((string)($state['output'] ?? '')); + return $output !== '' && is_file($config['videos_dir'] . '/' . $output) && !preg_match('/_preview\.(mp4|webm|mov|m4v)$/i', $output); +} +function mvlog_input_dir_can_show(string $dir, array $config): bool { return mvlog_input_dir_has_full_output($dir, $config) && !mvlog_input_dir_preview($dir); } +function mvlog_initialize_input_dir_defaults(string $dir, array $config): void { + if (!is_file($dir . '/.mvlog-hidden') && !mvlog_input_dir_permalink($dir) && !mvlog_input_dir_has_full_output($dir, $config)) { + mvlog_set_input_dir_visible($dir, false); + } +} +function mvlog_input_dir_switch_payload(string $dir, array $config, string $articleId): array { + $canShow = mvlog_input_dir_can_show($dir, $config); + $visible = $canShow && mvlog_input_dir_visible_marker($dir); + $permalink = mvlog_input_dir_permalink($dir); + return [ + 'dir' => basename($dir), + 'id' => $articleId, + 'enabled' => mvlog_input_dir_enabled($dir), + 'preview' => mvlog_input_dir_preview($dir), + 'visible' => $visible, + 'permalink' => $permalink, + 'can_show' => $canShow, + 'can_permalink' => $canShow, + 'public_locked' => $visible || $permalink, + 'map_hidden' => is_file($dir . '/.mvlog-hide-map'), + ]; +} + function mvlog_cleanup_stale_processing(string $dir, string $name, array $state, string $lockDir, bool $locked, string $status, string $articleId): array { $stateFile = $dir . '/.movmaker-state.json'; $started = ''; @@ -74,11 +122,11 @@ $workerRunning = mvlog_worker_running(); $dirs = glob($config['uploads_dir'] . '/*', GLOB_ONLYDIR) ?: []; foreach ($dirs as $dir) { $name = basename($dir); + mvlog_initialize_input_dir_defaults($dir, $config); $stateFile = $dir . '/.movmaker-state.json'; $lockDir = $dir . '/.movmaker-lock'; $idFile = $dir . '/.mvlog-id'; - $state = is_file($stateFile) ? json_decode((string)file_get_contents($stateFile), true) : []; - if (!is_array($state)) $state = []; + $state = mvlog_input_dir_state($dir); $status = (string)($state['status'] ?? ''); $articleId = strtolower((string)($state['article_id'] ?? '')); if ($articleId === '' && is_file($idFile)) $articleId = strtolower(trim((string)file_get_contents($idFile))); @@ -92,12 +140,7 @@ foreach ($dirs as $dir) { $cleaned[] = ['dir' => $name, 'id' => $articleId, 'status' => $status]; } - $switches[] = [ - 'dir' => $name, - 'id' => $articleId, - 'enabled' => is_file($dir . '/.movmaker-enabled'), - 'preview' => is_file($dir . '/.movmaker-preview'), - ]; + $switches[] = mvlog_input_dir_switch_payload($dir, $config, $articleId); if ($locked || $status === 'processing') { $started = '';