$v !== '' && $v !== null); } function query_url(array $params): string { $params = keep_non_empty($params); return $params ? ('?' . http_build_query($params)) : 'index.php'; } function hidden_video_outputs($config){ $hidden = []; foreach (glob($config['uploads_dir'].'/*', GLOB_ONLYDIR) ?: [] as $dir) { if (!is_file($dir . '/.mvlog-hidden')) continue; $state = is_file($dir . '/.movmaker-state.json') ? json_decode((string)file_get_contents($dir . '/.movmaker-state.json'), true) : []; if (is_array($state) && !empty($state['output'])) $hidden[basename((string)$state['output'])] = true; } return $hidden; } function video_metadata($path){ $base = pathinfo($path, PATHINFO_FILENAME); $meta = [ 'title' => nice_title($base), 'date' => date('Y-m-d', filemtime($path)), 'sort_date' => date('Y-m-d', filemtime($path)), 'location' => '', 'description' => '' ]; if (preg_match('/^(\d{4})(\d{2})(\d{2})[_-](.+)$/', $base, $m)) { $meta['date'] = "$m[1]-$m[2]-$m[3]"; $meta['sort_date'] = "$m[1]-$m[2]-$m[3]"; $meta['title'] = nice_title($m[4]); } foreach ([dirname($path).'/'.$base.'.txt', dirname($path).'/'.$base.'.data.txt'] as $sidecar) { if (!is_file($sidecar)) continue; foreach (file($sidecar, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) { if (!str_contains($line, ':')) continue; [$k, $v] = array_map('trim', explode(':', $line, 2)); $k = strtolower($k); if (in_array($k, ['title','date','location','place','description'], true)) { $meta[$k === 'place' ? 'location' : $k] = $v; } } } $ffprobe = trim((string)shell_exec('command -v ffprobe 2>/dev/null')); if ($ffprobe !== '') { $json = shell_exec(escapeshellarg($ffprobe).' -v quiet -print_format json -show_entries format_tags '.escapeshellarg($path).' 2>/dev/null'); $data = json_decode((string)$json, true); $tags = $data['format']['tags'] ?? []; $lower = []; foreach ($tags as $k => $v) $lower[strtolower((string)$k)] = $v; if (!empty($lower['title'])) $meta['title'] = $lower['title']; if (!empty($lower['date'])) $meta['date'] = $lower['date']; if (!empty($lower['creation_time'])) { $meta['sort_date'] = substr((string)$lower['creation_time'], 0, 10); if (empty($lower['date'])) $meta['date'] = $meta['sort_date']; } foreach (['location','place','location-eng','com.apple.quicktime.location.name','com.apple.quicktime.location.iso6709'] as $k) { if (!empty($lower[$k])) { $meta['location'] = $lower[$k]; break; } } foreach (['description','synopsis'] as $k) { if (!empty($lower[$k])) { $meta['description'] = $lower[$k]; break; } } } return $meta; } function load_video_cache($videos){ $cacheFile = __DIR__ . '/cache/videos.json'; $cache = is_file($cacheFile) ? json_decode((string)file_get_contents($cacheFile), true) : []; if (!is_array($cache) || ($cache['version'] ?? 0) !== 2) $cache = []; $items = $cache['items'] ?? []; $newItems = []; $changed = false; foreach ($videos as $path) { $key = basename($path); $mtime = filemtime($path); $size = filesize($path); $cached = $items[$key] ?? null; if (!is_array($cached) || ($cached['mtime'] ?? null) !== $mtime || ($cached['size'] ?? null) !== $size) { $cached = ['mtime' => $mtime, 'size' => $size, 'metadata' => video_metadata($path)]; $changed = true; } $newItems[$key] = $cached; } if (array_diff(array_keys($items), array_keys($newItems))) $changed = true; if ($changed) { file_put_contents($cacheFile, json_encode([ 'version' => 2, 'generated_at' => date('c'), 'items' => $newItems ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX); } return $newItems; } $hiddenOutputs = hidden_video_outputs($config); $videos = array_values(array_filter( glob($config['videos_dir'].'/*.{mp4,webm,mov,m4v}', GLOB_BRACE) ?: [], fn($v)=>empty($hiddenOutputs[basename($v)]) && !preg_match('/_preview\.(mp4|webm|mov|m4v)$/i', basename($v)) )); $videoCache = load_video_cache($videos); usort($videos, function($a, $b) use ($videoCache) { $am = $videoCache[basename($a)] ?? []; $bm = $videoCache[basename($b)] ?? []; $ad = strtotime((string)($am['metadata']['sort_date'] ?? $am['metadata']['date'] ?? '')) ?: filemtime($a); $bd = strtotime((string)($bm['metadata']['sort_date'] ?? $bm['metadata']['date'] ?? '')) ?: filemtime($b); return $bd <=> $ad; }); $filters = [ 'f_title' => trim((string)($_GET['f_title'] ?? '')), 'f_date' => trim((string)($_GET['f_date'] ?? '')), 'f_location' => trim((string)($_GET['f_location'] ?? '')), ]; $titleExact = !empty($_GET['f_exact']) && (string)$_GET['f_exact'] === '1'; // Backward compatibility with old push URL format (?job=...) $legacyJob = trim((string)($_GET['job'] ?? '')); if ($filters['f_title'] === '' && $legacyJob !== '') { $legacy = preg_replace('/^\d{8}[_-]/', '', $legacyJob); $filters['f_title'] = nice_title($legacy ?: $legacyJob); } $videos = array_values(array_filter($videos, function($v) use ($videoCache, $filters) { $name = basename($v); $m = $videoCache[$name]['metadata'] ?? video_metadata($v); $title = (string)($m['title'] ?? ''); $date = (string)($m['date'] ?? ''); $sortDate = (string)($m['sort_date'] ?? ''); $location = (string)($m['location'] ?? ''); if ($filters['f_title'] !== '') { if ($titleExact) { if (lower_text(trim($title)) !== lower_text(trim($filters['f_title']))) return false; } else { if (stripos($title, $filters['f_title']) === false) return false; } } if ($filters['f_date'] !== '' && stripos($date, $filters['f_date']) === false && stripos($sortDate, $filters['f_date']) === false) return false; if ($filters['f_location'] !== '' && stripos($location, $filters['f_location']) === false) return false; return true; })); $page = max(1, (int)($_GET['page'] ?? 1)); $per = $config['items_per_page']; $total = count($videos); $pages = max(1, (int)ceil($total / $per)); $page = min($page, $pages); $slice = array_slice($videos, ($page - 1) * $per, $per); $activeFilterCount = count(keep_non_empty($filters)); $baseParams = keep_non_empty($filters); if ($titleExact && ($filters['f_title'] ?? '') !== '') $baseParams['f_exact'] = '1'; ?> MVLog
×

Showing article(s) 0): ?> with active filter(s)

No videos found for current filter.

(string)($m['date'] ?? '')])); $locFilterUrl = query_url(array_merge($baseParams, ['f_location' => (string)($m['location'] ?? '')])); ?>
" alt="Map">

1) $linkParams['page'] = $i; ?>