User:Riviera/Podcasts continued

From XPUB & Lens-Based wiki

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.