afcast turns a podcast RSS feed into a VLC,cliamp, etc. -compatible
M3U playlist. Point it at a feed (or, with -discover, at a show's landing page) and it
writes one #EXTINF entry per episode whose path is the enclosure URL, so episodes stream
rather than download.
go install github.com/polera/af/cmd/afcast@latestOr build from a checkout:
make build # produces ./afcastafcast [flags] <feed-url-or-file>
The source may be an http(s) URL, a path to a local RSS file, or - to read from standard
input. The playlist goes to stdout unless -o names a file; a one-line summary is written to
stderr so it stays out of a piped playlist.
| Flag | Default | Description |
|---|---|---|
-o file |
stdout | Write the playlist to file |
-limit n |
0 |
Maximum number of episodes (0 = all) |
-order mode |
oldest |
Episode order: oldest, newest, or feed |
-timeout d |
30s |
HTTP timeout for fetching the feed |
-discover |
off | Treat the URL as a podcast landing page and find its feed |
-quiet |
off | Suppress the stderr summary |
-version |
Print version and exit |
Ordering sorts by publication date; episodes with no date sort last in both directions, and
feed keeps the feed's own sequence. -limit is applied after sorting.
# Write the whole feed to a playlist file
afcast -o show.m3u https://example.com/feed.xml
# The 10 most recent episodes, newest first
afcast -limit 10 -order newest -o recent.m3u https://example.com/feed.xml
# Build a playlist from a show's landing page, no feed URL needed
afcast -discover -o show.m3u https://www.kexp.org/podcasts/cobain50/
# Keep the feed's own ordering, then play it
afcast -order feed -o show.m3u https://example.com/feed.xml && cliamp show.m3u
# Pipe straight into cliamp
afcast https://example.com/feed.xml > /tmp/show.m3u| Code | Meaning |
|---|---|
0 |
Playlist written |
1 |
Error (bad flags, fetch failure, unparseable feed) |
2 |
Feed parsed but contains no playable episodes |
-discover resolves a landing page to its feed in three steps, most reliable first:
- A
<link rel="alternate" type="application/rss+xml">tag on the page. - An Apple Podcasts link on the page, resolved through the public iTunes Lookup API. Hosts like Omny and Megaphone build feed URLs from internal GUIDs that appear nowhere in the page, so this is often the only route that works.
- A bare feed-shaped URL in the page source.
If the URL already serves a feed, it is returned unchanged. The resolved feed URL is reported on stderr before use, since discovery can land on a different show than the page advertised.
The podcast package is usable on its own:
f, err := podcast.FetchURL(ctx, "https://example.com/feed.xml")
if err != nil {
return err
}
err = podcast.WriteFileM3U("show.m3u", f, podcast.Options{
Limit: 10,
Order: podcast.OrderNewestFirst,
})It parses RSS 2.0 plus the iTunes extensions, tolerates the mislabeled character encodings and irregular date formats common in real feeds, skips items with no audio enclosure, and deduplicates on GUID.
make test # go test ./...
make checks # staticcheck, osv-scanner, gosec
make licenses # regenerate THIRD_PARTY_LICENSES.txtRequires Go 1.26.1 or later. The module has no third-party dependencies.
MIT. See LICENSE.