Use article IDs for permalinks and OG images

This commit is contained in:
hbrain 2026-06-02 09:50:00 +00:00
parent fbc4f1045a
commit 37e43b6bca
3 changed files with 168 additions and 59 deletions

View file

@ -57,16 +57,60 @@ function map_hidden_outputs($config){
return $hidden;
}
function public_url_path($path){
$path = str_replace('\\', '/', trim((string)$path));
if ($path === '') return '';
$parts = array_values(array_filter(explode('/', $path), static fn($p) => $p !== ''));
return implode('/', array_map('rawurlencode', $parts));
}
function video_thumb_public_url($config, $videoName){
$videoName = basename((string)$videoName);
if ($videoName === '') return '';
$base = pathinfo($videoName, PATHINFO_FILENAME);
foreach (['jpg','jpeg','png','webp','gif'] as $ext) {
$file = $config['videos_dir'] . '/' . $base . '_thumb.' . $ext;
if (is_file($file)) return $config['public_videos'] . '/' . rawurlencode($base . '_thumb.' . $ext) . '?v=' . filemtime($file);
$info = function_exists('video_thumb_source_info') ? video_thumb_source_info($config, $videoName) : [];
$sourcePath = (string)($info['source_path'] ?? '');
if ($sourcePath !== '') {
$abs = str_starts_with($sourcePath, '/') ? $sourcePath : __DIR__ . '/' . ltrim($sourcePath, '/');
if (is_file($abs)) return public_url_path($sourcePath) . '?v=' . filemtime($abs);
}
$sourceFile = basename((string)($info['source_file'] ?? ''));
$inputDir = basename((string)($info['input_dir'] ?? ''));
if ($sourceFile !== '' && $inputDir !== '') {
$rel = 'in-dir/' . $inputDir . '/' . $sourceFile;
$abs = __DIR__ . '/' . $rel;
if (is_file($abs)) return public_url_path($rel) . '?v=' . filemtime($abs);
}
return '';
}
function video_thumb_source_info($config, $videoName){
$videoName = basename((string)$videoName);
if ($videoName === '') return [];
$base = pathinfo($videoName, PATHINFO_FILENAME);
$file = $config['videos_dir'] . '/' . $base . '_thumb.json';
if (!is_file($file)) return [];
$data = json_decode((string)file_get_contents($file), true);
return is_array($data) ? $data : [];
}
function video_article_id($config, $videoName){
$videoName = basename((string)$videoName);
if ($videoName === '') return '';
foreach (glob($config['uploads_dir'].'/*', GLOB_ONLYDIR) ?: [] as $dir) {
$stateFile = $dir . '/.movmaker-state.json';
if (!is_file($stateFile)) continue;
$state = json_decode((string)file_get_contents($stateFile), true);
if (!is_array($state)) continue;
$output = basename((string)($state['output'] ?? ''));
$previewOutput = basename((string)($state['preview_output'] ?? ''));
if ($videoName === $output || $videoName === $previewOutput) return (string)($state['article_id'] ?? '');
}
return '';
}
function article_og_image_url($articleId){
$articleId = strtolower(trim((string)$articleId));
if (!preg_match('/^[0-9]{14}[a-f0-9]{16}$/', $articleId)) return '';
$path = __DIR__ . '/out-dir/' . $articleId . '_og.jpg';
if (!is_file($path)) return '';
return 'https://bubulescu.org/out-dir/' . rawurlencode($articleId . '_og.jpg');
}
function video_metadata($path){
$base = pathinfo($path, PATHINFO_FILENAME);
@ -181,8 +225,8 @@ usort($videos, function($a, $b) use ($videoCache) {
$articleId = trim((string)($_GET['id'] ?? ''));
if ($articleId !== '') {
$videos = array_values(array_filter($videos, function($v) use ($articleId) {
return pathinfo($v, PATHINFO_FILENAME) === $articleId;
$videos = array_values(array_filter($videos, function($v) use ($articleId, $config) {
return video_article_id($config, basename($v)) === $articleId;
}));
$rawKeyword = '';
$keywordType = 'general';
@ -248,6 +292,21 @@ $slice = array_slice($videos, ($page - 1) * $per, $per);
$activeFilterCount = ($keywordValue !== '') ? 1 : 0;
$baseParams = ($rawKeyword !== '') ? ['q' => $rawKeyword] : [];
$defaultOgImageUrl = 'https://bubulescu.org/assets/img/bubulescuorg.jpg';
$ogImageUrl = $defaultOgImageUrl;
$ogImageAlt = 'MVLog: journal of an unreliable narrator.';
if ($articleId !== '') {
$customOg = article_og_image_url($articleId);
if ($customOg !== '') {
$ogImageUrl = $customOg;
if (!empty($slice)) {
$firstVideo = basename((string)$slice[0]);
$firstMeta = $videoCache[$firstVideo]['metadata'] ?? video_metadata($slice[0]);
$firstTitle = trim((string)($firstMeta['title'] ?? ''));
if ($firstTitle !== '') $ogImageAlt = 'MVLog: ' . $firstTitle;
}
}
}
$headerTitles = [
'Multiple Voices Log',
'MultiVerse Log',
@ -307,15 +366,15 @@ $siteHeaderTitle = $headerTitles[array_rand($headerTitles)];
<meta property="og:site_name" content="Bubulescu.Org">
<!-- Image -->
<meta property="og:image" content="https://bubulescu.org/assets/img/bubulescuorg.jpg">
<meta property="og:image:secure_url" content="https://bubulescu.org/assets/img/bubulescuorg.jpg">
<meta property="og:image" content="<?=h($ogImageUrl)?>">
<meta property="og:image:secure_url" content="<?=h($ogImageUrl)?>">
<meta property="og:image:type" content="image/jpeg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="MVLog: journal of an unreliable narrator.">
<meta property="og:image:alt" content="<?=h($ogImageAlt)?>">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://bubulescu.org/assets/img/bubulescuorg.jpg">
<meta name="twitter:image" content="<?=h($ogImageUrl)?>">
<link rel="alternate" type="application/rss+xml" title="MVLog RSS" href="feed.php">
<link rel="icon" type="image/png" href="assets/img/moto_travel.png">
@ -385,7 +444,8 @@ $siteHeaderTitle = $headerTitles[array_rand($headerTitles)];
<?php foreach($slice as $v):
$name = basename($v);
$base = pathinfo($name, PATHINFO_FILENAME);
$permalinkUrl = query_url(['id' => $base]);
$articleIdForVideo = video_article_id($config, $name);
$permalinkUrl = $articleIdForVideo !== '' ? query_url(['id' => $articleIdForVideo]) : '';
$url = $config['public_videos'].'/'.rawurlencode($name);
$m = $videoCache[$name]['metadata'] ?? video_metadata($v);
$posterUrl = video_thumb_public_url($config, $name);
@ -394,7 +454,7 @@ $siteHeaderTitle = $headerTitles[array_rand($headerTitles)];
?>
<article class="video-row">
<div class="video-row-head video-row-head-mobile">
<h2 class="video-row-title"><a href="<?=h($permalinkUrl)?>"><?=h($m['title'])?></a></h2>
<h2 class="video-row-title"><?php if($permalinkUrl !== ''): ?><a href="<?=h($permalinkUrl)?>"><?=h($m['title'])?></a><?php else: ?><?=h($m['title'])?><?php endif; ?></h2>
<p class="meta">
<span><a href="<?=h($dateFilterUrl)?>"><?=h($m['date'])?></a></span>
<?php if(!empty($m['location'])): ?><span><a href="<?=h($locFilterUrl)?>"><?=h($m['location'])?></a></span><?php endif; ?>
@ -412,7 +472,7 @@ $siteHeaderTitle = $headerTitles[array_rand($headerTitles)];
<?php endif; ?>
</div>
<div class="video-info">
<h2 class="video-row-title video-row-title-desktop"><a href="<?=h($permalinkUrl)?>"><?=h($m['title'])?></a></h2>
<h2 class="video-row-title video-row-title-desktop"><?php if($permalinkUrl !== ''): ?><a href="<?=h($permalinkUrl)?>"><?=h($m['title'])?></a><?php else: ?><?=h($m['title'])?><?php endif; ?></h2>
<p class="meta meta-desktop">
<span><a href="<?=h($dateFilterUrl)?>"><?=h($m['date'])?></a></span>
<?php if(!empty($m['location'])): ?><span><a href="<?=h($locFilterUrl)?>"><?=h($m['location'])?></a></span><?php endif; ?>