Permalink simplified

This commit is contained in:
hbrain 2026-06-20 16:49:34 +02:00
parent 040a22855e
commit b9efbf81cc
2 changed files with 7 additions and 2 deletions

View file

@ -1556,7 +1556,7 @@ $runningJobs = active_worker_jobs($config);
<noscript><button type="submit">Apply</button></noscript> <noscript><button type="submit">Apply</button></noscript>
</form> </form>
<?php if($hasVideo): ?><time class="admin-time<?= $staleLabel ? ' admin-time-stale' : '' ?>" title="<?=h($staleLabel ?: 'Video created at')?>"><?=h(date('d.m.Y H:i', filemtime($displayVideoPath)))?></time><?php endif; ?> <?php if($hasVideo): ?><time class="admin-time<?= $staleLabel ? ' admin-time-stale' : '' ?>" title="<?=h($staleLabel ?: 'Video created at')?>"><?=h(date('d.m.Y H:i', filemtime($displayVideoPath)))?></time><?php endif; ?>
</div><div class="admin-actions"><?php if($running): ?><span class="button disabled" title="Rendering now" data-edit-action="1">Rendering</span><?php elseif($publicLocked): ?><a class="button disabled" title="Disable Show and Permalink before editing" aria-disabled="true" data-edit-action="1" data-edit-href="?id=<?=rawurlencode(read_article_id($d))?>&edit=<?=rawurlencode(basename($d))?>">Edit</a><?php else: ?><a class="button" href="?id=<?=rawurlencode(read_article_id($d))?>&edit=<?=rawurlencode(basename($d))?>" data-edit-action="1" data-edit-href="?id=<?=rawurlencode(read_article_id($d))?>&edit=<?=rawurlencode(basename($d))?>">Edit</a><?php endif; ?></div></div><?php $articleIdForLink = read_article_id($d); $titlePlain = $meta['title'] ?: ($info['title'] ?? basename($d)); $titleText = h($titlePlain); $dateFilterUrl = $meta['date'] ? ('admin.php?tab=edit&q=' . rawurlencode('date=' . $meta['date'])) : ''; $locFilterUrl = $meta['location'] ? ('admin.php?tab=edit&q=' . rawurlencode('location=' . $meta['location'])) : ''; ?><h2 class="video-row-title" data-title-text="<?=h($titlePlain)?>" data-permalink-url="index.php?id=<?=rawurlencode($articleIdForLink)?>"><?php if(article_id_is_valid($articleIdForLink)): ?><a href="index.php?id=<?=rawurlencode($articleIdForLink)?>" target="_blank"><?= $titleText ?></a><?php else: ?><?= $titleText ?><?php endif; ?></h2><p class="meta"><?php if($meta['date']): ?><a class="meta-filter" href="<?=h($dateFilterUrl)?>" title="Filter by date"><?=h($meta['date'])?></a><?php endif; ?><?php if($meta['location']): ?><a class="meta-filter" href="<?=h($locFilterUrl)?>" title="Filter by location"><?=h($meta['location'])?></a><?php endif; ?></p><?php if(!empty($meta['teaser'])): ?><p class="description-teaser"><?=h((string)$meta['teaser'])?></p><?php endif; ?><?php if($meta['description']): ?><p class="description"><?=nl2br(h($meta['description']), false)?></p><?php endif; ?><?php if(!empty($meta['quote_da'])): ?><p class="description-quote">“<?=h(trim((string)$meta['quote_da'], "\"“”"))?>”</p><?php endif; ?><?php $detailParts = []; if(!$hasVideo) $detailParts[] = 'No video'; if($previewVideo) $detailParts[] = 'Preview video'; $detailParts[] = basename($d); $detailParts[] = (string)($info['file_count'] ?? count(list_files($d))) . ' files'; ?><p class="details"><?=h(implode(' · ', $detailParts))?></p></div></article><?php endforeach; ?></div><?=page_links('edit',$editPage,$editPages)?></section><?php endif; ?> </div><div class="admin-actions"><?php if($running): ?><span class="button disabled" title="Rendering now" data-edit-action="1">Rendering</span><?php elseif($publicLocked): ?><a class="button disabled" title="Disable Show and Permalink before editing" aria-disabled="true" data-edit-action="1" data-edit-href="?id=<?=rawurlencode(read_article_id($d))?>&edit=<?=rawurlencode(basename($d))?>">Edit</a><?php else: ?><a class="button" href="?id=<?=rawurlencode(read_article_id($d))?>&edit=<?=rawurlencode(basename($d))?>" data-edit-action="1" data-edit-href="?id=<?=rawurlencode(read_article_id($d))?>&edit=<?=rawurlencode(basename($d))?>">Edit</a><?php endif; ?></div></div><?php $articleIdForLink = read_article_id($d); $titlePlain = $meta['title'] ?: ($info['title'] ?? basename($d)); $titleText = h($titlePlain); $dateFilterUrl = $meta['date'] ? ('admin.php?tab=edit&q=' . rawurlencode('date=' . $meta['date'])) : ''; $locFilterUrl = $meta['location'] ? ('admin.php?tab=edit&q=' . rawurlencode('location=' . $meta['location'])) : ''; ?><h2 class="video-row-title" data-title-text="<?=h($titlePlain)?>" data-permalink-url="/?id=<?=rawurlencode($articleIdForLink)?>"><?php if(article_id_is_valid($articleIdForLink)): ?><a href="/?id=<?=rawurlencode($articleIdForLink)?>" target="_blank"><?= $titleText ?></a><?php else: ?><?= $titleText ?><?php endif; ?></h2><p class="meta"><?php if($meta['date']): ?><a class="meta-filter" href="<?=h($dateFilterUrl)?>" title="Filter by date"><?=h($meta['date'])?></a><?php endif; ?><?php if($meta['location']): ?><a class="meta-filter" href="<?=h($locFilterUrl)?>" title="Filter by location"><?=h($meta['location'])?></a><?php endif; ?></p><?php if(!empty($meta['teaser'])): ?><p class="description-teaser"><?=h((string)$meta['teaser'])?></p><?php endif; ?><?php if($meta['description']): ?><p class="description"><?=nl2br(h($meta['description']), false)?></p><?php endif; ?><?php if(!empty($meta['quote_da'])): ?><p class="description-quote">“<?=h(trim((string)$meta['quote_da'], "\"“”"))?>”</p><?php endif; ?><?php $detailParts = []; if(!$hasVideo) $detailParts[] = 'No video'; if($previewVideo) $detailParts[] = 'Preview video'; $detailParts[] = basename($d); $detailParts[] = (string)($info['file_count'] ?? count(list_files($d))) . ' files'; ?><p class="details"><?=h(implode(' · ', $detailParts))?></p></div></article><?php endforeach; ?></div><?=page_links('edit',$editPage,$editPages)?></section><?php endif; ?>
<?php if($tab==='edit' && $editDir && $editRunning): ?><section><h2>Edit input dir</h2><p><code>in-dir/<?=h(basename($editDir))?></code></p><div class="err">This input directory is <?=h($editStatus)?>. Editing is disabled until the job completes.</div></section><?php endif; ?> <?php if($tab==='edit' && $editDir && $editRunning): ?><section><h2>Edit input dir</h2><p><code>in-dir/<?=h(basename($editDir))?></code></p><div class="err">This input directory is <?=h($editStatus)?>. Editing is disabled until the job completes.</div></section><?php endif; ?>
<?php if($tab==='edit' && $editDir && !$editRunning): ?><section><h2>Edit input dir</h2><p><code>in-dir/<?=h(basename($editDir))?></code></p><form method="post" enctype="multipart/form-data" id="edit-form"><input type="hidden" name="action" value="update"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><input type="hidden" name="id" value="<?=h(ensure_article_id($editDir))?>"><label>Title<input name="title" value="<?=h($editData['title'])?>"></label><label>Teaser<input name="teaser" value="<?=h($editData['teaser'])?>" maxlength="240"></label><label>Danish quote<input name="quote_da" value="<?=h($editData['quote_da'])?>" maxlength="280"></label><label>Date<input name="date" value="<?=h($editData['date'])?>"></label><label>Place<input name="place" value="<?=h($editData['place'])?>"></label><label>Describe prompt<textarea name="describe_prompt" rows="4" placeholder="Optional extra guidance used by the Describe button"><?=h(read_describe_prompt($editDir))?></textarea></label><label>Description<textarea name="description" maxlength="5000" data-counter="description-counter-edit"><?=h($editData['description'])?></textarea><small id="description-counter-edit" class="counter"></small></label><button type="submit">Save changes</button><label>Add images / videos<input type="file" name="media[]" multiple accept="image/*,video/*"></label><label>Add audio<input type="file" name="audio[]" multiple accept="audio/*"></label><h3>Files and captions</h3><div class="file-list"><?php foreach($editFiles as $f): $ext=strtolower(pathinfo($f, PATHINFO_EXTENSION)); $fileUrl='in-dir/'.rawurlencode(basename($editDir)).'/'.rawurlencode($f); ?><div class="caption-row"><div class="preview"><?php if(in_array($ext,['jpg','jpeg','png','webp','gif'])): ?><img src="<?=h($fileUrl)?>" alt=""><?php elseif(in_array($ext,['mp4','mov','m4v','webm'])): ?><video src="<?=h($fileUrl)?>" controls preload="metadata"></video><a class="download-link" href="<?=h($fileUrl)?>" download>Download</a><?php else: ?><span><?=h(strtoupper($ext ?: 'FILE'))?></span><?php endif; ?></div><div class="caption-fields"><strong><?=h($f)?></strong><?php if(in_array($ext,['jpg','jpeg','png','webp','gif','mp4','mov','m4v','webm'])): ?><input type="hidden" name="caption_files[]" value="<?=h($f)?>"><textarea name="captions[]" placeholder="Optional caption for this file"><?=h($editData['captions'][$f] ?? '')?></textarea><?php if(in_array($ext,['mp4','mov','m4v','webm'])): ?><label class="checkbox-label"><input type="checkbox" name="use_audio_files[]" value="<?=h($f)?>" <?=!empty($editData['video_audio'][$f])?'checked':''?>> <span>Use video file audio</span></label><?php endif; ?><?php else: ?><small>No caption for audio files</small><?php endif; ?></div><div class="file-actions" style="display:flex;gap:.45rem;flex-wrap:wrap;align-self:start"><?php if(in_array($ext,['jpg','jpeg','png','webp','gif'])): ?><button type="button" class="set-thumb-btn" onclick="setThumb(<?=h(json_encode($f))?>)">Set as thumb</button><?php endif; ?><?php if(in_array($ext,['jpg','jpeg','png','webp','gif','mp4','mov','m4v','webm'])): ?><button type="button" class="button order-btn-up" title="Move up" onclick="moveFileOrder(<?=h(json_encode($f))?>,'up',this.closest('.caption-row'),this)">↑</button><button type="button" class="button order-btn-down" title="Move down" onclick="moveFileOrder(<?=h(json_encode($f))?>,'down',this.closest('.caption-row'),this)">↓</button><?php endif; ?><button type="button" onclick="deleteFile(<?=h(json_encode($f))?>)">Remove</button></div></div><?php endforeach; ?></div><button type="submit">Save changes</button></form><form method="post" id="delete-file-form" style="display:none"><input type="hidden" name="action" value="delete_file"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><input type="hidden" name="id" value="<?=h(ensure_article_id($editDir))?>"><input type="hidden" name="file" id="delete-file-name" value=""></form><form method="post" onsubmit="return confirm(\'Delete this input directory\?\')" id="delete-dir-form""><input type="hidden" name="action" value="delete_dir"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><input type="hidden" name="id" value="<?=h(ensure_article_id($editDir))?>"><label class="checkbox-label"><input type="checkbox" name="delete_output" value="1"> <span>Also delete generated video, if any</span></label><button class="danger" type="submit">Delete Article</button></form></section><?php endif; ?> <?php if($tab==='edit' && $editDir && !$editRunning): ?><section><h2>Edit input dir</h2><p><code>in-dir/<?=h(basename($editDir))?></code></p><form method="post" enctype="multipart/form-data" id="edit-form"><input type="hidden" name="action" value="update"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><input type="hidden" name="id" value="<?=h(ensure_article_id($editDir))?>"><label>Title<input name="title" value="<?=h($editData['title'])?>"></label><label>Teaser<input name="teaser" value="<?=h($editData['teaser'])?>" maxlength="240"></label><label>Danish quote<input name="quote_da" value="<?=h($editData['quote_da'])?>" maxlength="280"></label><label>Date<input name="date" value="<?=h($editData['date'])?>"></label><label>Place<input name="place" value="<?=h($editData['place'])?>"></label><label>Describe prompt<textarea name="describe_prompt" rows="4" placeholder="Optional extra guidance used by the Describe button"><?=h(read_describe_prompt($editDir))?></textarea></label><label>Description<textarea name="description" maxlength="5000" data-counter="description-counter-edit"><?=h($editData['description'])?></textarea><small id="description-counter-edit" class="counter"></small></label><button type="submit">Save changes</button><label>Add images / videos<input type="file" name="media[]" multiple accept="image/*,video/*"></label><label>Add audio<input type="file" name="audio[]" multiple accept="audio/*"></label><h3>Files and captions</h3><div class="file-list"><?php foreach($editFiles as $f): $ext=strtolower(pathinfo($f, PATHINFO_EXTENSION)); $fileUrl='in-dir/'.rawurlencode(basename($editDir)).'/'.rawurlencode($f); ?><div class="caption-row"><div class="preview"><?php if(in_array($ext,['jpg','jpeg','png','webp','gif'])): ?><img src="<?=h($fileUrl)?>" alt=""><?php elseif(in_array($ext,['mp4','mov','m4v','webm'])): ?><video src="<?=h($fileUrl)?>" controls preload="metadata"></video><a class="download-link" href="<?=h($fileUrl)?>" download>Download</a><?php else: ?><span><?=h(strtoupper($ext ?: 'FILE'))?></span><?php endif; ?></div><div class="caption-fields"><strong><?=h($f)?></strong><?php if(in_array($ext,['jpg','jpeg','png','webp','gif','mp4','mov','m4v','webm'])): ?><input type="hidden" name="caption_files[]" value="<?=h($f)?>"><textarea name="captions[]" placeholder="Optional caption for this file"><?=h($editData['captions'][$f] ?? '')?></textarea><?php if(in_array($ext,['mp4','mov','m4v','webm'])): ?><label class="checkbox-label"><input type="checkbox" name="use_audio_files[]" value="<?=h($f)?>" <?=!empty($editData['video_audio'][$f])?'checked':''?>> <span>Use video file audio</span></label><?php endif; ?><?php else: ?><small>No caption for audio files</small><?php endif; ?></div><div class="file-actions" style="display:flex;gap:.45rem;flex-wrap:wrap;align-self:start"><?php if(in_array($ext,['jpg','jpeg','png','webp','gif'])): ?><button type="button" class="set-thumb-btn" onclick="setThumb(<?=h(json_encode($f))?>)">Set as thumb</button><?php endif; ?><?php if(in_array($ext,['jpg','jpeg','png','webp','gif','mp4','mov','m4v','webm'])): ?><button type="button" class="button order-btn-up" title="Move up" onclick="moveFileOrder(<?=h(json_encode($f))?>,'up',this.closest('.caption-row'),this)">↑</button><button type="button" class="button order-btn-down" title="Move down" onclick="moveFileOrder(<?=h(json_encode($f))?>,'down',this.closest('.caption-row'),this)">↓</button><?php endif; ?><button type="button" onclick="deleteFile(<?=h(json_encode($f))?>)">Remove</button></div></div><?php endforeach; ?></div><button type="submit">Save changes</button></form><form method="post" id="delete-file-form" style="display:none"><input type="hidden" name="action" value="delete_file"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><input type="hidden" name="id" value="<?=h(ensure_article_id($editDir))?>"><input type="hidden" name="file" id="delete-file-name" value=""></form><form method="post" onsubmit="return confirm(\'Delete this input directory\?\')" id="delete-dir-form""><input type="hidden" name="action" value="delete_dir"><input type="hidden" name="dir" value="<?=h(basename($editDir))?>"><input type="hidden" name="id" value="<?=h(ensure_article_id($editDir))?>"><label class="checkbox-label"><input type="checkbox" name="delete_output" value="1"> <span>Also delete generated video, if any</span></label><button class="danger" type="submit">Delete Article</button></form></section><?php endif; ?>
<?php if($tab==='new'): ?><section><h2>Add new movie input</h2><form method="post" enctype="multipart/form-data" id="new-form"><input type="hidden" name="action" value="create"><label>Title*<input name="title" required></label><label>Teaser<input name="teaser" maxlength="240"></label><label>Danish quote<input name="quote_da" maxlength="280"></label><label>Date<input name="date" placeholder="2026-05-25"></label><label>Place<input name="place"></label><label>Description<textarea name="description" maxlength="5000" data-counter="description-counter-new"></textarea><small id="description-counter-new" class="counter"></small></label><label>Images / videos*<input type="file" name="media[]" multiple required accept="image/*,video/*"></label><label>Audio (optional)<input type="file" name="audio[]" multiple accept="audio/*"></label><button type="submit">Create</button></form></section><?php endif; ?> <?php if($tab==='new'): ?><section><h2>Add new movie input</h2><form method="post" enctype="multipart/form-data" id="new-form"><input type="hidden" name="action" value="create"><label>Title*<input name="title" required></label><label>Teaser<input name="teaser" maxlength="240"></label><label>Danish quote<input name="quote_da" maxlength="280"></label><label>Date<input name="date" placeholder="2026-05-25"></label><label>Place<input name="place"></label><label>Description<textarea name="description" maxlength="5000" data-counter="description-counter-new"></textarea><small id="description-counter-new" class="counter"></small></label><label>Images / videos*<input type="file" name="media[]" multiple required accept="image/*,video/*"></label><label>Audio (optional)<input type="file" name="audio[]" multiple accept="audio/*"></label><button type="submit">Create</button></form></section><?php endif; ?>

View file

@ -4,6 +4,11 @@ $config = require __DIR__ . "/config.php";
foreach (["videos_dir", "thumbs_dir", "uploads_dir"] as $d) if (!is_dir($config[$d])) mkdir($config[$d], 0775, true); 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); if (!is_dir(__DIR__ . "/cache")) mkdir(__DIR__ . "/cache", 0775, true);
if (preg_match('~/index\.php(?:\?|$)~', (string)($_SERVER['REQUEST_URI'] ?? '')) && preg_match('/^[0-9]{14}[a-f0-9]{16}$/', (string)($_GET['id'] ?? ''))) {
header('Location: /?id=' . rawurlencode((string)$_GET['id']), true, 301);
exit;
}
function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, "UTF-8"); } function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, "UTF-8"); }
function render_description_html($s){ function render_description_html($s){
$html = h($s); $html = h($s);
@ -536,7 +541,7 @@ $siteHeaderTitle = $headerTitles[array_rand($headerTitles)];
$base = pathinfo($name, PATHINFO_FILENAME); $base = pathinfo($name, PATHINFO_FILENAME);
$articleIdForVideo = video_article_id($config, $name); $articleIdForVideo = video_article_id($config, $name);
$permalinkEnabled = $articleIdForVideo !== '' && article_permalink_enabled($config, $articleIdForVideo); $permalinkEnabled = $articleIdForVideo !== '' && article_permalink_enabled($config, $articleIdForVideo);
$permalinkUrl = $permalinkEnabled ? query_url(['id' => $articleIdForVideo]) : ''; $permalinkUrl = $permalinkEnabled ? ('/?id=' . rawurlencode($articleIdForVideo)) : '';
$shareUrl = $permalinkEnabled ? ('https://bubulescu.org/?id=' . rawurlencode($articleIdForVideo)) : ''; $shareUrl = $permalinkEnabled ? ('https://bubulescu.org/?id=' . rawurlencode($articleIdForVideo)) : '';
$url = $config['public_videos'].'/'.rawurlencode($name); $url = $config['public_videos'].'/'.rawurlencode($name);
$m = $videoCache[$name]['metadata'] ?? video_metadata($v); $m = $videoCache[$name]['metadata'] ?? video_metadata($v);