chriswere.wales

Plok

Plok is a simple Bash script for generating a podcast website and RSS feed from a directory of MP3 files.

You can download the code here.

It reads podcast information from site.conf, extracts episode metadata from MP3 files using ffprobe, generates an index.html page, and creates a podcast-compatible rss.xml feed.

Requirements

Plok requires:

On Debian, the main external dependency can be installed with:

sudo apt install ffmpeg

Directory structure

A basic Plok project looks like this:

.
├── plok
├── site.conf
├── media/
│   ├── 20260801-first-episode.mp3
│   ├── 20260808-second-episode.mp3
│   └── 20260815-third-episode.mp3
├── head.html        # optional
├── foot.html        # optional
├── style.css        # optional
└── avatar.png       # used by the RSS feed

Running:

./plok

generates:

index.html
rss.xml

The generated files replace any existing index.html and rss.xml.

MP3 filenames

MP3 filenames must begin with an eight-digit date in YYYYMMDD format.

For example:

20260801-first-episode.mp3
20260808-second-episode.mp3
20260901-third-episode.mp3

The first eight characters are used to determine the episode date.

The date is used for:

The remainder of the filename does not determine the episode title. The title is read from the MP3 TITLE metadata tag.

If the MP3 does not contain a TITLE tag, the episode is displayed as:

Untitled

The DESCRIPTION metadata tag is used as the episode synopsis.

MP3 metadata

Plok reads the following metadata from each MP3:

Metadata Used for
TITLE Episode title
DESCRIPTION Episode synopsis

For example, using ffmpeg:

ffmpeg -i input.mp3 
    -metadata title="My Episode" 
    -metadata description="This is the episode description." 
    -c copy output.mp3

site.conf

The site.conf file contains the podcast configuration.

Settings use the following format:

key: value

Whitespace around the key and value is removed.

Required settings

title

The podcast title.

title: My Podcast

author

The podcast author.

author: Chris

url

The base URL of the podcast website.

url: https://example.com

The trailing / is automatically removed if present.

Optional settings

description

The podcast description.

description: A podcast about interesting things.

email

The podcast contact email address.

email: chris@example.com

language

The podcast language.

Default:

language: en-GB

category

The podcast category.

Default:

category: Society & Culture

explicit

Whether the podcast contains explicit content.

Default:

explicit: false

date_format

The format used for dates displayed on the HTML page.

Default:

date_format: %d %b %Y

This produces dates such as:

08 Aug 2026

The format follows the GNU date format.

recursive

Controls whether Plok searches subdirectories inside media/.

Default:

recursive: false

With:

recursive: true

Plok searches recursively.

order

Controls the order of episodes on the generated page and RSS feed.

Default:

order: reverse

This puts newer episodes first.

To put older episodes first:

order: forward

HTML templates

Plok has two built-in HTML templates:

The template is selected using the template setting in site.conf.

head.html

If head.html exists, its contents are inserted into the generated HTML immediately after the opening <body> tag.

This can be used for things such as:

foot.html

If foot.html exists, its contents are added after all episode entries and before the closing </body> and </html> tags.

This can be used for:

style.css

If style.css exists, Plok automatically adds:

<link rel="stylesheet" href="style.css">

to the generated HTML <head>.

This allows the generated page and its templates to be styled without modifying Plok.

RSS feed

Plok generates a podcast RSS 2.0 feed containing:

The generated feed is:

rss.xml

The podcast artwork is expected at:

avatar.png

and is referenced using:

https://example.com/avatar.png

The RSS feed URL is:

https://example.com/rss.xml

Example site.conf

A complete configuration might look like:

title: My Podcast
description: A podcast about interesting things.
author: Chris
email: chris@example.com
language: en-GB
category: Society & Culture
explicit: false
date_format: %d %b %Y
recursive: false
order: reverse
url: https://example.com
template: compact

The minimum configuration is:

title: My Podcast
author: Chris
url: https://example.com

All other settings have defaults.

Running Plok

Make the script executable:

chmod +x plok

Then run:

./plok

Plok will report each MP3 as it processes it:

Processing: 20260808-second-episode.mp3
Processing: 20260801-first-episode.mp3
Done

The resulting files are:

index.html
rss.xml

Generated HTML safety

Episode titles are HTML-escaped before being inserted into the generated page.

Episode descriptions are also HTML-escaped before being converted into links and line breaks.

This prevents characters such as:

&
<
>

from being interpreted as HTML.

URLs found in episode descriptions beginning with http:// or https:// are automatically converted into HTML links.

Temporary files

Plok generates temporary files using mktemp while creating the HTML and RSS files.

A shell trap removes these temporary files when the script exits.

The completed temporary files are moved into place only after generation has finished.