plyr.fm#
music on atproto
check the plyr.fm artist page for the latest auto-generated development podcast!
tech stack
backend#
- framework: FastAPI
- database: Neon PostgreSQL
- storage: Cloudflare R2
- background tasks: docket (Redis-backed)
- hosting: Fly.io
- observability: Pydantic Logfire
- auth: atproto OAuth 2.1
frontend#
- framework: SvelteKit with Svelte 5 runes
- runtime: Bun
- hosting: Cloudflare Pages
- styling: vanilla CSS (lowercase aesthetic)
services#
- moderation: Rust ATProto labeler for copyright/sensitive content
- transcoder: Rust audio conversion service (ffmpeg)
local development
prerequisites#
quick start#
# install dependencies
uv sync
cd frontend && bun install && cd ..
# start dev services (redis for background tasks)
just dev-services
# run backend (hot reloads at http://localhost:8001)
just backend run
# run frontend (hot reloads at http://localhost:5173)
just frontend run
useful commands#
# run tests
just backend test
# run linting
just backend lint
just frontend check
# database migrations
just backend migrate "migration message"
just backend migrate-up
# stop dev services
just dev-services-down
features
listening#
- audio playback with persistent queue across tabs
- like tracks, add to playlists
- browse artist profiles and discographies
- share tracks, albums, and playlists with link previews
- unified search with Cmd/Ctrl+K
- teal.fm scrobbling
creating#
- OAuth authentication via ATProto (bluesky accounts)
- upload tracks with title, artwork, tags, and featured artists
- organize tracks into albums and playlists
- drag-and-drop reordering
- timed comments with clickable timestamps
- artist support links (ko-fi, patreon, etc.)
data ownership#
- tracks, likes, playlists synced to your PDS as ATProto records
- portable identity - your data travels with you
- public by default - any client can read your music records
project structure
plyr.fm/
├── backend/ # FastAPI app
│ ├── src/backend/ # application code
│ │ ├── api/ # public endpoints
│ │ ├── _internal/ # services (auth, atproto, background tasks)
│ │ ├── models/ # database schemas
│ │ └── storage/ # R2 adapter
│ ├── tests/ # pytest suite
│ └── alembic/ # migrations
├── frontend/ # SvelteKit app
│ ├── src/lib/ # components & state
│ └── src/routes/ # pages
├── moderation/ # Rust labeler service
├── transcoder/ # Rust audio service
├── redis/ # self-hosted Redis config
├── docs/ # documentation
└── justfile # task runner
costs
~$20/month:
- fly.io (backend + redis + moderation): ~$14/month
- neon postgres: $5/month
- cloudflare (pages + r2): ~$1/month
- audd audio fingerprinting: $5-10/month (usage-based)
live dashboard: https://plyr.fm/costs
links#
- production: https://plyr.fm
- staging: https://stg.plyr.fm
- API docs: https://api.plyr.fm/docs
- python SDK / MCP server: plyrfm (PyPI)
- documentation: docs/README.md
- status: STATUS.md