diff --git a/new.php b/new.php index f324027..d393649 100644 --- a/new.php +++ b/new.php @@ -3,7 +3,9 @@ require __DIR__ . '/auth.php'; mvlog_require_login(); $config = require __DIR__ . "/config.php"; foreach (["videos_dir", "thumbs_dir", "uploads_dir"] as $d) if (!is_dir($config[$d])) mkdir($config[$d], 0775, true); +if (!is_dir(__DIR__ . "/cache")) mkdir(__DIR__ . "/cache", 0775, true); 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 slugify($s){ $s = strtolower(trim($s)); $s = preg_replace('/[^a-z0-9]+/', '-', $s); return trim($s, '-') ?: 'movie'; } function rrmdir($dir){ if(!is_dir($dir)) return; foreach(scandir($dir) as $f){ if($f==='.'||$f==='..') continue; $p="$dir/$f"; is_dir($p)?rrmdir($p):unlink($p);} rmdir($dir); } function input_dirs($base){ return glob($base.'/*', GLOB_ONLYDIR) ?: []; } @@ -133,13 +135,54 @@ function unique_input_dir($base, $slug){ if (!file_exists($candidate)) return $candidate; } } -function input_dir_sort_date($dir){ - $data = read_data($dir); - return input_dir_date_from_text($data['date'] ?? '') ?? input_dir_date_from_media($dir); +function input_dir_signature($dir){ + $entries = []; + foreach (scandir($dir) ?: [] as $file) { + if ($file === '.' || $file === '..' || in_array($file, ['.movmaker-state.json','.movmaker-enabled','.mvlog-hidden'], true)) continue; + if ($file === '.movmaker-lock') continue; + $path = $dir . '/' . $file; + if (is_file($path)) $entries[] = [$file, filesize($path), filemtime($path)]; + } + sort($entries); + return hash('sha256', json_encode($entries, JSON_UNESCAPED_UNICODE)); } -function sort_input_dirs_by_metadata_date(&$dirs){ - usort($dirs, function($a, $b) { - $cmp = strcmp(input_dir_sort_date($b), input_dir_sort_date($a)); +function input_dir_info($dir){ + $data = read_data($dir); + $files = list_files($dir); + return [ + 'name' => basename($dir), + 'title' => $data['title'] ?: basename($dir), + 'sort_date' => input_dir_date_from_text($data['date'] ?? '') ?? input_dir_date_from_media($dir), + 'file_count' => count($files), + 'signature' => input_dir_signature($dir), + ]; +} +function load_input_dir_cache($dirs){ + $cacheFile = __DIR__ . '/cache/input-dirs.json'; + $cache = is_file($cacheFile) ? json_decode((string)file_get_contents($cacheFile), true) : []; + if (!is_array($cache) || ($cache['version'] ?? 0) !== 1) $cache = ['version'=>1,'items'=>[]]; + $oldItems = is_array($cache['items'] ?? null) ? $cache['items'] : []; + $items = []; $changed = false; + foreach ($dirs as $dir) { + $name = basename($dir); + $sig = input_dir_signature($dir); + $cached = $oldItems[$name] ?? null; + if (is_array($cached) && ($cached['signature'] ?? '') === $sig) { + $items[$name] = $cached; + } else { + $items[$name] = input_dir_info($dir); + $changed = true; + } + } + if (array_diff(array_keys($oldItems), array_keys($items))) $changed = true; + if ($changed) file_put_contents($cacheFile, json_encode(['version'=>1,'generated_at'=>date('c'),'items'=>$items], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX); + return $items; +} +function sort_input_dirs_by_metadata_date(&$dirs, $dirInfo){ + usort($dirs, function($a, $b) use ($dirInfo) { + $ad = $dirInfo[basename($a)]['sort_date'] ?? '00000000'; + $bd = $dirInfo[basename($b)]['sort_date'] ?? '00000000'; + $cmp = strcmp($bd, $ad); return $cmp !== 0 ? $cmp : strnatcasecmp(basename($b), basename($a)); }); } @@ -232,13 +275,17 @@ try { $_GET['edit'] = $slug; } elseif ($action === 'set_enabled') { $dir = safe_input_dir($config['uploads_dir'], $_POST['dir'] ?? ''); - set_input_dir_enabled($dir, !empty($_POST['enabled'])); - header('Location: new.php?tab=edit&msg=' . rawurlencode((!empty($_POST['enabled']) ? 'Enabled rendering for: in-dir/' : 'Disabled rendering for: in-dir/') . basename($dir))); + $enabledNow = !empty($_POST['enabled']); + set_input_dir_enabled($dir, $enabledNow); + if (!empty($_POST['ajax'])) ajax_json(['ok'=>true, 'enabled'=>$enabledNow, 'dir'=>basename($dir)]); + header('Location: new.php?tab=edit&msg=' . rawurlencode(($enabledNow ? 'Enabled rendering for: in-dir/' : 'Disabled rendering for: in-dir/') . basename($dir))); exit; } elseif ($action === 'set_visible') { $dir = safe_input_dir($config['uploads_dir'], $_POST['dir'] ?? ''); - set_input_dir_visible($dir, !empty($_POST['visible'])); - header('Location: new.php?tab=edit&msg=' . rawurlencode((!empty($_POST['visible']) ? 'Shown: in-dir/' : 'Hidden: in-dir/') . basename($dir))); + $visibleNow = !empty($_POST['visible']); + set_input_dir_visible($dir, $visibleNow); + if (!empty($_POST['ajax'])) ajax_json(['ok'=>true, 'visible'=>$visibleNow, 'dir'=>basename($dir)]); + header('Location: new.php?tab=edit&msg=' . rawurlencode(($visibleNow ? 'Shown: in-dir/' : 'Hidden: in-dir/') . basename($dir))); exit; } elseif ($action === 'update') { $dir = safe_input_dir($config['uploads_dir'], $_POST['dir'] ?? ''); @@ -284,7 +331,8 @@ try { } } catch (Throwable $e) { $err = $e->getMessage(); } $dirs = input_dirs($config['uploads_dir']); -sort_input_dirs_by_metadata_date($dirs); +$dirInfo = load_input_dir_cache($dirs); +sort_input_dirs_by_metadata_date($dirs, $dirInfo); $orphanVideos = orphan_videos($config); $tab = $_GET['tab'] ?? (isset($_GET['edit']) ? 'edit' : 'new'); $page = max(1, (int)($_GET['page'] ?? 1)); @@ -299,11 +347,33 @@ if ($editName !== '') { try { $editDir = safe_input_dir($config['uploads_dir'],
No orphan videos.
=page_links('videos',$videoPage,$videoPages)?>No input directories yet.
No input directories yet.
in-dir/=h(basename($editDir))?>
in-dir/=h(basename($editDir))?>