Terminal podcast player with cover art, playback resume, and optional sync via a private GitHub Gist.
- Browse podcast feeds in a terminal UI
- Play episodes with
ffplay - Render podcast cover art in the terminal with
chafa - Resume from the last saved playback position
- Cache feeds, cover art, durations, and rendered art locally
- Sync config and play state across machines with GitHub Gists
- Install as a Go binary or through npm-distributed platform binaries
- Go 1.25+ if building from source
ffplayandffprobefromffmpegchafafor terminal cover-art renderingghif you want to usesync
If ffplay is missing, playback will fail. If chafa is missing, the app still runs, but cover art will not render.
npm install -g podcast-player-cliThis package ships prebuilt binaries for:
- macOS
arm64 - macOS
amd64 - Linux
arm64 - Linux
amd64
Node.js 18+ is required for the npm launcher.
go build -o podcast-player-cli .Pass feed URLs directly:
podcast-player-cli https://example.com/feed.xml https://example.com/another.xmlOr keep your subscriptions in the config file and just run:
podcast-player-cliYou can also route feed and cover-art requests through a proxy:
podcast-player-cli --proxy http://127.0.0.1:7890On first launch the app creates:
~/.podcast-player-cli/config.json~/.podcast-player-cli/play-state.json~/.podcast-player-cli/sync-state.json~/.podcast-player-cli/cache/
Example config:
{
"feed_urls": [
"https://example.com/feed.xml",
"https://example.com/another.xml"
],
"proxy_url": "http://127.0.0.1:7890",
"sync": {
"gist_id": "YOUR_GIST_ID"
}
}Notes:
- CLI feed URLs override
feed_urlsfor that run --proxyoverridesproxy_url- playback state is saved automatically while listening
j/kor arrow keys: move selectionenter: open a subscription or play the selected episodel: move deeper into episodes or episode detailsh/backspace: move backp: play selected episodespace: pause or resume playbackz: toggle zen moder: refresh feedsg/G: jump to top or bottomesc: back or exit zen modectrl+c: quit
Sync stores config.json, play-state.json, and a small manifest in a private GitHub Gist.
Before using sync:
- install GitHub CLI
gh - run
gh auth login
Initialize sync:
podcast-player-cli sync initPull from the configured gist:
podcast-player-cli sync pullPush local state to the configured gist:
podcast-player-cli sync pushOverride the gist ID for a single command:
podcast-player-cli sync pull --gist <gist-id>
podcast-player-cli sync push --gist <gist-id>Run tests:
go test ./...Build locally:
go build ./...