Podcast first episode real test - run: 2026-10-25 11:08 UTC
host: Linux 6.8.0-139-generic x86_64
ffmpeg: ffmpeg version 6.1.1-3ubuntu5 Copyright (c) 2000-2023 the FFmpeg developers
=== 1. the narration we recorded for the episode ===
$ ffprobe -v error -show_entries format=duration,size -show_entries stream=codec_name,sample_rate,channels -of default=noprint_wrappers=1 '/home/ubuntu/rt/pod/episode.wav'
codec_name=pcm_s16le
sample_rate=24000
channels=1
duration=22.869333
size=1097772
exit=0
=== 2. encode the episode the way Apple recommends for RSS (MP3 stereo, 44.1 kHz, 128 kbps) ===
$ ffmpeg -v error -i '/home/ubuntu/rt/pod/episode.wav' -c:a libmp3lame -b:a 128k -ar 44100 -ac 2 episode.mp3 -y
exit=0
$ ffprobe -v error -show_entries format=duration,size,bit_rate -show_entries stream=codec_name,sample_rate,channels,bit_rate -of default=noprint_wrappers=1 episode.mp3
codec_name=mp3
sample_rate=44100
channels=2
bit_rate=128000
duration=22.909388
size=367012
bit_rate=128161
exit=0
=== 3. how loud is it? (our own measurement) ===
$ ffmpeg -v error -i episode.mp3 -af ebur128=peak=true -f null -
exit=0
--- ebur128 summary ---
=== 3b. normalise the episode to -16 LUFS (our chosen target) and measure the difference ===
$ ffmpeg -v error -i episode.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11 -c:a libmp3lame -b:a 128k -ar 44100 -ac 2 episode-normalised.mp3 -y
exit=0
$ ffmpeg -v error -i episode-normalised.mp3 -af ebur128=peak=true -f null -
exit=0
--- ebur128 summary of the normalised file ---
$ ffmpeg -v info -i episode-normalised.mp3 -af ebur128=peak=true -f null - 2>&1 | grep -A10 Summary
[Parsed_ebur128_0 @ 0x591e25415e00] Summary:
Integrated loudness:
I: -16.0 LUFS
Threshold: -27.3 LUFS
Loudness range:
LRA: 3.9 LU
Threshold: -37.6 LUFS
LRA low: -19.7 LUFS
LRA high: -15.8 LUFS
exit=0
=== 4. the RSS feed we ship ===
enclosure length set to the real file size: 367012 bytes
Plot Nine
https://example.com/plotnine
A fortnightly show from a city allotment: compost, slugs and what we are not doing this season.en-gbPlot NinefalsePlot Ninehello@example.comEpisode 1: The heap in JanuaryWhat actually happens to a compost heap in January, why the slugs win every year, and one thing we are not doing this season.Sun, 25 Oct 2026 09:00:00 +0000plotnine-e00100:00:231
=== 5. check the feed against Apple's published requirements ===
$ python3 /home/ubuntu/rt/pod/check_feed.py feed.xml episode.mp3
PASS the feed is well formed XML
PASS the root element is rss version 2.0
PASS the itunes namespace is declared
PASS the feed has a channel
PASS the channel has a
PASS the channel has a
PASS the channel has a
PASS the channel has a
PASS the channel has
PASS the channel has
PASS the channel has artwork ()
PASS the channel has
PASS the feed has at least one episode - 1 item(s)
PASS the episode has a
PASS the episode has a
PASS the episode has a
PASS the episode has a
PASS the episode has an
PASS the enclosure has a url
PASS the enclosure has a length
PASS the enclosure has a type
PASS the enclosure url is ASCII with only a-z, A-Z, 0-9 and / . - _ - https://example.com/plotnine/episode-001.mp3
PASS the pubDate follows RFC 2822 with a time zone offset - Sun, 25 Oct 2026 09:00:00 +0000
PASS every episode GUID is unique
PASS every episode enclosure URL is unique
PASS the feed avoids HTML entities such as ’ or “
PASS the episode file is MP3 - mp3
PASS the episode file is stereo - 2
PASS the episode sample rate is 44.1 kHz - 44100
PASS the episode bit rate is in Apple's recommended 128-256 kbps range for stereo MP3 - 128 kbps
PASS the enclosure length matches the audio file size - feed says 367012, file is 367012
RESULT: 31 checks passed, 0 failed
exit=0
=== 6. what we ship ===
-rw-rw-r-- 1 ubuntu ubuntu 367012 Oct 25 11:08 episode.mp3
-rw-rw-r-- 1 ubuntu ubuntu 1269 Oct 25 11:08 feed.xml
=== done ===
=== 7. transcribe the episode with the live tool and compare it word by word ===
$ node scenario-transcript2.cjs episode.mp3 script.txt
page: https://koldflux.com/tools/podcast/transcript
language select: English model select: Accurate (Whisper base, 80 MB download)
run: 2026-10-25, headless Chromium via Playwright
the run that produced the transcript took 14 s and reported no page errors.
three earlier runs of the same scenario on the same day each took about 500 s and did
not leave a readable transcript box, so we did not measure where that time went.
--- the transcript the tool wrote, as it downloaded it (time codes included) ---
[00:00:00] Welcome to Plot 9, a fortnightly show from a city allotment.
[00:00:05] Today, what actually happens to a compost heap in January, why the slugs seem to win every
[00:00:14] single year, and one thing we are definitely not doing this season.
[00:00:22] Bring a mug.
--- word by word against the script we recorded ---
method: lower case, strip punctuation, drop the time codes, split on spaces,
then a plain Levenshtein distance over the word lists
reference words: 43
transcript words: 43
edit distance: 1
word error rate: 2.3%
errors: 1
sub nine -> 9
The only mistake was the show name: the tool wrote "Plot 9" for "Plot Nine".
Everything else came back word for word, including the clause "why the slugs seem to
win every single year".
The tool page reports 4.8% of words wrong over 48 minutes of read English. Our 2.3%
comes from 43 words of synthetic speech, so the two numbers are not comparable: a
longer recording has more chances to go wrong.
=== done, transcript comparison added ===