Download specific podcast episode audio from Apple Podcasts, RSS feeds, or xiaoyuzhou links — with an interactive picker.
Project description
podpull
Download any podcast episode — Apple Podcasts, RSS, or 小宇宙/xiaoyuzhou — straight to your shell.
Pick episodes from an interactive multi-select list, with spinners and progress bars. No app, no login, no DRM. Files are named cloud-safe and (for multiple picks) grouped per show.
▶ Live animated demo & landing page: https://xiaoleiy.github.io/podpull
Demo
$ podpull get 1532755821
✓ 我們家的睡前故事 — 394 episodes
? Select episodes (↑/↓ · space · enter)
❯ ◉ 2026-06-23 EP343 迷宮中的牛頭人
◯ 2026-06-16 EP342 午睡任務
◉ 2026-06-09 EP341 修煉龍 4
██████████████████ 100% 21.2 MB • saved to ~/Downloads/Podcasts/我們家的睡前故事/
How it works
Apple Podcasts hosts no audio — it is a directory that points at each show's
RSS feed, and every episode in that feed carries a direct <enclosure> audio URL.
podpull walks that chain:
Apple show URL/id ──(iTunes Lookup API)──▶ RSS feedUrl
RSS feed ──(<enclosure url>)────▶ direct .mp3 / .m4a
download ──(resumable)──────────▶ <YYYY-MM-DD> - <title>.<ext>
It also resolves a pasted xiaoyuzhou episode page (via its og:audio tag) and a
pasted Apple episode link (…?i=<id>, matched in the feed).
Install
# Homebrew (recommended)
brew install xiaoleiy/tap/podpull
# or pipx / pip, straight from git
pipx install git+https://github.com/xiaoleiy/podpull
pip install git+https://github.com/xiaoleiy/podpull
Requires Python 3.9+. Optional: yt-dlp (deep-catalog Apple-episode fallback),
ffmpeg/ffprobe (verify downloads).
Note: not yet published to PyPI — install via the Homebrew tap or from git.
Set up your AI coding agents (optional)
Teach your AI agents to use podpull so you can just ask them to grab an episode:
podpull skills install # detected agents
podpull skills install --all # all supported agents
podpull skills status # see what's detected / installed
This writes podpull's instructions in each agent's native format:
| Agent | Installed as | Location |
|---|---|---|
| Claude Code | skill | ~/.claude/skills/podpull/SKILL.md |
| Codex | skill | ~/.codex/skills/podpull/SKILL.md |
| OpenCode | /podpull command |
~/.config/opencode/commands/podpull.md |
| Cursor | project rule | <project>/.cursor/rules/podpull.mdc |
Re-run after brew upgrade to refresh. Nothing is written until you run it.
(Cursor has no file-based global rule — run it inside a project for a project rule,
or paste the printed rule into Cursor Settings → Rules.)
Usage
podpull search "睡前故事" # find shows -> id, #episodes, name, author
podpull info 1532755821 # show metadata (accepts URL, id, or RSS)
podpull list 1532755821 # recent episodes, numbered (0 = newest)
podpull list 1532755821 --match "EP34" # filter by title regex
Download
# Interactive picker — just give a show; pick one or many episodes with the keyboard:
podpull get 1532755821
# ↑/↓ move · space toggle · a select-all · enter confirm
# Or select non-interactively (also used when piping / scripting):
podpull get 1532755821 --latest 1 # newest episode
podpull get 1532755821 --match "牛頭人" # by title regex
podpull get 1532755821 --index 0,2,5 # by list number (0 = newest)
podpull get 1532755821 --latest 3 --out ~/Audio/bedtime
# Pasted single-episode links:
podpull get "https://www.xiaoyuzhoufm.com/episode/<id>"
podpull get "https://podcasts.apple.com/.../id<show>?i=<track>"
Downloads default to ~/Downloads/Podcasts (override with --out). The saved file
path is printed to stdout (so you can pipe/capture it); progress and messages go
to stderr. Use --no-input to never open the picker (fail instead) for scripts.
Filenames are normalized for cloud storage — emoji and other symbols are dropped, full-width/illegal characters folded or stripped — so files upload cleanly to Google Drive, OneDrive, Dropbox, iCloud, etc. (CJK and ordinary text are kept). When you grab multiple episodes at once, they're placed in a sub-folder named after the show.
<src> accepts: an Apple show URL, a bare Apple ID, a raw RSS feed URL, an Apple
episode URL (?i=), or a xiaoyuzhou episode URL.
Roadmap
- v0.1: search · info · list · download (stdlib only).
- v0.2: interactive multi-select picker, rich progress bars + spinners,
colored help, scriptable stdout. Adds
rich+questionary. - v0.3: renamed
podget→podpull. - v0.4: cloud-safe filename normalization; multi-episode downloads grouped into a per-show folder.
- v0.5 (current):
pullalias forget;podpull skills installsets up integrations for Claude Code, Codex, OpenCode, and Cursor. - next: more robust feed parsing, tests on more hosts, Podcast Index support.
- v1+ (
podpull[ai]): opt-in BYOK summarization — local transcription (faster-whisper) + your own LLM key (Anthropic/OpenAI). Fully local, private, no subscription. Cleanly isolated from the core.
Ethics & legal
podpull reads the public RSS feeds that podcasters publish for exactly this purpose, and downloads the enclosure files they distribute. Respect each show's copyright and terms — download only what you're entitled to, for personal use.
License
MIT © xiaoleiyu
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file podpull-0.5.1.tar.gz.
File metadata
- Download URL: podpull-0.5.1.tar.gz
- Upload date:
- Size: 28.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a214edbbffb39562102291e46a72387dcc4027c4e173008f889a5f834bf23777
|
|
| MD5 |
be173d1a5caaa20309ed55164325109c
|
|
| BLAKE2b-256 |
f707a7e2a92d5fb5658a695b87cfb7ef23800746b3204f959f8862d961d66dc7
|
File details
Details for the file podpull-0.5.1-py3-none-any.whl.
File metadata
- Download URL: podpull-0.5.1-py3-none-any.whl
- Upload date:
- Size: 21.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05b350a0c4e2de12619e807db3f90161e544a2ad5f0e12035cbb9fb355c3f247
|
|
| MD5 |
a52e3552a5ad5819fbecc984f56b5277
|
|
| BLAKE2b-256 |
246abf8a85151e3e5215bf6181816622e6667c6b21406f31f16cdaadbd16291f
|