PodcastFeedMaker

Published on Β· Updated Β· 12 min

Wlad
Wlad
Founder & Swift Tech Lead

The Story

It all started with a simple need: generate clean, standards-compliant podcast RSS feeds without hacking XML by hand.

Between 2006 and 2012, I was producing electronic music podcasts. Back then, I managed everything with a homemade PHP backoffice β€” a DIY setup that worked, but required tremendous effort to stay compatible with iTunes, aggregators, and validators.

Years later, while working on audio projects, the need came back. But this time, I wanted to do things right: a modern, typed, tested Swift library that respects all current standards β€” Apple Podcasts, Podcast Namespace, PSP-1.

It was while developing this library that the idea for Podcast Maker was born. The library first, the app second.

What is PodcastFeedMaker?

PodcastFeedMaker is a Swift library for generating, parsing, and validating podcast RSS feeds. Not a wrapper, not a template generator β€” a real, complete modeling of the RSS format with all its namespaces.

The key feature? It's bidirectional. You can build a feed from scratch with Swift models, generate XML, but also parse existing XML and get it back as typed models. Full round-trip, no data loss.

It covers the 7 XML namespaces found in the podcast world: RSS 2.0, iTunes, Podcast Namespace 2.0 (with all 32 tags), Atom, Dublin Core, Content Module, and Podlove Simple Chapters. For validation, five major platforms are supported: Apple Podcasts, Spotify, Amazon Music, Podcast Index, and the PSP-1 standard.

All of this with zero external dependencies in the core library β€” pure Swift with Foundation, Linux-compatible from day one.

What It Can Do

  • Generate β€” Clean XML, synchronous or streaming mode for large catalogs. Configurable formatting, automatic CDATA wrapping, 4 namespace handling modes

  • Parse β€” Complete reading with diagnostics and error recovery. Supports 12 different date formats (RFC 2822, ISO 8601, and the "quirky" formats found in the wild)

  • Validate β€” Check against 5 platforms with three levels: errors, warnings, infos. Know exactly what's blocking before you submit

  • Round-trip β€” Parse an existing feed, modify it, regenerate it. Unknown elements, CDATA sections, XML comments, namespace prefixes β€” all preserved

  • Builder DSL β€” Declarative syntax with result builders. 18 channel modifiers, 14 item modifiers, enclosure factories

  • Templates β€” 4 levels depending on your needs: basic for quick starts, standard for production, advanced for transcripts and chapters, expert for full coverage

  • Chapters β€” JSON Chapters (the Podcast NS 2.0 format) and Podlove Simple Chapters, both Codable

  • Feed Diff β€” Compare two feed versions and see what changed: added, removed, modified episodes

  • CLI β€” 13 commands to do everything from the terminal

First Feed in 30 Seconds

Here's the complete workflow: build a feed, generate XML, re-parse it, and validate it.

The 7 Namespaces

The podcast RSS world is a stack of XML namespaces that have accumulated over the years. PodcastFeedMaker handles them all β€” every tag, every attribute is modeled, generated, parsed, and validated.

NamespacePrefixTags

RSS 2.0 Core

β€”

14 (channel + item)

iTunes

itunes

10

Podcast NS 2.0

podcast

32

Atom

atom

1

Dublin Core

dc

1

Content Module

content

1

Podlove Simple Chapters

psc

1

The Podcast Namespace 2.0 in Detail

The Podcast Namespace led by Podcast Index brings 32 new tags organized in phases. PodcastFeedMaker implements them all:

PhaseTags

Phase 1

locked, transcript, funding, chapters, soundbite

Phase 2

person, location, season, episode

Phase 3

trailer, license, alternateEnclosure, source, integrity

Phase 4+

guid, value, medium, liveItem, contentLink, socialInteract, block, txt, remoteItem, podroll, updateFrequency, podping, valueTimeSplit, chat, publisher, image, images, valueRecipient

Multi-Platform Validation

Every platform has its own requirements. Apple wants HTTPS everywhere and artwork between 1400 and 3000px. Spotify prefers MP3 and limits files to 200 MB. PSP-1 requires a GUID on every episode.

Instead of discovering these issues at submission time, FeedValidator checks everything upfront:

What Each Validator Checks

PlatformKey Points

Apple Podcasts

HTTPS required, artwork 1400-3000px JPEG/PNG, itunes:image + itunes:category + itunes:explicit required

Spotify

MP3 preferred, max 200 MB per file, square artwork 1400-2048px, description max 4000 characters

Amazon Music

Various audio formats accepted (MP3/M4A/FLAC/OGG/ALAC), artwork 1400-3000px

Podcast Index

Podcast NS 2.0 tags expected (podcast:locked, podcast:guid, podcast:funding), Value4Value config

PSP-1

language required, atom:link self required, podcast:locked + podcast:guid required, GUID on every item

The Builder DSL

Building a feed with PodcastFeedMaker means chaining modifiers in a fluent way. No XML to write, no magic strings β€” everything is typed.

18 modifiers are available for channels (author, categories, image, owner, funding, etc.) and 14 for items (description, duration, season, episode, persons, transcripts, soundbites, etc.).

Enclosure Factories

