From edcb6ca928929935f3e2b0c9923bfd618469c834 Mon Sep 17 00:00:00 2001 From: hbrain Date: Thu, 4 Jun 2026 23:57:00 +0200 Subject: [PATCH] Show on main landing page restore, separately from permalink --- admin.php | 83 ++++++++++++++++++++++++++++++++++++++++++++--- index.php | 51 +++++++++++++++++++++-------- lib/send_push.php | 2 +- style.css | 2 +- 4 files changed, 119 insertions(+), 19 deletions(-) diff --git a/admin.php b/admin.php index d23e5cf..889a98e 100644 --- a/admin.php +++ b/admin.php @@ -6,6 +6,7 @@ foreach (["videos_dir", "thumbs_dir", "uploads_dir"] as $d) if (!is_dir($config[ if (!is_dir(__DIR__ . "/cache")) mkdir(__DIR__ . "/cache", 0775, true); const ARTICLE_ID_FILE = '.mvlog-id'; const MAP_HIDDEN_FILE = '.mvlog-hide-map'; +const PERMALINK_FILE = '.mvlog-permalink'; function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, "UTF-8"); } function ajax_json($data){ header('Content-Type: application/json; charset=UTF-8'); echo json_encode($data, JSON_UNESCAPED_UNICODE); exit; } function lower_text($s){ return function_exists('mb_strtolower') ? mb_strtolower((string)$s, 'UTF-8') : strtolower((string)$s); } @@ -651,7 +652,7 @@ entries = [] for dirpath, dirnames, filenames in os.walk(root): dirnames[:] = [d for d in dirnames if d != '.movmaker-lock'] for name in filenames: - if name in {'.movmaker-state.json', '.movmaker-enabled', '.movmaker-preview', '.mvlog-hidden', '.mvlog-id', '.mvlog-hide-map'}: + if name in {'.movmaker-state.json', '.movmaker-enabled', '.movmaker-preview', '.mvlog-hidden', '.mvlog-permalink', '.mvlog-id', '.mvlog-hide-map'}: continue path = os.path.join(dirpath, name) rel = os.path.relpath(path, root) @@ -763,6 +764,17 @@ 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){ + $state = input_dir_state($dir); + $output = basename((string)($state['output'] ?? '')); + return $output !== '' && is_file($config['videos_dir'] . '/' . $output) && !input_dir_preview($dir); +} +function set_input_dir_permalink($dir, $permalink){ + $path = $dir . '/' . PERMALINK_FILE; + if ($permalink) { file_put_contents($path, "permalink\n"); @chmod($path, 0664); } + elseif (is_file($path)) unlink($path); +} function input_dir_map_hidden($dir){ return is_file($dir . '/' . MAP_HIDDEN_FILE); } function set_input_dir_map_hidden($dir, $hidden){ $path = $dir . '/' . MAP_HIDDEN_FILE; @@ -999,6 +1011,7 @@ try { '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, @@ -1023,6 +1036,7 @@ try { '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, @@ -1045,7 +1059,8 @@ try { include_once __DIR__ . '/lib/send_push.php'; try_send_show_notification($articleId ?: basename($dir), $dir, __DIR__, '/var/log/mvlog_notify.log'); } else { - error_log("[mvlog] send_push helper missing, cannot send notification for " . basename($dir) . "\n", 3, '/var/log/mvlog_notify.log'); + error_log("[mvlog] send_push helper missing, cannot send notification for " . basename($dir) . " +", 3, '/var/log/mvlog_notify.log'); } } @@ -1056,6 +1071,27 @@ try { 'ok' => true, 'visible' => $currentVisible, 'can_show' => $canShow, + 'can_permalink' => input_dir_can_permalink($dir, $config), + 'dir' => basename($dir), + 'id' => $articleId, + 'message' => $message, + ]); + } + header('Location: admin.php?tab=edit&msg=' . rawurlencode($message)); + exit; + } elseif ($action === 'set_permalink') { + $dir = resolve_input_dir_from_request($config['uploads_dir'], $_POST['id'] ?? '', $_POST['dir'] ?? '', $articleIndex); + $articleId = ensure_state_article_id($dir); + $permalinkNow = !empty($_POST['permalink']); + $canPermalink = input_dir_can_permalink($dir, $config); + if ($permalinkNow && !$canPermalink) throw new RuntimeException('Only finished full-quality videos can use permalinks.'); + set_input_dir_permalink($dir, $permalinkNow && $canPermalink); + $message = ($permalinkNow ? 'Permalink enabled for: in-dir/' : 'Permalink disabled for: in-dir/') . basename($dir); + if (!empty($_POST['ajax'])) { + ajax_json([ + 'ok' => true, + 'permalink' => $permalinkNow && $canPermalink, + 'can_permalink' => $canPermalink, 'dir' => basename($dir), 'id' => $articleId, 'message' => $message, @@ -1313,7 +1349,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:

@@ -1344,6 +1380,16 @@ $runningJobs = active_worker_jobs($config);
+
+ + + + + +
@@ -1355,7 +1401,7 @@ $runningJobs = active_worker_jobs($config);
-
RenderingEdit

No videoPreview video

โ€œโ€

ยท files

+
RenderingEdit

No videoPreview video

โ€œโ€

ยท files

Edit input dir

in-dir/

This input directory is . Editing is disabled until the job completes.

Edit input dir

in-dir/

Files and captions

No caption for audio files

Add new movie input

@@ -1775,6 +1821,23 @@ async function handleSwitchToggle(form, checkbox){ } } +function updateAdminRowTitleLink(row){ + if(!row) return; + const titleEl = row.querySelector('h2'); + if(!titleEl) return; + const title = titleEl.dataset.titleText || titleEl.textContent.trim(); + const url = titleEl.dataset.permalinkUrl || ''; + titleEl.textContent = ''; + if(url){ + const link = document.createElement('a'); + link.href = url; + link.textContent = title; + titleEl.appendChild(link); + } else { + titleEl.textContent = title; + } +} + function applySwitchPayload(payload){ if(!payload) return; let row = null; @@ -1790,6 +1853,10 @@ function applySwitchPayload(payload){ if('preview' in payload) setSwitch('preview', payload.preview); if('enabled' in payload) setSwitch('render', payload.enabled); if('map_hidden' in payload) setSwitch('hide-map', payload.map_hidden); + if('permalink' in payload){ + setSwitch('permalink', payload.permalink); + row.dataset.permalink = payload.permalink ? '1' : '0'; + } if('visible' in payload){ setSwitch('show', payload.visible); row.classList.toggle('shown', !!payload.visible); @@ -1805,6 +1872,14 @@ function applySwitchPayload(payload){ } } } + if('can_permalink' in payload){ + row.dataset.canPermalink = payload.can_permalink ? '1' : '0'; + const permalinkInput = row.querySelector('form[data-switch="permalink"] input[type="checkbox"]'); + if(permalinkInput){ + permalinkInput.disabled = !payload.can_permalink; + } + } + updateAdminRowTitleLink(row); }