Skip to content
ThemeNord

Same themes as the MinusPod app

Default

Catppuccin

Dracula

Nord

Gruvbox

Solarized

Rose Pine

Kanagawa

Ayu

Other

Podcasting 2.0 in MinusPod

MinusPod sits between the original podcast feed and your player. It downloads each episode, removes ad segments, re-encodes the audio, and serves a modified RSS feed pointing at the processed files.

MinusPod is not the podcast’s publisher, so the Podcast Namespace (the podcast: tags often called “Podcasting 2.0”) needs care: it is a proxy that rewrites someone else’s feed.

Almost none of this is configurable. Two things are: each feed can choose how its podcast:chapters tag is populated (see “Chapter modes” below), and Podping listening is an opt-in, instance-wide toggle (see “Podping” below). Everything else in this document is automatic for every feed MinusPod serves.

This document is about that proxy case: a feed MinusPod re-serves on someone else’s behalf. A local feed is different. MinusPod is the publisher there, not a proxy, so there is no upstream tag to pass through, strip, or regenerate against. See Local Feeds > Podcasting 2.0 fields for what a local feed emits instead.

Chapters and transcript for the cut audio, the served feed’s namespace tags, and the chapter settings. Portrait cut and the file itself in Videos.

Every Podcast Namespace tag falls into one of four buckets:

  1. Pass through: the tag is still true after ad removal, so the upstream value is copied into the served feed unchanged.
  2. Regenerate: the tag describes the audio, so MinusPod produces its own correct version for the processed file.
  3. Strip: the tag asserts something about the original audio that is false for the re-cut file, so emitting it would be a lie or would break players. It is removed.
  4. Always emit: MinusPod adds the tag regardless of the upstream feed.

“Strip” is not a feature gap. Passing these tags through would make the feed describe audio that no longer exists.

Tag Behavior
podcast:guid MinusPod mints its own feed GUID. See “Feed identity” below.
podcast:txt (purpose="ai-content") Always set to true. MinusPod algorithmically re-cuts the audio, and the served feed discloses that. Any upstream ai-content value is replaced, because once MinusPod has processed the file the upstream claim is no longer accurate.

These remain accurate after ad removal and are copied verbatim:

Tag Why it survives
podcast:funding The creator’s donation links are unaffected by ad removal.
podcast:locked Reflects the creator’s intent about feed re-import. If the original feed has no locked tag, MinusPod emits locked as yes, because a private re-feed should not be imported into public directories.
podcast:podroll Show recommendations remain valid and useful for discovery.
podcast:value, podcast:valueRecipient, podcast:valueTimeSplit Value-for-value payment information is passed through untouched so listener support still reaches the original creator. MinusPod does not insert itself into the payment split.
podcast:license Content license is metadata, not tied to the audio timeline.
podcast:medium Describes the kind of content, unaffected.
podcast:person Host and guest credits are unaffected by cutting.
podcast:updateFrequency The publishing schedule does not change.
podcast:season, podcast:episode Structural numbering, no timeline dependency.
podcast:trailer A trailer is its own separate file, not an offset into the episode.
podcast:image Artwork sources improve display and are unaffected. The deprecated plural podcast:images, if present upstream, is also passed through untouched.
podcast:socialInteract Comment and discussion links are unaffected.
podcast:block The publisher’s directory-block hints. Multiple instances are allowed, optionally scoped to one platform with an id attribute (e.g. id="apple"). MinusPod copies each one verbatim. Stripping these would silently expose the re-feed in directories the publisher chose to keep it out of.
podcast:complete Boolean for “no more episodes are coming”. Applies to the show, not the audio timeline; ad removal does not change whether the run is over.
podcast:txt (general, no verify purpose) Free-form metadata, harmless to carry.

MinusPod already produces these for the cut file. The upstream versions are discarded because their timestamps point into the original, uncut audio, and because subscribers to a MinusPod feed must never be sent to a publisher URL: the proxy serves everything or nothing. Until MinusPod finishes processing an episode, the served feed carries no transcript or chapter URL for it; the audio enclosure returns 503 with a JIT-triggered processing job behind it.

Tag Why it is regenerated
podcast:transcript MinusPod generates a transcript aligned to the processed audio. An upstream transcript would be offset by the length of every removed ad, and would also point subscribers at the publisher’s CDN. The upstream tag is still read internally, never served, to diff against MinusPod’s own transcript for ad evidence; see Upstream Transcript Differential.
podcast:chapters MinusPod serves its own chapters JSON because upstream timestamps point into the original, uncut audio. Its contents depend on the effective chapter mode; see “Chapter modes” below.
itunes:duration Recomputed from the processed file’s actual length.
enclosure length The processed file’s byte size. An unprocessed episode passes through upstream’s length when declared, omitting the attribute otherwise.

