fully containerized, but should still be adaptable to non-container use

This commit is contained in:
2021-10-17 16:48:09 -07:00
parent 2a8711ea15
commit 93660fa379
5 changed files with 78 additions and 15 deletions

10
Dockerfile Normal file
View File

@@ -0,0 +1,10 @@
FROM php:fpm
RUN apt-get update && apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/*
COPY record.sh cleanup.sh /usr/bin/
COPY *.php /var/www/html/
ENV BASEURL "$BASEURL"
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)
VOLUME /var/www/html/

55
README.md Normal file
View File

@@ -0,0 +1,55 @@
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.
Standalone Instructions
-----------------------
You'll need a webserver with PHP support, as well as curl and ffmpeg, which are used by the recording script. Unpack to an empty directory, and make sure the server is set to run index.php as an index file.
record.sh gets called (most likely as a cronjob) to capture and save audio. It needs to be called with the CHANNELS and BITRATE environment variables defined as described below.
cleanup.sh should be set up to run daily.
rss.php depends on the BASEURL environment variable:
```$baseurl=getenv("BASEURL");```
I don't know where offhand you'd set environment variables for a PHP script that's run by a webserver, so you might find it easier to hardcode your server's address here:
```$baseurl="https://streams.alfter.us/";```
Docker Instructions
-------------------
This container builds on the php:fpm container to include tools and scripts for capturing streaming audio, transcoding it to AAC, and storing it as a set of HTTP live streams and a podcast.
Three environment variables are exposed to configure StreamShifter:
* BASEURL: base URL under which the site will be served (required)
* CHANNELS: number of audio channels to encode (default 1)
* BITRATE: encoding bitrate, kbps (default: 32)
The recordings and scripts to be served are stored in a named volume. Configure your webserver to serve it under a vhost by whatever means you would configure it to serve php:fpm.
Start the PHP FPM server with something like this:
```docker run -d --name streamshifter -e BASEURL=https://streamshifter.alfter.us/ -v streamshifter-data:/var/www/html salfter/streamshifter```
It runs on port 9000. You should set your webserver container to hand off PHP requests to it.
To schedule recordings, use the record.sh script in a running container (use ```docker exec```) with four parameters, all required:
* duration, seconds
* short name for the stream (no spaces, used as part of filenames)
* stream URL
* long name for the stream (may have spaces, written into stream metadata)
Use whatever task scheduler your system provides (crontab, systemd timer unit, etc.) to run the script at the appropriate time. This example saves 10 seconds of the stream from KDWN, a talk-radio station in Las Vegas (streaming URL subject to change at their whim):
```docker exec -it streamshifter record.sh 10 test "https://14983.live.streamtheworld.com/KDWNAMAAC.aac?tdsdk=js-2.9&pname=TDSdk&pversion=2.9&banners=320x50&sbmid=ddc0cb91-c9a7-46c4-bf53-85841c22c8e4" Test```
There is also a cleanup script you can run periodically that will remove everything more than one week old:
```docker exec -it streamshifter cleanup.sh```

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env bash
source /etc/profile
#PATH=$PATH:/usr/local/bin
find /var/www/streamshifter/htdocs/audio -name \*.m4a -type f -mtime +7 -delete
find /var/www/html/audio -name \*.m4a -type f -mtime +7 -delete

View File

@@ -1,12 +1,12 @@
#!/usr/bin/env bash
source /etc/profile
#PATH=$PATH:/usr/local/bin
cd /var/www/streamshifter/htdocs
mkdir -p /var/www/html/audio
cd /var/www/html
find . -name $2-\*.ts -delete
find . -name $2\*.m3u8 -delete
#transopt="aac -ac 1 -ab 32k -ar 22050" # AAC-LC
transopt="libfdk_aac -profile:a aac_he_v2 -ac 2 -ab 32k -ar 22050" # HE-AAC v2
transopt="aac -ac ${CHANNELS} -ab ${BITRATE}k -ar 22050" # AAC-LC
#transopt="libfdk_aac -profile:a aac_he_v2 -ac ${CHANNELS} -ab ${BITRATE}k -ar 22050" # HE-AAC v2 (requires Gentoo, or a source build)
curl -sm $1 "$3" 2>/dev/null | ffmpeg -i - -acodec $transopt -metadata title="$4 - `date +'%d %b %Y'`" -metadata artist="$4" -f segment -segment_list $2.m3u8 -segment_time 20 $2-%04d.ts 2>/dev/null
ffmpeg -i $2.m3u8 -acodec copy -movflags +faststart -metadata title="$4 - `date +'%d %b %Y'`" -metadata artist="$4" audio/$2-`date +%Y%m%d`.m4a 2>/dev/null

16
rss.php
View File

@@ -2,7 +2,7 @@
require_once('./getid3/getid3/getid3.php');
$getid3=new getID3;
$baseurl="https://streamshifter.alfter.us/";
$baseurl=getenv("BASEURL");
$doc = new DOMDocument("1.0", "UTF-8");
$root = $doc->createElement("rss");
@@ -15,12 +15,12 @@
$latest=0;
$c=0; // sort entries into reverse chronological order
if ($h=opendir("audio"))
if ($h=opendir("/var/www/html/audio"))
{
while (($e=readdir($h))!==false)
if (strlen($e)>4)
if (substr_compare($e,".m4a",-4,4)===0)
$arr[$c++]=filemtime("audio/".$e)." ".$e;
$arr[$c++]=filemtime("/var/www/html/audio/".$e)." ".$e;
closedir($h);
}
sort($arr, SORT_NUMERIC);
@@ -32,7 +32,7 @@
$item=$doc->createElement("item");
// extract title from metadata
$fi=$getid3->analyze("audio/".$e);
$fi=$getid3->analyze("/var/www/html/audio/".$e);
getid3_lib::CopyTagsToComments($fi);
$item->appendChild($doc->createElement("title",$fi["comments_html"]["title"][0]));
$item->appendChild($doc->createElement("author",$fi["comments_html"]["artist"][0]));
@@ -45,16 +45,16 @@
$enclURL->value=$baseurl."audio/".$e;
$encl->appendChild($enclURL);
$enclLength=$doc->createAttribute("length");
$enclLength->value=filesize($e);
$enclLength->value=filesize("/var/www/html/audio/".$e);
$encl->appendChild($enclLength);
$enclType=$doc->createAttribute("type");
$enclType->value="audio/mp4a-latm";
$encl->appendChild($enclType);
$item->appendChild($encl);
$item->appendChild($doc->createElement("pubDate",gmdate(DATE_RSS,date(filemtime("audio/".$e)))));
$item->appendChild($doc->createElement("pubDate",gmdate(DATE_RSS,date(filemtime("/var/www/html/audio/".$e)))));
$channel->appendChild($item);
if ($latest<filemtime("audio/".$e))
$latest=filemtime("audio/".$e);
if ($latest<filemtime("/var/www/html/audio/".$e))
$latest=filemtime("/var/www/html/audio/".$e);
}
$channel->appendChild($doc->createElement("lastBuildDate",gmdate(DATE_RSS,date($latest))));