- Descriptions now render Markdown or sanitized HTML via [includes/db.php](/Users/tyemeclifford/Documents/GH/mediaplayer/includes/db.php).

Public player descriptions render formatted HTML on the homepage.
Catalogue cards, embed meta tags, and social metadata use safe 
plain-text excerpts.
Add/edit admin pages now use a rich description editor that preserves 
pasted HTML styling, with a textarea fallback for no-JS.
External/YouTube-imported descriptions are sanitized before storage.
README now documents Markdown/HTML description support.
This commit is contained in:
Ty Clifford
2026-07-01 15:41:01 -04:00
parent e9369e242c
commit 6a1c545f35
11 changed files with 787 additions and 17 deletions
+11 -5
View File
@@ -9,7 +9,7 @@ $msg = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = trim($_POST['title'] ?? '');
$description = trim($_POST['description'] ?? '');
$description = media_prepare_description_for_storage($_POST['description'] ?? '');
$duration = (int)($_POST['duration'] ?? 0);
$sort_order = (int)($_POST['sort_order'] ?? 0);
$published = isset($_POST['published']) ? 1 : 0;
@@ -40,7 +40,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$metadata = media_external_metadata($url);
$source_metadata[$url] = $metadata;
if ($title === '' && $metadata['title'] !== '') $title = $metadata['title'];
if ($description === '' && $metadata['description'] !== '') $description = $metadata['description'];
if ($description === '' && $metadata['description'] !== '') {
$description = media_prepare_description_for_storage($metadata['description']);
}
if ($duration <= 0 && (int)$metadata['duration'] > 0) $duration = (int)$metadata['duration'];
if ((int)$metadata['view_count'] > $initial_external_view_count) {
$initial_external_view_count = (int)$metadata['view_count'];
@@ -291,8 +293,8 @@ render_head('Add Video — Admin', '
<span class="hint">Leave blank when pasting a supported external URL, then use Fetch Info.</span>
</div>
<div class="form-group span2">
<label class="form-label" for="description">Description</label>
<textarea class="form-textarea" id="description" name="description" rows="3"><?= h($_POST['description'] ?? '') ?></textarea>
<label class="form-label" id="description-label" for="description">Description</label>
<?php render_description_editor($_POST['description'] ?? ''); ?>
</div>
<div class="form-group">
<label class="form-label" for="duration">Duration (seconds)</label>
@@ -401,6 +403,7 @@ render_head('Add Video — Admin', '
<?php render_footer(); ?>
</main>
<?php render_description_editor_script(); ?>
<script>
function toggleSourceRow(row) {
var select = row.querySelector('.source-type-select');
@@ -430,7 +433,10 @@ function fillFromMetadata(row, metadata, force) {
var label = row.querySelector('input[name="source_label[]"]');
if (metadata.title && title && (force || !title.value.trim())) title.value = metadata.title;
if (metadata.description && description && (force || !description.value.trim())) description.value = metadata.description;
if (metadata.description && description && (force || !description.value.trim())) {
if (window.setDescriptionEditorValue) window.setDescriptionEditorValue(metadata.description);
else description.value = metadata.description;
}
if (metadata.duration && duration && (force || !parseInt(duration.value || '0', 10))) duration.value = metadata.duration;
if (label && !label.value.trim()) label.value = providerLabel(metadata.provider) || metadata.title || 'External';
}
+4 -3
View File
@@ -39,7 +39,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($action === 'save') {
$title = trim($_POST['title'] ?? '');
$description = trim($_POST['description'] ?? '');
$description = media_prepare_description_for_storage($_POST['description'] ?? '');
$duration = (int)($_POST['duration'] ?? 0);
$sort_order = (int)($_POST['sort_order'] ?? 0);
$view_count = max(0, (int)($_POST['view_count'] ?? $video['view_count']));
@@ -335,8 +335,8 @@ render_head('Edit Video — Admin', '
value="<?= h($video['title']) ?>" required>
</div>
<div class="form-group span2">
<label class="form-label" for="description">Description</label>
<textarea class="form-textarea" id="description" name="description" rows="3"><?= h($video['description']) ?></textarea>
<label class="form-label" id="description-label" for="description">Description</label>
<?php render_description_editor($video['description']); ?>
</div>
<div class="form-group">
<label class="form-label">Slug (auto-generated)</label>
@@ -508,6 +508,7 @@ render_head('Edit Video — Admin', '
<?php render_footer(); ?>
</main>
<?php render_description_editor_script(); ?>
<script>
function toggleSourceRow(row) {
var select = row.querySelector('.source-type-select');
+1 -1
View File
@@ -251,7 +251,7 @@ function yt_video_record(string $id, string $title, string $description = '', st
return [
'id' => $id,
'title' => $title,
'description' => trim($description),
'description' => media_prepare_description_for_storage($description),
'duration' => yt_duration_seconds($duration_text),
'duration_text' => trim($duration_text),
'thumbnail_url' => $thumbnail_url ?: 'https://i.ytimg.com/vi/' . rawurlencode($id) . '/hqdefault.jpg',