6dd541b1a43ee12d6753225f33851a827e2be476
- blossom-server 4.4.1 expects rules nested under storage: — the top-level rules list was ignored, leaving an empty ruleset that rejected all uploads - podpuddle now verifies blobs and uploads recordings via BLOSSOM_URL_INTERNAL (http://blossom:3000) while feeds keep the browser-facing URL; unreachable blossom now returns 502 instead of a 500 - mediamtx: fix deprecated allow-origin params, disable MoQ - scripts/e2e.mjs: 14 API checks (login, replay/URL rejection, upload, episode, feed, stream keys, mediamtx auth) — all green, plus verified live: RTMP publish with key → HLS 200, wrong key refused, status planned→live→ended via poller, recording remuxed + published as episode, feed XML well-formed with 2 items Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
podpuddle
Self-hosted, nostr-native podcast publishing and livestreaming.
- Log in with nostr — NIP-07 browser extension (Alby, nos2x, …); the server verifies NIP-98 signed requests. No passwords, no email.
- Upload an mp4 → it is stored on a Blossom server
(bundled, or point at any external one) and published in an RSS 2.0 podcast feed with
Podcasting 2.0
<podcast:value>lightning-address payment info. - Go live — stream from OBS (RTMP) or straight from the browser (WebRTC/WHIP) through MediaMTX; viewers watch via HLS and the stream is announced on nostr as a NIP-53 (kind 30311) live event.
- Publish recordings — live streams are recorded; one click remuxes and publishes a recording as a podcast episode.
Quick start
cp .env.example .env # edit PUBLIC_HOST if not localhost
docker compose up --build -d
Then open http://localhost:8095, log in with a NIP-07 extension, and follow the wizard.
Services / ports
| Service | Host port | Purpose |
|---|---|---|
| podpuddle | 8095 | Web UI + API + RSS feeds |
| MediaMTX | 1935 | RTMP ingest (OBS) |
| MediaMTX | 8889 (+8189/udp) | WebRTC/WHIP ingest (browser) |
| MediaMTX | 8890 | HLS playback |
| blossom-server | 8098 | Media blob storage (sha256-addressed) |
Streaming with OBS
Create a stream in the UI; it gives you:
- Server:
rtmp://<host>:1935/live - Stream key:
<streamId>?key=<secret>
The HLS playback URL (http://<host>:8890/live/<streamId>/index.m3u8) is public and never
contains the secret.
Development
docker compose up mediamtx blossom -d # backends
cd server && npm install && npm run dev # API on :8095
cd frontend && npm install && npm run dev # Vite on :5173, proxies /api + /feeds
Tests: cd server && npm test.
Data
Everything lives in named docker volumes: podpuddle-data (SQLite, server nostr key,
covers), mediamtx-recordings (stream recordings, 7-day retention), blossom-data
(media blobs).
Languages
TypeScript
69.6%
Vue
24.8%
JavaScript
4.3%
Dockerfile
0.6%
CSS
0.6%
Other
0.1%