Pass-through episodes are the exception: nothing is cut, so the publisher’s timestamps stay valid. At processing time MinusPod imports the item’s podcast:chapters and podcast:transcript and serves them from its own URLs, never the publisher’s. A timed transcript (VTT, SRT or JSON) is stored as the episode transcript with a VTT when VTT transcripts are enabled; an untimed one (HTML or plain text) appears in the Transcript card only, with no VTT. Once the feed leaves pass-through, the next reprocess transcribes the episode with Whisper; the publisher transcript is not used for detection.

Settings > Transcripts & Chapters sets the chapter mode: Auto (the default), Always generate, or Off. New feeds and feeds set to Inherit use that choice; an explicit Feed Settings value overrides it. During normal processing, the mode is applied only when Generate Chapters is on.

Encrypted, compressed, restricted, or malformed ID3 chapter tags stop processing before existing audio and chapter data are replaced.

The cut step remaps embedded ID3 chapters and preserves their images and links. Auto keeps surviving ID3 publisher chapters, including a single chapter. When preserving publisher chapters, recuts recover their metadata from the retained original and remap it to the new cut timeline.

Chapter images are served locally when their JPEG or PNG data fits the artwork size limit. Other embedded image formats remain in the ID3 tags. Local image URLs retain the validated feed key supplied with the chapter request.

When usable embedded chapters are unavailable, MinusPod checks whether the feed declares its chapters in a separate podcast:chapters JSON file, captured at the last feed refresh. If it does, MinusPod fetches that file, remaps its timestamps the same way, and uses the result when at least two chapters survive. A failed or malformed fetch counts as unknown, not as “no chapters”, and it falls back to generation rather than losing chapters altogether.

Only when neither source yields usable chapters does MinusPod fall back to AI-generated chapters. If the embedded probe itself fails (for example a transient ffprobe error), MinusPod treats that as unknown too, and skips the chapter step for that run rather than risk overwriting the ID3 frames the cut step already wrote correctly.

Always generate skips the probe and always produces AI chapters.

Off stops chapter work for episodes processed from then on: no probing, no generation, and nothing saved, so those episodes carry no podcast:chapters tag. Episodes processed before the switch keep the chapters they already have until they are reprocessed.

Auto is the default because it keeps the publisher’s chapters whenever they hold up across the cut, rather than replacing accurate ones with generated chapters.

Most apps only show podcast:chapters once playback starts. To make the list readable while browsing, turn on List chapters in episode descriptions under Settings > Transcripts & Chapters (chaptersInNotes, off by default). Each episode’s description in the served feed, and on the episode page, then ends with a Chapters block: one mm:ss Title line per chapter, h:mm:ss past an hour. It is built from the same generated chapters the JSON carries. The block is rendered when the description is served and is never written into the stored description, so turning the setting off removes it and regenerating chapters updates it. Each feed can override the global value from its Feed Settings page (chaptersInNotes: on, off, or unset to follow the global setting).

To jump from a podcast app to an episode in MinusPod, turn on Add review links to episode descriptions under Settings > Transcripts & Chapters (reviewLinksInNotes, off by default). The description of every episode MinusPod has seen then ends with two links: Review in MinusPod opens the episode page, and Rate 5 stars opens it with ?rate=5, which applies a 5-star rating as soon as the page loads, confirms it with an Undo button and removes the parameter from the address bar. The links are added as soon as MinusPod has the episode, including while it is still processing, because some apps store show notes the first time they see an episode and never refresh them. Items the upstream feed lists but MinusPod has not discovered yet get no links. The rating link is a page address, not an API call, because podcast apps and link previews fetch URLs from show notes on their own. It needs a browser logged in to MinusPod and goes through the login page first when it is not. The links are built from UI_BASE_URL, or BASE_URL when that is unset. Each feed can override the global value from its Feed Settings page (reviewLinksInNotes: on, off, or unset to follow the global setting).

A segment kept in the audio by its category action still sits in the file. Set a category’s segment action to Mark (Settings > Segment actions, or a feed’s own override; see Configuration > Segment categories) and MinusPod adds a chapter at the start of each marked break and a resume chapter at its end, so an app that skips by chapter can jump past it. Keep leaves the segment in the audio but publishes no chapter for it. Chapters have no end time, which is why the resume chapter exists. When a generated chapter already starts within two seconds of the end, that chapter is the resume point instead. A feed whose chapters mode is Off still gets no chapters, Mark or not.

A marked segment needs a detection confidence of at least Minimum confidence (Settings > Transcripts & Chapters, 0.9 by default). Turn on Include segments waiting for review to chapter held segments too, when the category they are held under resolves to Mark on that feed. They use the waiting-for-review title format, and rejecting one removes its chapter without a recut. Confirming one queues a recut, which rebuilds the chapter list when it runs.

Titles come from Chapter title (Ad: {label} by default), Title while waiting for review (Possible ad: {label}), and Resume title (Show). {label} is the category name, such as Sponsor. {category} is its id, such as sponsor, for players that match chapter titles by keyword. Switching a category between Keep and Mark, globally or on one feed, takes effect the next time that feed’s chapters are rebuilt: Regenerate Chapters on an episode, or Re-render episodes with current segment actions on the feed. Existing episodes are not backfilled automatically.

A category’s segment action is the only chapter switch. The deprecated adChaptersEnabled and adChapterCategories API fields map onto it: adChaptersEnabled reads true when any category is Mark, and false sets every Mark to Keep (true has no effect); a true or false entry in adChapterCategories sets that category to Mark or Keep. New integrations should set segmentCategoryActions to mark directly.

These describe the original audio’s timeline or bytes. After ad removal they are false. Two of them can make a conformant player refuse to play the episode.

Tag Why it is removed
podcast:soundbite startTime and duration point into the original timeline. After cutting, that offset is wrong, so a “highlight” would play the wrong audio, possibly mid-sentence or inside a removed ad.
podcast:integrity A cryptographic hash of the original audio bytes. The processed file will never match it. A player that verifies integrity will reject the episode outright.
podcast:alternateEnclosure Points at other copies of the original, un-stripped audio. Following it bypasses ad removal entirely.
podcast:source Describes sources of the original audio, not the processed file MinusPod serves.
podcast:liveItem A live stream. By the time MinusPod has downloaded and processed recorded audio, the live event is over. It has no meaning in a re-cut feed.
podcast:txt (purpose="verify" or purpose="applepodcastsverify") An ownership-verification token a hosting platform issued to the original publisher. It proves nothing about a MinusPod re-feed, and carrying it forward leaks the original owner’s token into a feed they don’t control.

Podping is a Hive blockchain notification bus that podcast hosts use to announce “this feed just updated” the moment they publish, instead of waiting for aggregators to poll. MinusPod does one half of that: it can listen for these notifications about the feeds it re-serves, but it never sends any of its own.

Settings > Global Defaults has a Podping notifications toggle, off by default. When enabled, MinusPod runs a background thread that polls public Hive API nodes roughly every 3 seconds for new blocks, reads the podping and pp_-prefixed custom JSON operations in them, and checks each announced feed URL against your configured feeds. On a match, MinusPod stamps that feed’s “last podping” time and triggers an immediate refresh of that one feed, instead of waiting for the next scheduled RSS poll.

When Podping is enabled, open Podping servers beneath the toggle to edit the Hive RPC node list. Add between 1 and 20 HTTP(S) endpoint URLs, remove or reorder them, then save. MinusPod normalizes and deduplicates the list, and rotates through it for listener traffic and health checks. Reset defaults restores the shipped node list. These RPC endpoints are separate from the observed feed hosts shown in System Health.

Which senders count is up to each feed. A feed can name the accounts allowed to podping it with <podcast:hiveAccount account="..."> inside its <podcast:podping> tag, and MinusPod ignores podpings for that feed from anyone else. A feed carrying usesPodping="false" is asking to be polled, so MinusPod skips podping refreshes for it entirely. The tag is optional, and a feed that says nothing accepts any sender. Scheduled polling runs either way, so the worst a declaration can do is leave a feed on the schedule.

No Hive account, keys, or wallet are required. The listener only reads the public chain; it never writes to it. Requests go to a small, built-in list of public Hive API nodes over outbound HTTPS, roughly two requests every 3 seconds while the toggle is on (a head poll plus a block fetch each tick). If a node is unreachable, the listener rotates to the next one and backs off.

Settings > System Health lists each node’s endpoint, latest HTTP status, and last successful response time. It identifies the node carrying listener traffic. While the listener is enabled, MinusPod checks every node at startup and every five minutes. Check now runs the same check on demand, even when the listener is off. These checks do not change the active node. The same summary and check progress are available from GET /api/v1/system/status.

Podping is an accelerator, not a replacement for polling. The scheduled RSS refresh (see How It Works > Processing Queue and the Feed Refresh and Podping settings) keeps running unchanged, so a missed or delayed Podping notification costs nothing: the feed is picked up on its next regular poll either way.

Coverage depends on the host. Hosts sending Podping notifications include Spreaker, Buzzsprout, RSS.com, PodServe, Transistor, RedCircle, Captivate, Podigee, Fireside, PRX Dovetail, Blubrry, Podhome, and Alitu, alongside a long tail of self-hosted and WordPress feeds. Many large hosts, including Acast, Megaphone, Libsyn, Simplecast, and Omny, do not. Enabling the toggle only speeds up episodes on feeds whose host pings; everything else keeps its existing polling cadence.

That list is a snapshot from three days of Podping traffic on the Hive chain in July 2026, and hosts adopt Podping over time. Use the Podping line below to see what a specific feed actually receives.

With the listener on, the feed detail page and the feed lists show one line per feed. It reads Podping: last ping at <time> once a notification has arrived for that feed. A feed whose own tag declares usesPodping="true" but has not been pinged yet reads Podping: enabled, none received yet. Everything else reads Podping: never. The line is hidden when the listener is off, because that is an instance-wide setting rather than anything about the feed.

The API carries more detail than the line does. podpingCoverage on the feeds endpoints separates the reasons a feed reads as never: the publisher declined Podping, the publisher opted in but nothing has arrived yet, the host was seen pinging other feeds in the last 30 days, or nothing is known. It also returns the parsed declaration as podpingUses and podpingHiveAccounts. GET /api/v1/podping/hosts lists every domain the listener has seen announcing feeds, which is the way to confirm the listener is receiving traffic at all. A feed that stays on never while /podping/hosts shows its host pinging usually means MinusPod’s stored source URL does not match what the host announces.

MinusPod does not send Podping notifications for the feeds it serves, and has no podcast:podping tag or setting to turn that on.

This follows from what MinusPod is. It is a proxy that re-serves someone else’s feed with ads removed, not the publisher of that content. The feeds MinusPod serves change only when the upstream feed changes, and players already discover that on the upstream publisher’s own schedule (directly, or through the upstream host’s own Podping notifications). MinusPod announcing its own re-feed as a new publish event would tell the ecosystem about a private, ad-stripped derivative of content you do not own, which is not what Podping is for.

MinusPod mints its own podcast:guid rather than reusing the original feed’s GUID.

The GUID is the stable identifier other tools use to recognize a feed. A MinusPod feed is a modified derivative served at a different URL. If it claimed the original’s GUID, aggregators could treat the two feeds as the same feed, which they are not.

The GUID is computed the way the Podcast Namespace guid spec specifies: a deterministic UUIDv5 over the served feed URL, using the namespace’s fixed constant. The same feed URL always produces the same GUID, so the identity is stable for as long as the feed is served at the same address. If you move MinusPod to a different domain, the served URL changes and so does the GUID, which is correct, because at that point it is genuinely a feed at a new address.

The Podcast Namespace spec treats several xmlns URIs as equivalent, and real-world feeds use them interchangeably. The reference pc20.xml feed, for example, declares the GitHub-blob form rather than the podcastindex.org form. MinusPod accepts all of these on parse:

  • https://podcastindex.org/namespace/1.0
  • https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md
  • https://github.com/Podcastindex-org/podcast-namespace/blob/master/docs/1.0.md
  • The http:// variants of each

The served feed always declares the canonical https://podcastindex.org/namespace/1.0 URI on its <rss> root, no matter which form the upstream feed used. Passthrough tags are re-emitted under the canonical podcast: prefix.

Every tag MinusPod adds is in the podcast: namespace. A player that does not understand a tag ignores it; the standard RSS and itunes: elements it relies on are untouched. A basic podcast app sees a normal feed and plays the audio. Podcasting 2.0 apps see the additional tags. Nothing about this support breaks older clients.

docs/examples/served-feed.xml is a sanitized excerpt of a real feed served by a MinusPod instance, with the host, feed key, and episode identifiers replaced by placeholders. It shows the podcast:guid, podcast:locked, podcast:funding, podcast:txt, podcast:transcript, and podcast:chapters tags as MinusPod emits them.

External Podcasting 2.0 documentation:

Per-tag specifications are linked inline from the tables above.