Three factories set the MIME type automatically β€” no need to remember if it's audio/mpeg or audio/mp3:

XML Generation

FeedGenerator produces complete XML synchronously. For massive catalogs (10,000+ episodes), StreamingFeedGenerator generates in async chunks:

Namespace Modes

Four modes for handling namespace declarations in generated XML:

ModeBehavior

.auto

Scans the feed and only declares namespaces that are actually used

.feedDefined

Declares exactly what's listed in PodcastFeed.namespaces

.explicit(Set)

You manually specify the set to declare

.parsed

Preserves original prefixes and URIs (perfect for round-trip)

Feed Parsing

The parser handles all 7 namespaces with best-effort error recovery. A malformed feed doesn't crash everything β€” you get what's readable along with diagnostics about what caused issues.

12 Supported Date Formats

In the real world, podcast feeds use... creative date formats. The parser handles 12 of them:

CategoryExamples

RFC 2822

Tue, 14 Feb 2026 10:30:00 +0100, 14 Feb 2026 10:30:00 GMT

ISO 8601

2026-02-14T10:30:00Z, 2026-02-14T10:30:00.000+01:00, 2026-02-14

Fuzzy

Feb 14, 2026, 2026/02/14, 02/14/2026, 14-02-2026

Templates

Four pre-configured templates depending on your needs. Each activates a set of tags and validations suited to the use case:

LevelWhat It IncludesFor Whom

Basic

RSS 2.0 + minimal iTunes

Prototyping, quick tests

Standard

  • PSP-1 compliance

Production, broad compatibility

Advanced

  • Podcast NS phases 1-3

Transcripts, chapters, V4V

Expert

All 7 complete namespaces

Maximum coverage

Templates are composable with the + operator and configurable via .requiring(), .recommending(), .targeting().

Lossless Round-Trip

Parse an existing feed, modify it, and regenerate β€” without losing elements you don't know about. This is crucial when working with third-party feeds that use custom extensions.

What's PreservedHow

Unknown elements

Captured as UnknownElement and re-injected during generation

CDATA sections

Parser notes which fields used CDATA

XML comments

Preserved at channel and item level

Namespace prefixes

Original mappings are retained

Comparing Feeds

FeedDiff detects differences between two feed versions:

Chapters

Two chapter systems coexist in the podcast ecosystem. PodcastFeedMaker supports both:

  • JSON Chapters β€” The Podcast Namespace format, linked via <podcast:chapters>

  • Podlove Simple Chapters β€” The inline format via <psc:chapters>

CLI: 13 Commands

podcastfeed exposes all library functionality from the command line. Perfect for automation and CI/CD pipelines.

Installation

In Action

All Commands

CommandWhat It Does

init

Creates a feed from a template (basic, standard, advanced, expert)

generate

Generates XML from a JSON definition

read

Displays a feed (summary, JSON, or XML)

validate

Checks against a platform

lint

Quick validation, optional strict mode

episodes

Lists episodes with sort and limit

chapters

Extracts chapters

diff

Compares two feeds

convert

Converts between formats

add-episode

Adds an episode

Exit Codes

For CI/CD integration: 0 = success, 1 = error, 2 = warnings without errors. In --strict mode, warnings become errors.

Architecture

Tests

2655 tests across 283 test suites. Complete coverage of all 7 namespaces, 12 date formats, 5 validators. All tests run on macOS and Linux in CI β€” no mocks, real XMLParser and real Data.

Installation

Requirements

  • Swift 6.2+ with strict concurrency

  • Lib: macOS 13+, iOS 16+, tvOS 16+, watchOS 9+, visionOS 1+

  • CLI: macOS 13+, Linux (Ubuntu 22.04+, Amazon Linux 2023+)

  • Zero dependencies in the core (swift-argument-parser for CLI only)

References

The specs PodcastFeedMaker is built on:

Roadmap

  • βœ… OPML import/export β€” Subscription lists, validation and conversion between apps (0.2.0)

  • βœ… Feed Audit β€” 0-100 scoring across 29 criteria, actionable recommendations, compatibility matrix (0.2.0)

  • βœ… Vapor Middleware β€” Server-side dynamic feeds, HTTP caching, Podping (PodcastFeedVapor)

  • More validators β€” Additional per-platform rules

Under the Hood

  • Swift 6.2 β€” Strict concurrency, Sendable types

  • Zero dependencies β€” Pure Swift + Foundation

  • Multi-platform β€” macOS, iOS, tvOS, watchOS, visionOS, Linux

  • 2655 tests β€” 283 suites, CI on macOS + Linux

  • 12 DocC guides β€” Complete documentation

Links

GitHub - atelier-socle/podcast-feed-maker: Reference-quality Swift library for generating, parsing, and validating podcast RSS feeds. 7 namespaces, 5 platform validators, builder DSL, CLI tool.

GitHub - atelier-socle/podcast-feed-maker: Reference-quality Swift library for generating, parsing, and validating podcast RSS feeds. 7 namespaces, 5 platform validators, builder DSL, CLI tool.

Reference-quality Swift library for generating, parsing, and validating podcast RSS feeds. 7 namespaces, 5 platform validators, builder DSL, CLI tool.…

GitHub