Files
podsteadr/docker-compose.yml
T
ssmithxandClaude Sonnet 5 e92ef7fef9 feat: Cashu marketplace for paid episodes, resale, and cross-instance discovery
Paid episodes:
- server/services/cashu.ts: self-custodied Cashu wallet against a configured
  mint (NUT-04 mint quote -> bolt11 invoice -> mint/store proofs -> LNURL-pay
  payout on withdraw). Buyers pay a plain Lightning invoice, no Cashu wallet
  needed on their end.
- routes/marketplace.ts: purchase/confirm flow, download-url paywall gate,
  reseller certification/revocation, earnings ledger + withdraw.
- services/marketplace.ts: producer + certified-reseller source resolution,
  with a naive per-seller sales-count reputation signal.

Discovery:
- services/rss.ts: <podsteadr:source> RSS tag on priced episodes (producer +
  resellers, price, sales count, url) so pricing/sources are discoverable
  straight from the feed, not just a separate API call. Locked episodes point
  their <enclosure> at an info page instead of the raw file.
- routes/feeds.ts: /catalog.opml lists every podcast this instance hosts, for
  peer podsteadr servers or any OPML-aware crawler to discover without a
  central directory.

Frontend: episode wizard price/reseller controls, sources display, earnings
dashboard.

Also fixes CORS and a container-image reference:
- app.ts: register @fastify/cors, open on the catalog/feed/sources endpoints
  (already deliberately public/crawlable) and on purchase/confirm (already
  accept stateless NIP-98 header auth for exactly this case). Credentials
  stay off, so the session cookie never crosses origins — cookie-authed
  admin routes stay same-origin-only. Needed so external clients like
  podsteadr-player can browse/buy/play from a different origin.
- docker-compose.yml: fully qualify the mediamtx image reference
  (docker.io/bluenviron/mediamtx:1.19.2) — some Podman hosts have no
  unqualified-search registry configured and fail to resolve short names.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29 12:43:46 +00:00

61 lines
1.9 KiB
YAML

name: podsteadr
services:
podsteadr:
build: .
container_name: podsteadr
restart: unless-stopped
ports:
- "8095:8095"
environment:
NODE_ENV: production
PORT: "8095"
DATA_DIR: /data
RECORDINGS_DIR: /recordings
PUBLIC_URL: ${PUBLIC_URL:-http://localhost:8095}
MEDIAMTX_API_URL: http://mediamtx:9997
MEDIAMTX_RTMP_PUBLIC: ${MEDIAMTX_RTMP_PUBLIC:-rtmp://localhost:1935}
MEDIAMTX_WHIP_PUBLIC: ${MEDIAMTX_WHIP_PUBLIC:-http://localhost:8889}
MEDIAMTX_HLS_PUBLIC: ${MEDIAMTX_HLS_PUBLIC:-http://localhost:8890}
BLOSSOM_URL_DEFAULT: ${BLOSSOM_URL_DEFAULT:-http://localhost:8098}
BLOSSOM_URL_INTERNAL: http://blossom:3000
NOSTR_RELAYS: ${NOSTR_RELAYS:-wss://relay.damus.io,wss://nos.lol,wss://relay.nostr.band}
CASHU_MINT_URL_DEFAULT: ${CASHU_MINT_URL_DEFAULT:-https://mint.minibits.cash/Bitcoin}
volumes:
- podsteadr-data:/data
- mediamtx-recordings:/recordings:ro
depends_on:
- mediamtx
- blossom
mediamtx:
image: docker.io/bluenviron/mediamtx:1.19.2
container_name: podsteadr-mediamtx
restart: unless-stopped
ports:
- "1935:1935" # RTMP ingest
- "8889:8889" # WebRTC / WHIP
- "8189:8189/udp" # WebRTC ICE
- "8890:8888" # HLS (host 8890; 8888 kept free for other apps)
environment:
# Browsers need a reachable ICE host candidate; set PUBLIC_HOST in .env
MTX_WEBRTCADDITIONALHOSTS: ${PUBLIC_HOST:-localhost}
volumes:
- ./mediamtx/mediamtx.yml:/mediamtx.yml:ro
- mediamtx-recordings:/recordings
blossom:
image: ghcr.io/hzrd149/blossom-server:4
container_name: podsteadr-blossom
restart: unless-stopped
ports:
- "8098:3000"
volumes:
- ./blossom/config.yml:/app/config.yml:ro
- blossom-data:/app/data
volumes:
podsteadr-data:
mediamtx-recordings:
blossom-data: