Model or dataset
ttlequals0/MinusPod avatar
ttlequals0/MinusPod

MinusPod: a self-hosted ad remover for podcasts that re-cuts the feed

MinusPod is a self-hosted server that removes ads before you ever hit play

423 stars39 forksPythonMIT

At a glance

What is it?
MinusPod runs Whisper transcription and an LLM ad detector on your own server, then publishes a re-cut RSS feed. It is aimed at people who will trade GPU time and API spend for control over what gets cut.
Who is it for?
Adopt MinusPod if you already run Docker, have a GPU or a remote Whisper endpoint, and want the ad-removal decision to live on your hardware with an audit trail of rejected cuts. Do not adopt it if you want a hosted app on a phone: the README describes a server with a web UI, not a client, and the related searches asking what MinusPod is on Android have no answer in the documentation.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What MinusPod removes, and who is expected to run it

Podcast ad insertion happens at the enclosure URL, not in the app. The file your client downloads already contains the host-read spot, and dynamic ad insertion can swap a different sponsor into the same episode weeks later. MinusPod attacks that at the source: it subscribes to the upstream feed, downloads the audio, finds the ad spans, cuts them with FFmpeg, and serves its own feed and audio files. The README's one-line description is "a self-hosted server that removes ads before you ever hit play," and the word server is doing real work. This is not a phone app or a browser extension.

The intended operator is someone who already runs Docker and is willing to hold an Anthropic, OpenRouter or Ollama credential. The requirements section lists Docker with NVIDIA GPU support for local Whisper, or a remote Whisper backend if you have no GPU. The trade is explicit: you supply compute and possibly per-token spend, and in return the detection logic, the prompts, the sponsor list and the correction history all stay on your machine. The repository is MIT licensed and the last push was on 2026-09-15, with releases v2.96.25, v2.96.24 and v2.96.22 landing within four days of each other.

The detection pipeline: Whisper, sliding-window LLM passes, then FFmpeg

The pipeline described in the README is sequential and mostly deterministic until the LLM stage. Whisper transcribes the episode. An LLM reads the transcript in sliding windows to find ad segments. FFmpeg cuts them. Flask serves the modified feed and audio. The docs directory carries the detail in docs/how-it-works.md, covering the verification pass, sliding windows, the queue, validation, pattern learning and audio analysis.

What makes the design more than a transcript filter is the second and third passes. After the first cut, an automatic verification pass runs over the re-cut audio. An optional ad-reviewer stage can confirm, adjust or reject each cut, and the README states it can resurrect borderline detections. Alongside the LLM there are audio-side signals: loudness analysis, DAI transition detection, pre and post-roll handling, and a VAD-gap detector for spans Whisper drops. Per-feed audio cue detection snaps cuts to a show's jingle or stinger, which matters because a stinger boundary is often a cleaner cut point than a word boundary.

Every marker carries a segment category (sponsor, cross-promo, self-promo, interaction, and opt-in intro, outro or recap), and each category resolves to remove, beep or keep. The default is remove until you configure otherwise, which is the aggressive setting. Corrections feed a pattern learner scoped podcast to network to global, so a repeat sponsor can be caught without asking the LLM again. That last mechanism is the cost-control valve: the more you correct, the less you pay for tokens on the same sponsor.

Installing MinusPod with Docker Compose and setting the first password

The quick start assumes an .env file, a data directory, and docker-compose up. Before processing an episode you must set BASE_URL, configure provider access, and choose a model. The README gives this block:

bash
# 1. Create environment file
cat > .env << EOF
ANTHROPIC_API_KEY=your-key-here
BASE_URL=http://localhost:8000
MINUSPOD_MASTER_PASSPHRASE=long-random-string-you-will-not-lose
OPENAI_MODEL=claude-haiku-4-5
EOF

# 2. Create data directory
mkdir -p data

# 3. Run
docker-compose up -d

After that the web UI answers at http://localhost:8000/ui/, which is where you add and manage feeds. Two details in the README are easy to miss and both will stop you. First, compose requires an application password before it serves the normal API, and you set the first password from the same host. For a remote setup you put a temporary MINUSPOD_SETUP_TOKEN in .env, send it in the X-MinusPod-Setup-Token header when setting the first password, then remove it. Second, compose prevents unauthenticated feed requests from starting paid processing, so you either enable Authenticated Feeds or set MINUSPOD_ALLOW_PUBLIC_PROCESSING=true if public just-in-time processing is deliberate.

If you have no NVIDIA GPU, the README points at the CPU variant, which is multi-arch and runs natively on amd64 and arm64:

bash
docker compose -f docker-compose.cpu.yml up -d

That still leaves transcription, which you offload to a remote API. On the passphrase: MINUSPOD_MASTER_PASSPHRASE is strongly recommended for production because without it provider API keys are stored in the database as plaintext. Setting it later migrates existing plaintext rows to enc:v1: storage on the next boot, with a mandatory pre-migration SQLite snapshot in data/backups/. An encrypted API download can only be restored with the same passphrase, so losing it means losing that backup.

Release cadence, stable versus latest, and what that costs you

The README is unusually direct about this: the :latest GPU tag and :cpu follow every release, and several can land in one day. The release list bears that out. For a slower track you set MINUSPOD_VERSION=stable or MINUSPOD_VERSION=stable-cpu in .env to pin ttlequals0/minuspod:stable or :stable-cpu. The README states that stable tags only move to releases that have soaked in production, and points to the releases page for curated notes.

My read is that the default tag is the wrong choice for anyone who does not want to read a changelog before a weekend. A pipeline that re-cuts audio and republishes feeds has a lot of surface for a regression: a bad cut is audible and a broken enclosure breaks every subscriber at once. Pinning stable costs you fixes and buys you a smaller blast radius. The counter-argument is that ad detection is adversarial, sponsors change read styles, and a detector that is a month behind may simply miss more. Neither the README nor the compose file documents an automatic rollback, so downgrading means changing the tag and accepting whatever the database migration did in between. That is the real upgrade cost here: the app owns a SQLite database and a data directory, and schema changes ride along with image changes.

Where MinusPod is the wrong tool

The honest limitation is that this is a server you operate, and the failure modes are operational. If the container is down, your feed is down. If Whisper mishears a host-read transition, the LLM may cut into content, and while the verification pass and the review queue exist precisely to catch that, the README does not claim they are infallible. Rejected detections stay visible for auditing, which is the right design, but auditing is work you have to do.

Cost is the second boundary. Local Whisper on GPU means a machine that is on when episodes drop. A remote Whisper backend or a hosted LLM means per-episode spend, and the README's own stats view tracks token usage and spend, which tells you the project expects that number to be non-trivial. Pattern learning reduces repeat spend but only after you have corrected the same sponsor enough times.

Third, the client side. MinusPod publishes a re-cut RSS feed per podcast. Whether your podcast app follows that URL, and whether it handles regenerated Podcasting 2.0 transcripts and chapters, depends on the app, and the README does not enumerate compatible clients. If you listen in a closed app that ignores feed URLs you supply, the whole pipeline is invisible to you. The related searches asking what MinusPod is on Android point at exactly this gap: the documentation describes a server and a web UI, not a mobile client.

How MinusPod differs from a client-side ad skipper

The obvious alternative is a podcast client that detects and skips ad segments during playback, the category the related searches gesture at with names like ZeroAds and Podtastic. The approaches are not variations on a theme; they sit at different layers. A client-side skipper leaves the downloaded file untouched and jumps the playhead, so the ad audio is still in the file, still counted as a download, and still there if you scrub back. It requires no server, no GPU, no API key, and no feed URL change.

MinusPod instead rewrites the artifact. The ad is gone from the audio that gets served, and the feed it publishes carries versioned audio files plus regenerated transcripts and chapters. That produces a file you can hand to any player, cast to a speaker, or archive. It also means the work happens once per episode rather than on every device, and the corrections accumulate in a pattern store that a client-side skipper has nowhere to keep. The cost is everything described above: a host, a GPU or a paid transcription path, an LLM credential, and a feed URL your client must accept.

There is a middle option worth naming. MinusPod's local feeds feature builds a feed from your own audio files instead of an upstream RSS feed, with single or bulk episode upload and a dry-run import preview, running the same ad-removal pipeline. That is a reasonable way to evaluate the detector on a handful of files you already have before you point it at a live subscription.

Licence, encryption and the parts that are your responsibility

MinusPod is MIT licensed, which is permissive and places few obligations on you beyond keeping the notice. The practical constraints are not in the licence text. They are in the data you handle: provider API keys, an optional master passphrase, encrypted backups, and a database that holds your correction history. The README recommends a long random passphrase kept separately from the database, and states that an encrypted API download requires the same passphrase that created it. Treat that as an operational rule, not a suggestion.

The README also carries a disclaimer section and an LLM disclosure section. Both are worth reading before you expose the instance, because the project's own framing is that detection is probabilistic and the operator is the one publishing the resulting feed. If you serve that feed publicly, the re-cut audio and the AI-content disclosure tags are your publication. Nothing in the repository tells you what your upstream podcast's terms say about redistributing modified audio, and that question is outside what a licence file can answer.

Editorial conclusion

Adopt MinusPod if you already run Docker, have a GPU or a remote Whisper endpoint, and want the ad-removal decision to live on your hardware with an audit trail of rejected cuts. Do not adopt it if you want a hosted app on a phone: the README describes a server with a web UI, not a client, and the related searches asking what MinusPod is on Android have no answer in the documentation. Before committing, verify three things on your own box: whether your GPU has the VRAM the installation doc's table requires, whether the stable tag has moved since you pinned it, and whether your podcast client follows the re-cut feed URL rather than the original enclosure.

Frequently asked questions

Does MinusPod need an NVIDIA GPU?

No. The README lists Docker with NVIDIA GPU support for local Whisper as one option, and a remote Whisper backend as the alternative with no GPU needed. The CPU variant is multi-arch and runs natively on amd64 and arm64, with transcription offloaded to a remote API.

Which LLM providers can MinusPod use?

Anthropic, OpenRouter, Ollama, or any OpenAI-compatible endpoint, switchable at runtime. The .env.example shows four provider blocks, with LLM_PROVIDER set to anthropic by default and OPENAI_MODEL seeding the model setting whenever it is unset.

What happens if I do not set MINUSPOD_MASTER_PASSPHRASE?

Provider API keys are stored in the database as plaintext. The README says the passphrase is strongly recommended for production, and that setting it later migrates existing plaintext rows to enc:v1: encrypted storage on the next boot with a mandatory pre-migration SQLite snapshot in data/backups/.

Why does the first password need a setup token on a remote host?

Compose requires an application password before it serves the normal API, and the first password is set from the same host by default. For a remote setup the README says to put a temporary MINUSPOD_SETUP_TOKEN in .env and send it in the X-MinusPod-Setup-Token header, then remove it.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. ttlequals0/MinusPod on GitHub
Community notes

Community notes