switch over to MediaElement.js so we can add skip-30-second buttons
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -4,3 +4,6 @@
|
||||
[submodule "getid3"]
|
||||
path = getid3
|
||||
url = https://github.com/JamesHeinrich/getID3
|
||||
[submodule "mediaelement-plugins"]
|
||||
path = mediaelement-plugins
|
||||
url = https://github.com/mediaelement/mediaelement-plugins
|
||||
|
||||
10
.vscode/launch.json
vendored
Normal file
10
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Listen for Xdebug",
|
||||
"type": "php",
|
||||
"request": "launch",
|
||||
"port": 9000
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -7,4 +7,5 @@ ENV CHANNELS "${CHANNELS:-1}"
|
||||
ENV BITRATE "${BITRATE:-32}"
|
||||
RUN (cd /var/www/html && curl -L https://github.com/JamesHeinrich/getID3/archive/refs/tags/v1.9.21.tar.gz | tar xzf - && mv getID3-* getid3)
|
||||
RUN (cd /var/www/html && curl -L https://github.com/mediaelement/mediaelement/archive/refs/tags/5.0.1.tar.gz | tar xzf - && mv mediaelement-* mediaelement)
|
||||
RUN (cd /var/www/html && curl -L https://github.com/mediaelement/mediaelement-plugins/archive/refs/tags/2.6.1.tar.gz | tar xzf - && mv mediaelement-plugins-* mediaelement-plugins)
|
||||
VOLUME /var/www/html/
|
||||
|
||||
@@ -3,6 +3,8 @@ StreamShifter
|
||||
|
||||
Capture streaming audio from your favorite sources to build a custom podcast stream. I used this for a number of years on a bog-standard Linux/Nginx/PHP-FPM server, and have recently containerized it for use with Docker. It'll record live audio captured from a URL, transcoding it into a common format along the way. You can listen to the most recent stream as it records with HTTP live streaming, or you can listen later to the podcast.
|
||||
|
||||
StreamShifter actually uses MediaElement.js now...it wasn't previously. Buttons to skip forward and back 30 seconds have been added to the player, which are convenient for skipping past commercials.
|
||||
|
||||
Standalone Instructions
|
||||
-----------------------
|
||||
|
||||
|
||||
141
index.php
141
index.php
@@ -1,78 +1,79 @@
|
||||
<html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Live Audio and Podcasts</title>
|
||||
<meta name="viewport" content="width=320">
|
||||
<script src="mediaelement/build/jquery.js"></script>
|
||||
<script src="mediaelement/build/mediaelement-and-player.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
|
||||
<link rel="stylesheet" href="mediaelement/build/mediaelementplayer.min.css" />
|
||||
<script type="text/javascript">
|
||||
function LoadAudio(file)
|
||||
{
|
||||
document.getElementById("player").style.visibility="visible";
|
||||
document.getElementById("video").style.visibility="hidden";
|
||||
<title>Live Audio and Podcasts</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
document.getElementById("player").innerHTML="<audio src=\"audio/"+file+"\" type=\"audio/m4a\" controls=\"controls\" width=\"500px\" />";
|
||||
document.getElementById("filename").innerHTML=file;
|
||||
$('audio').mediaelementplayer();
|
||||
}
|
||||
|
||||
function LoadM3U8(file)
|
||||
{
|
||||
document.getElementById("player").style.visibility="hidden";
|
||||
document.getElementById("video").style.visibility="visible";
|
||||
|
||||
var video=document.getElementById("video");
|
||||
if (Hls.isSupported())
|
||||
{
|
||||
var hls=new Hls();
|
||||
hls.loadSource(file);
|
||||
hls.attachMedia(video);
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function() {video.play();});
|
||||
}
|
||||
else if (video.canPlayType("application/vnd.apple.mpegurl"))
|
||||
{
|
||||
video.src=file;
|
||||
video.addEventListener("loadedmetadata", function() {video.play();});
|
||||
}
|
||||
document.getElementById("filename").innerHTML=file;
|
||||
}
|
||||
</script>
|
||||
<link rel="stylesheet" href="mediaelement/build/mediaelementplayer.css">
|
||||
<link rel="stylesheet" href="mediaelement-plugins/dist/jump-forward/jump-forward.css">
|
||||
<link rel="stylesheet" href="mediaelement-plugins/dist/skip-back/skip-back.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Live Audio and Podcasts</h1>
|
||||
<ul>
|
||||
<?php
|
||||
$arr=[];
|
||||
$c=0;
|
||||
if ($h=opendir("audio"))
|
||||
{
|
||||
while (($e=readdir($h))!==false)
|
||||
<h1>Live Audio and Podcasts</h1>
|
||||
<ul>
|
||||
<?php
|
||||
$arr=[];
|
||||
$c=0;
|
||||
if ($h=opendir("audio"))
|
||||
{
|
||||
if (strlen($e)>4)
|
||||
if (substr_compare($e,".m4a",-4,4)===0)
|
||||
$arr[$c++]="<li><a href=\"audio/".$e."\">".$e."</a> (<a href=\"#\" onclick=\"LoadAudio('".$e."')\">Load in Player</a>)</li>\n";
|
||||
while (($e=readdir($h))!==false)
|
||||
{
|
||||
if (strlen($e)>4)
|
||||
if (substr_compare($e,".m4a",-4,4)===0)
|
||||
$arr[$c++]="<li><a href=\"audio/".$e."\">".$e."</a> (<a href=\"#\" onclick=\"Load('audio/".$e."', 'audio/m4a')\">Load in Player</a>)</li>\n";
|
||||
}
|
||||
closedir($h);
|
||||
}
|
||||
closedir($h);
|
||||
}
|
||||
if ($h=opendir("."))
|
||||
{
|
||||
while (($e=readdir($h))!==false)
|
||||
if ($h=opendir("."))
|
||||
{
|
||||
if (strlen($e)>5)
|
||||
if (substr_compare($e,".m3u8",-5,5)===0)
|
||||
$arr[$c++]="<li><a href=\"".$e."\">".$e."</a> (<a href=\"#\" onclick=\"LoadM3U8('".$e."')\">Load in Player</a>)</li>\n";
|
||||
while (($e=readdir($h))!==false)
|
||||
{
|
||||
if (strlen($e)>5)
|
||||
if (substr_compare($e,".m3u8",-5,5)===0)
|
||||
$arr[$c++]="<li><a href=\"".$e."\">".$e."</a> (<a href=\"#\" onclick=\"Load('".$e."', 'application/x-mpegURL')\">Load in Player</a>)</li>\n";
|
||||
}
|
||||
closedir($h);
|
||||
}
|
||||
closedir($h);
|
||||
}
|
||||
sort($arr);
|
||||
foreach ($arr as $item)
|
||||
echo $item;
|
||||
?>
|
||||
<li><a href="rss.php">RSS Feed</a></li>
|
||||
</ul>
|
||||
<p>
|
||||
<span id="player" style="visibility: hidden;"></span>
|
||||
<video id="video" controls autoplay style="width: 500px; height: 50px; visibility: hidden;"></video>
|
||||
<br /><span id="filename"></span></p>
|
||||
</body></html>
|
||||
sort($arr);
|
||||
foreach ($arr as $item)
|
||||
echo $item;
|
||||
?>
|
||||
<li><a href="rss.php">RSS Feed</a></li>
|
||||
</ul>
|
||||
<br />
|
||||
<div class="media-wrapper">
|
||||
<audio id="player1" width="400" height="45" controls preload="none"></audio>
|
||||
</div>
|
||||
|
||||
<br /><span id="filename"></span>
|
||||
|
||||
<script src="mediaelement/build/mediaelement-and-player.min.js"></script>
|
||||
<script src="mediaelement-plugins/dist/jump-forward/jump-forward.js"></script>
|
||||
<script src="mediaelement-plugins/dist/skip-back/skip-back.js"></script>
|
||||
<script>
|
||||
var mediaElements = document.querySelectorAll('video, audio');
|
||||
|
||||
for (var i = 0, total = mediaElements.length; i < total; i++) {
|
||||
|
||||
var features = ['playpause', 'current', 'skipback', 'progress', 'jumpforward', 'duration'];
|
||||
|
||||
new MediaElementPlayer(mediaElements[i], {
|
||||
autoRewind: false,
|
||||
features: features,
|
||||
});
|
||||
}
|
||||
|
||||
function Load(src, mime_type)
|
||||
{
|
||||
document.getElementById("player1").src=src;
|
||||
document.getElementById("player1").type=mime_type;
|
||||
document.getElementById("player1").load();
|
||||
document.getElementById("player1").play();
|
||||
document.getElementById("filename").innerHTML=src;
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
1
mediaelement-plugins
Submodule
1
mediaelement-plugins
Submodule
Submodule mediaelement-plugins added at 9651e3f626
68
mejs-controls.svg
Normal file
68
mejs-controls.svg
Normal file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<symbol id="icon-captions" viewBox="0 0 18 14" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#fff">
|
||||
<path d="M-.67-4.08h14a2,2,0,0,1,2,2v10a2,2,0,0,1-2,2h-14a2,2,0,0,1-2-2v-10A2,2,0,0,1-.67-4.08Z" transform="translate(2.67 4.08)"/>
|
||||
</g>
|
||||
<g fill="#000">
|
||||
<path d="M2.88,6.67a2.81,2.81,0,0,1-2.1-1A3.91,3.91,0,0,1,.88.87c.5-.6,2-1.7,4.6.2l-.6.8c-1.4-1-2.6-1.1-3.3-.3a3,3,0,0,0-.1,3.5c.7.9,1.9.8,3.4-.1l.5.9a5.28,5.28,0,0,1-2.5.8Zm7.5,0a2.81,2.81,0,0,1-2.1-1,3.91,3.91,0,0,1,.1-4.8c.5-.6,2-1.7,4.6.2l-.5.8c-1.4-1-2.6-1.1-3.3-.3a3,3,0,0,0-.1,3.5c.7.9,1.9.8,3.4-.1l.5.9a6.07,6.07,0,0,1-2.6.8Z" transform="translate(2.67 4.08)"/>
|
||||
</g>
|
||||
</symbol>
|
||||
<symbol id="icon-chapters" viewBox="0 0 16.6 13" xmlns="http://www.w3.org/2000/svg"><path d="M1.5,0A1.54,1.54,0,0,1,3,1.5,1.54,1.54,0,0,1,1.5,3,1.54,1.54,0,0,1,0,1.5,1.47,1.47,0,0,1,1.5,0ZM6.6,0h8.5a1.47,1.47,0,0,1,1.5,1.5A1.54,1.54,0,0,1,15.1,3H6.6A1.47,1.47,0,0,1,5.1,1.5,1.37,1.37,0,0,1,6.6,0ZM1.5,5A1.54,1.54,0,0,1,3,6.5,1.54,1.54,0,0,1,1.5,8,1.54,1.54,0,0,1,0,6.5,1.47,1.47,0,0,1,1.5,5ZM6.6,5h8.5a1.47,1.47,0,0,1,1.5,1.5A1.54,1.54,0,0,1,15.1,8H6.6A1.47,1.47,0,0,1,5.1,6.5,1.37,1.37,0,0,1,6.6,5ZM1.5,10a1.5,1.5,0,0,1,0,3A1.54,1.54,0,0,1,0,11.5,1.47,1.47,0,0,1,1.5,10Zm5.1,0h8.5a1.47,1.47,0,0,1,1.5,1.5A1.54,1.54,0,0,1,15.1,13H6.6a1.47,1.47,0,0,1-1.5-1.5A1.37,1.37,0,0,1,6.6,10Z"/></symbol>
|
||||
<symbol id="icon-fullscreen" viewBox="0 0 17.8 17.8" xmlns="http://www.w3.org/2000/svg"><path d="M0,1A.94.94,0,0,1,1,0H6.4c.6,0,.7.3.3.7l-6,6C.3,7.1,0,7,0,6.4ZM0,16.8a.94.94,0,0,0,1,1H6.4c.6,0,.7-.3.3-.7l-6-6c-.4-.4-.7-.3-.7.3ZM17.8,1a.94.94,0,0,0-1-1H11.4c-.6,0-.7.3-.3.7l6,6c.4.4.7.3.7-.3Zm0,15.8a.94.94,0,0,1-1,1H11.4c-.6,0-.7-.3-.3-.7l6-6c.4-.4.7-.3.7.3Z"/></symbol>
|
||||
<symbol id="icon-unfullscreen" viewBox="0 0 17.8 17.8" xmlns="http://www.w3.org/2000/svg"><path d="M11.74,4.64a.94.94,0,0,0,1,1h4.1c.6,0,.7-.3.3-.7L12.44.24c-.4-.4-.7-.3-.7.3Zm-7.1,1a.94.94,0,0,0,1-1V.54c0-.6-.3-.7-.7-.3L.24,4.94c-.4.4-.3.7.3.7Zm1,7.1a.94.94,0,0,0-1-1H.54c-.6,0-.7.3-.3.7l4.7,4.7c.4.4.7.3.7-.3Zm7.1-1a.94.94,0,0,0-1,1v4.1c0,.5.3.7.7.3l4.7-4.7c.4-.4.3-.7-.3-.7Z"/></symbol>
|
||||
<symbol id="icon-mute" viewBox="0 0 17.55 17.03" xmlns="http://www.w3.org/2000/svg">
|
||||
<g stroke="none">
|
||||
<path d="M6.21,4.36a3,3,0,0,1-1.8.6H1.21a.94.94,0,0,0-1,1v5.7a.94.94,0,0,0,1,1h4.2c.3.2.5.4.8.6l3.5,2.6a.47.47,0,0,0,.8-.4V2.06a.47.47,0,0,0-.8-.4Z"/>
|
||||
</g>
|
||||
<g fill="none" stroke-linecap="round" stroke-width="1.5px">
|
||||
<path d="M13.11,1.18S17,.38,17,8.88s-3.9,7.8-3.9,7.8"/>
|
||||
<path d="M11.81,5.08s2.6-.4,2.6,3.8-2.6,3.9-2.6,3.9"/>
|
||||
</g>
|
||||
</symbol>
|
||||
<symbol id="icon-unmute" viewBox="0 0 18.2 17" xmlns="http://www.w3.org/2000/svg">
|
||||
<g stroke="none">
|
||||
<path d="M6.21,4.36a3,3,0,0,1-1.8.6H1.21a.94.94,0,0,0-1,1v5.7a.94.94,0,0,0,1,1h4.2c.3.2.5.4.8.6l3.5,2.6a.47.47,0,0,0,.8-.4V2.06a.47.47,0,0,0-.8-.4Z"/>
|
||||
</g>
|
||||
<g fill="none" stroke-linecap="round" stroke-width="2px">
|
||||
<path d="M12,5.55l5.4,5.4M12,11l5.4-5.4"/>
|
||||
</g>
|
||||
</symbol>
|
||||
<symbol id="icon-play" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"><path d="M16.5 8.5c.3.1.4.5.2.8-.1.1-.1.2-.2.2l-11.4 7c-.5.3-.8.1-.8-.5V2c0-.5.4-.8.8-.5l11.4 7z"/></symbol>
|
||||
<symbol id="icon-pause" viewBox="0 0 14 16" xmlns="http://www.w3.org/2000/svg"><path d="M1,0H3.2a.94.94,0,0,1,1,1V15a.94.94,0,0,1-1,1H1a.94.94,0,0,1-1-1V1A1,1,0,0,1,1,0Zm9.8,0H13a.94.94,0,0,1,1,1V15a.94.94,0,0,1-1,1H10.8a.94.94,0,0,1-1-1V1A1,1,0,0,1,10.8,0Z"/></symbol>
|
||||
<symbol id="icon-replay" viewBox="0 0 17.52 15.97" xmlns="http://www.w3.org/2000/svg"><path d="M16.7,7.27a.81.81,0,0,1-.9.7c-.1,0-.2,0-.2-.1l-4.9-1.8c-.5-.2-.6-.6-.1-.8l6.2-3.6c.5-.3.8-.1.7.5l-.8,5.1Z"/><path d="M8.1,13.77a5.92,5.92,0,0,1-2.9-.7A5.77,5.77,0,0,1,2,7.87a6.21,6.21,0,0,1,6.3-6A6.15,6.15,0,0,1,13.9,6l.1-.1L16.1,7A8.1,8.1,0,0,0,7,.07,8.24,8.24,0,0,0,0,8a8.06,8.06,0,0,0,4.3,7,10.21,10.21,0,0,0,3.8,1,8.24,8.24,0,0,0,6.6-3.3l-1.8-.9a7,7,0,0,1-4.8,2Z"/></symbol>
|
||||
<symbol id="icon-overlay-play" viewBox="0 0 80 80" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#333" stroke="#fff" stroke-width="5px">
|
||||
<path d="M2.5,40A37.5,37.5,0,1,1,40,77.5,37.51,37.51,0,0,1,2.5,40Z"/>
|
||||
</g>
|
||||
<g fill="#fff">
|
||||
<path d="M60.3,38a1,1,0,0,1,.6,1.4.9.9,0,0,1-.6.6L30,57.5c-1,.6-1.7.1-1.7-1v-35c0-1.1.8-1.5,1.7-1Z"/>
|
||||
</g>
|
||||
</symbol>
|
||||
<symbol id="icon-loading-spinner" viewBox="0 0 75.8 77.9" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#fff">
|
||||
<circle cx="38.8" cy="8.1" r="8.1"/>
|
||||
<g opacity="0.4">
|
||||
<circle cx="70.8" cy="40" r="5"/>
|
||||
</g>
|
||||
<g opacity="0.6">
|
||||
<circle cx="38.8" cy="71.9" r="6"/>
|
||||
</g>
|
||||
<g opacity="0.8">
|
||||
<circle cx="7" cy="40" r="7"/>
|
||||
</g>
|
||||
<g opacity="0.9">
|
||||
<circle cx="15.1" cy="17.3" r="7.5"/>
|
||||
</g>
|
||||
<g opacity="0.3">
|
||||
<circle cx="63.2" cy="17.1" r="4.5"/>
|
||||
</g>
|
||||
<g opacity="0.5">
|
||||
<circle cx="62.7" cy="63.8" r="5.5"/>
|
||||
</g>
|
||||
<g opacity="0.7">
|
||||
<circle cx="15.1" cy="63.8" r="6.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
Reference in New Issue
Block a user