- Implemented audio support with Video.js.

What changed:
Added uploaded/direct audio playback paths in 
[index.php](/Users/tyemeclifford/Documents/GH/mediaplayer/index.php) and 
[embed.php](/Users/tyemeclifford/Documents/GH/mediaplayer/embed.php).
Added common audio upload support: MP3, M4A, AAC, WAV, FLAC, OGG, OGA, 
OPUS.
Added waveform poster generation for uploaded audio via ffmpeg, stored 
like normal thumbnails under media/thumbs/.
Updated add/edit forms to accept media files, not just video files.
Added audio-friendly labels like Audio, 320kbps, 256kbps, 128kbps.
Updated docs and changelog.
This commit is contained in:
Ty Clifford
2026-06-25 13:34:20 -04:00
parent 8a39bc02fa
commit 7deae1a399
10 changed files with 365 additions and 80 deletions
+96 -16
View File
@@ -33,6 +33,13 @@ $native_player_sources = [];
foreach ($player_sources as $player_source) {
if (($player_source['kind'] ?? '') !== 'iframe') $native_player_sources[] = $player_source;
}
$native_player_mode = (($primary_player_source['kind'] ?? '') === 'audio') ? 'audio' : 'video';
$active_native_sources = [];
foreach ($native_player_sources as $player_source) {
$kind = $player_source['kind'] ?? '';
if ($native_player_mode === 'audio' && $kind === 'audio') $active_native_sources[] = $player_source;
if ($native_player_mode === 'video' && $kind !== 'audio') $active_native_sources[] = $player_source;
}
$meta_title = $video ? $video['title'] . ' — TyClifford.com' : 'Video Player';
$meta_description = $video && trim($video['description'] ?? '') !== '' ? trim($video['description']) : 'TyClifford.com media player';
@@ -153,6 +160,57 @@ header('Content-Security-Policy: frame-ancestors *');
.video-js .vjs-current-time,
.video-js .vjs-duration,
.video-js .vjs-time-divider { color: rgba(255,255,255,.8) !important; font-size: .7em !important; }
.audio-player-frame {
position: absolute;
inset: 0;
display: flex;
align-items: flex-end;
justify-content: center;
padding: 1rem;
background: radial-gradient(circle at 50% 35%, rgba(176,96,255,.12), transparent 55%), #09090f;
}
.audio-waveform-art {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(180deg, rgba(9,9,15,.2), rgba(9,9,15,.82));
overflow: hidden;
}
.audio-waveform-art img {
width: 100%;
height: 100%;
object-fit: cover;
opacity: .92;
filter: saturate(1.15) contrast(1.05);
}
.audio-waveform-fallback {
position: absolute;
inset: 0;
background:
linear-gradient(90deg, transparent 0 4%, rgba(0,232,122,.34) 4% 5%, transparent 5% 9%),
radial-gradient(circle at 50% 35%, rgba(0,232,122,.12), transparent 55%),
#09090f;
background-size: 90px 100%, 100% 100%, 100% 100%;
opacity: .9;
}
.audio-player-frame .video-js {
position: relative !important;
inset: auto !important;
width: 100% !important;
max-width: calc(100% - 1rem) !important;
height: 4.2rem !important;
background: rgba(9,9,15,.86) !important;
border: 1px solid rgba(255,255,255,.08);
border-radius: 6px;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0,0,0,.35);
}
.audio-player-frame .video-js .vjs-control-bar {
background: rgba(9,9,15,.92) !important;
height: 4.2rem !important;
}
.provider-embed-frame {
position: absolute;
inset: 0;
@@ -240,20 +298,42 @@ header('Content-Security-Policy: frame-ancestors *');
allow="accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share"
allowfullscreen
referrerpolicy="no-referrer-when-downgrade"></iframe>
<?php elseif (!empty($native_player_sources)): ?>
<video id="embed-player"
class="video-js vjs-default-skin vjs-big-play-centered"
controls preload="metadata"
<?php if ($video['thumbnail']): ?>
poster="<?= htmlspecialchars(public_absolute_url(public_media_url($video['thumbnail'])), ENT_QUOTES) ?>"
<?php endif; ?>>
<?php foreach ($native_player_sources as $src): ?>
<source
src="<?= htmlspecialchars($src['url'], ENT_QUOTES) ?>"
type="<?= htmlspecialchars($src['mime'], ENT_QUOTES) ?>">
<?php endforeach; ?>
<p class="vjs-no-js">Your browser does not support HTML5 video.</p>
</video>
<?php elseif (!empty($active_native_sources)): ?>
<?php if ($native_player_mode === 'audio'): ?>
<div class="audio-player-frame">
<div class="audio-waveform-art" aria-hidden="true">
<?php if ($video['thumbnail']): ?>
<img src="<?= h(public_absolute_url(public_media_url($video['thumbnail']))) ?>" alt="">
<?php else: ?>
<div class="audio-waveform-fallback"></div>
<?php endif; ?>
</div>
<audio id="embed-player"
class="video-js vjs-default-skin"
controls preload="metadata">
<?php foreach ($active_native_sources as $src): ?>
<source
src="<?= htmlspecialchars($src['url'], ENT_QUOTES) ?>"
type="<?= htmlspecialchars($src['mime'], ENT_QUOTES) ?>">
<?php endforeach; ?>
<p class="vjs-no-js">Your browser does not support HTML5 audio.</p>
</audio>
</div>
<?php else: ?>
<video id="embed-player"
class="video-js vjs-default-skin vjs-big-play-centered"
controls preload="metadata"
<?php if ($video['thumbnail']): ?>
poster="<?= htmlspecialchars(public_absolute_url(public_media_url($video['thumbnail'])), ENT_QUOTES) ?>"
<?php endif; ?>>
<?php foreach ($active_native_sources as $src): ?>
<source
src="<?= htmlspecialchars($src['url'], ENT_QUOTES) ?>"
type="<?= htmlspecialchars($src['mime'], ENT_QUOTES) ?>">
<?php endforeach; ?>
<p class="vjs-no-js">Your browser does not support HTML5 video.</p>
</video>
<?php endif; ?>
<?php endif; ?>
<?php else: ?>
@@ -265,13 +345,13 @@ header('Content-Security-Policy: frame-ancestors *');
<line x1="8" y1="21" x2="16" y2="21"/>
<line x1="12" y1="17" x2="12" y2="21"/>
</svg>
<p><?= $slug ? 'video not found' : 'no video specified' ?></p>
<p><?= $slug ? 'media not found' : 'no media specified' ?></p>
</div>
<?php endif; ?>
</div>
<?php if ($video && !empty($native_player_sources) && (!$primary_player_source || ($primary_player_source['kind'] ?? '') !== 'iframe')): ?>
<?php if ($video && !empty($active_native_sources) && (!$primary_player_source || ($primary_player_source['kind'] ?? '') !== 'iframe')): ?>
<script>
document.addEventListener('DOMContentLoaded', function () {
var player = videojs('embed-player', {