User:Riviera/Podcasts continued
The other week I started writing a shell script to generate podcasts in an RSS format. I first outlined the connection between podcasts and rss feeds following a discussion we had in class. Then I wrote about how I utilised grep, cat and sed. I combined these commands in a shell script. The aim was to write a file containing the tag-structure of an XML document whilst removing content. This outline structure became the basis of the podcast generator script, skeleton. Along the way I analysed and improved the first version of the script. I am summarising what I did the other week here because the commentary on the code is somewhat inaccurate. I utilised a less than consistent document production workflow to write the wiki page. However, I have since decided upon a more consistent way of writing wiki pages (using https://pandoc.org) and so pages will be better maintained starting from now.
What I worked on was quite relevant to our discussion of regular expressions on Monday 9th. It could furthermore bear relevance to CSS and paged media if an HTML page was made for the channel. I envision a publication made with weasyprint, perhaps using the technique of imposition. Each page might contain a link to a radio broadcast from the past, along with some text.
Draft three of script
#!/usr/bin/fish
function skelegen -d "Generate an RSS channel for a podcast"
set -l options (fish_opt -s h -l help);
set options $options (fish_opt --short=v --long=verbose);
set options $options (fish_opt --short=A --long=auto);
set options $options (fish_opt --short=g --long=generate --required-val);
set options $options (fish_opt --short=a --long=add --required-val --multiple-vals);
set options $options (fish_opt --short=c --long=channel --required-val);
argparse $options -- $argv;
or return
if set -ql _flag_help
echo "skelegen [ -h ] [ -vA ] [ -g DIR | -a FILE ] -c XML_FILE
-h --help Display this text
-v --verbose Output information about processes
-A --auto Automatically insert titles and descriptions
-g --generate DIR Generate an RSS feed for DIR
-a --add FILE Add an item to a channel
-c --channel XML_FILE Create output channel
Skelegen is a command line application for generating and writing RSS feeds for podcasts. Skelegen is capable of generating an RSS feed for a directory of audio recordings. It is also possible to add audio recordings to a channel. Titles and descriptions can be added automatically.
EXAMPLE USAGE
skelegen --generate ~/Music/podcast --channel ~/public_html/podcasts/mypodcast.xml
skelegen --add ~/Music/podcast/episode.mp3 --channel ~/public_html/podcasts/myotherpodcast.xml"
end
if set -ql _flag_generate and set -ql _flag_add;
echo 'ERROR: skelegen cannot add and generate simultaneously';
return 1;
end
if not set -ql _flag_channel;
echo "ERROR: channel must be specified.";
return 1;
end
if set -ql _flag_channel;
if set -ql _flag_verbose
echo 'Touching ~/.skeleton/channellist'
end
mkdir -p ~/.skeleton;
touch ~/.skeleton/channellist;
if set -ql _flag_verbose
echo 'Setting local variables'
end
set -g channelprefix (echo $_flag_channel | sed -E 's/\\/([^\\/]*.xml)/\\/\n\1/' | grep -Ev "[^/]*.xml");
set -g publicprefix (echo $channelprefix | sed -E 's/\\/home\\/'$USER'\\/public_html\\/([^\\/]+\\/)/https:\\/\\/hub.xpub.nl\\/chopchop\\/~'$USER'\\/\1/');
set -g channelfile (echo $_flag_channel | sed -E 's/\\/([^\\/]*.xml)/\\/\n\1/' | grep -Eo "[^/]*.xml");
if grep -Eoq '[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}/'$channelfile ~/.skeleton/channellist;
set -g showid (grep -Eo '[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}/'$channelfile ~/.skeleton/channellist | uniq -d | sed -E 's/([[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12})\\/('$channelfile')/\1\n\2/' | grep -Eo "[[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}");
else;
set showid (uuidgen)
end
set -g channel {$channelprefix}{$showid}/{$channelfile};
if set -ql _flag_verbose
echo ' '
echo 'Local Variables'
echo '---------------'
echo 'Showid: '$showid;
echo 'Channel: '$channel;
echo 'Channel file: '$channelfile;
echo 'Public prefix: '$publicprefix;
echo 'Channel prefix: '$channelprefix;
echo ' '
echo 'Making parent directory: ' {$channelprefix}{$showid};
end
mkdir -p {$channelprefix}{$showid};
if not cat $_flag_channel > /dev/null;
if set -ql _flag_verbose
echo 'Writing channel data'
end
touch $channel;
echo '<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">' >> $channel;
echo '<channel>' >> $channel;
echo '<ttl>60</ttl>' >> $channel;
echo '<generator>skeleton</generator>' >> $channel;
if set -ql _flag_auto
echo '<title>'My Podcast'</title>' >> $channel;
else;
if set -ql _flag_verbose
echo 'What is the title of your podcast?'
end
read -l channelname -P "Channel Title: ";
echo '<title>'$channelname'</title>' >> $channel;
end
echo '<link>https://hub.xpub.nl/chopchop/worm/</link>' >> $channel;
echo '<atom:link href="'$publicprefix$showid'" ref="self" type="application/rss+xml"/>' >> $channel;
echo '<language>en</language>' >> $channel;
if set -ql _flag_auto
echo '<description><![CDATA['Chanel Description']]></description>' >> $channel;
else;
if set -ql _flag_verbose
echo 'Provide a description for your podcast'
end
read -l channeldesc -P "Channel Description: ";
echo '<description><![CDATA['$channeldesc']]></description>' >> $channel;
end
if set -ql _flag_verbose
echo 'Adding image to channel'
end
echo '<image><url>'{$publicprefix}{$showid}'/image.jpg</url>' >> $channel;
echo '<link>https://hub.xpub.nl/chopchop/worm/</link>' >> $channel;
echo '<title>'$channelname'</title>' >> $channel;
echo '</image>' >> $channel;
# end
echo '</channel>' >> $channel;
echo '</rss>' >> $channel;
if set -ql _flag_verbose
echo 'Indexing channel in ~/.skeleton/channellist'
end
echo $channel >> ~/.skeleton/channellist;
end
mv $channel $_flag_channel
if set -ql _flag_verbose
echo 'Generated channel '$_flag_channel
end
end
if set -ql _flag_generate
head -n 13 $_flag_channel > {$channelprefix}tmpchannel;
# end
if set -ql _flag_verbose
echo 'Writing item data ...'
echo ' '
end
for file in (ls $_flag_generate);
if set -ql _flag_verbose
echo 'Setting incremental counter'
end
set i (math $i + 1);
if set -ql _flag_verbose
echo 'Setting guid'
end
set -l guid (sha256sum {$_flag_generate}/{$file} | grep -Eo "[[:alnum:]]{64}");
if set -ql _flag_verbose
echo 'Making directory: ' {$channelprefix}{$showid}/e/{$guid};
end
mkdir -p {$channelprefix}{$showid}/e/{$guid};
if set -ql _flag_verbose
echo 'Creating link to ' $file
end
ln -s {$_flag_generate}/{$file} {$channelprefix}{$showid}/e/{$guid}/{$file};
set itemfile (printf '%s%s/e/%s/item-%i' $channelprefix $showid $guid $i);
echo "<item>" > $itemfile;
if set -ql _flag_auto
echo "<title>"$file"</title>" >> $itemfile;
else;
read -l title -P "Item $i Title: ";
echo "<title>"$title"</title>" >> $itemfile;
end
echo "<pubDate>"(date)"</pubDate>" >> $itemfile;
echo '<enclosure url="'$publicprefix$showid'/e/'$guid'/'$file'" length="'(soxi -D {$_flag_generate}/{$file})'" type="'(file -b --mime-type {$_flag_generate}/{$file})'"/>' >> $itemfile;
sed -i 's/\\/\\/[^.]*\(\\/[^\\/]*.mp3\)/\1/' $itemfile;
echo '<guid isPermaLink="false">'$guid'</guid>' >> $itemfile;
set -l link "https://hub.xpub.nl/chopchop/~river/podcasts/$showid/e/$guid/$file";
echo '<link>'$link'</link>' >> $itemfile;
if set -ql _flag_auto
echo '<description><![CDATA['No description']]></description>' >> $itemfile;
else;
read -l desc -P "Item $i Description: ";
echo '<description><![CDATA['$desc']]></description>' >> $itemfile;
end
echo '</item>' >> $itemfile;
end
# concatenate items in reverse order and append to the channel file
if set -ql _flag_verbose
echo 'Writing item data ... done'
echo 'Generating channel ...'
end
for item in (ls -t {$channelprefix}*/e/*/item-*);
cat $item >> {$channelprefix}tmpchannel;
end
# close the rss and channel tags
tail -n 2 $_flag_channel >> {$channelprefix}tmpchannel;
cat {$channelprefix}tmpchannel > $_flag_channel
rm {$channelprefix}tmpchannel
if set -ql _flag_verbose
echo 'Generating channel ... done'
end
end
if set -ql _flag_add
if set -ql _flag_verbose
echo 'Setting local variables'
end
set -g guid (sha256sum $_flag_add | grep -Eo "[[:alnum:]]{64}");
set -g channelprefix (echo $_flag_channel | sed -E 's/\\/([^\\/]*.xml)/\\/\n\1/' | grep -Ev "[^/]*.xml");
set -g addfile (readlink -f $_flag_add | grep -Eo "[^/]*.mp3");
set -g addprefix (echo $_flag_add | sed -E 's/\\/([^\\/]*.mp3)/\\/\n\1/' | grep -Ev "[^/]*.mp3");
set -g itemprefix (printf '%s%s/e/%s' $channelprefix $showid $guid );
set -g itemfile (printf '%s%s/e/%s/item' $channelprefix $showid $guid);
if set -ql _flag_verbose
echo 'Indexing channel in ~/.skeleton/channellist'
end
touch ~/.skeleton/channellist
echo {$channelprefix}{$showid}/{$channelfile} >> ~/.skeleton/channellist
if set -ql _flag_verbose
echo ' '
echo 'Local Variables'
echo '---------------'
echo 'Guid: '$guid;
echo 'Showid: '$showid;
echo 'Channel: '$channel;
echo 'Item file: '$itemfile;
echo 'Add prefix: '$addprefix;
echo 'File to add: '$addfile;
echo 'Item prefix: '$itemprefix;
echo 'Channel file: '$channelfile;
echo 'Public prefix: '$publicprefix;
echo 'Channel prefix: '$channelprefix;
echo ' '
echo 'Making directory' $itemprefix
end
mkdir -p $itemprefix
if set -ql _flag_verbose
echo 'Touching' $itemfile
end
touch $itemfile
if set -ql _flag_verbose
echo 'Writing item data'
end
echo "<item>" > $itemfile;
if set -ql _flag_auto
echo "<title>"No Title"</title>" >> $itemfile;
else;
read -l title -P "Title: "
echo "<title>"$title"</title>" >> $itemfile;
end
echo "<pubDate>"(date)"</pubDate>" >> $itemfile;
echo "Enclosing url"
# set foo (readlink -f $addfile | soxi -D)
echo '<enclosure url="https://hub.xpub.nl/chopchop/~'$USER'/podcasts/'$showid'/e/'$guid'/'$addfile'" length="'(soxi -D {$addprefix}{$addfile})'" type="'(file -b --mime-type {$addprefix}{$addfile})'"/>' >> $itemfile;
sed -i 's/\\/\\/[^.]*\(\\/[^\\/]*\\.mp3\)/\1/' $itemfile;
echo '<guid isPermaLink="false">'$guid'</guid>' >> $itemfile;
set -l link "https://hub.xpub.nl/chopchop/~"$USER"/podcasts/$showid/e/$guid/$addfile";
echo '<link>'$link'</link>' >> $itemfile;
if set -ql _flag_auto
echo '<description><![CDATA['No description']]></description>' >> $itemfile;
else;
read -l desc -P "Description: ";
echo '<description><![CDATA['$desc']]></description>' >> $itemfile;
end
echo '</item>' >> $itemfile;
touch {$channelprefix}{$channelfile};
if set -ql _flag_verbose
echo 'Adding item to channel';
end
head -n 13 $_flag_channel >> {$channelprefix}tmpchannel;
cat $itemfile >> {$channelprefix}tmpchannel;
tail -n +14 $_flag_channel >> {$channelprefix}tmpchannel;
mv {$channelprefix}tmpchannel $_flag_channel
if set -ql _flag_verbose
echo 'Creating link to '$addfile
end
ln -s $_flag_add {$channelprefix}{$showid}/e/{$guid}/{$addfile};
# ln (readlink -f $_flag_channel)
end
end
Discussion of draft three
The script now features several additional flags. The "verbose" flag sends to stdout descriptive information about what the script is doing whilst it does it. This information is useful for debugging. It is also a more convenient means of documenting the software than writing about it. The "add" flag allows the user to add an mp3 file to a podcast. If the podcast does not exist, skelegen creates the channel. If the channel exists, skelegen adds the item to the channel. This is a flexible way of creating podcasts. Lastly, the "auto" flag automatically inserts a title and description for the item(s) / channel.
skelegen --generate /media/worm/radio/ --channel ~/public_html/podcast.xml
I turned the script into a zine using free and open source software. In particular I used Emacs, pandoc, ConTeXt and pdfcpu.
Cron and Skelegen
0 14 * * 7 skelegen --auto --add (random choice (tree -if /media/worm/radio/ | grep -Eo "(/[^/]+)+.mp3")) --channel /home/$USER/public_html/random-podcast.xml
The above line of code is an example of how the shell script can be used to generate a podcast. Here I have combined the script with cron, an automatic task scheduler. The above line of code goes in a crontab file. It calls skelegen at 1400 every Sunday. The cronjob adds a random .mp3 file from Worm's radio archive to a podcast channel called 'random-podcast'. The "auto" flag ensures the script runs to completion. The podcast was inspired by worm's 'random-radio' which plays when nobody is broadcasting live.