1# [plyr.fm](https://plyr.fm) 2 3music on [atproto](https://atproto.com) 4 5check the [plyr.fm artist page](https://plyr.fm/u/plyr.fm) for the latest [auto-generated](.github/workflows/status-maintenance.yml) development podcast! 6 7<details> 8<summary>tech stack</summary> 9 10### backend 11- **framework**: [FastAPI](https://fastapi.tiangolo.com) 12- **database**: [Neon PostgreSQL](https://neon.com) 13- **storage**: [Cloudflare R2](https://developers.cloudflare.com/r2/) 14- **background tasks**: [docket](https://github.com/zzstoatzz/docket) (Redis-backed) 15- **hosting**: [Fly.io](https://fly.io) 16- **observability**: [Pydantic Logfire](https://logfire.pydantic.dev) 17- **auth**: [atproto OAuth 2.1](https://atproto.com/specs/oauth) 18 19### frontend 20- **framework**: [SvelteKit](https://kit.svelte.dev) with Svelte 5 runes 21- **runtime**: [Bun](https://bun.sh) 22- **hosting**: [Cloudflare Pages](https://pages.cloudflare.com) 23- **styling**: vanilla CSS (lowercase aesthetic) 24 25### services 26- **moderation**: Rust ATProto labeler for copyright/sensitive content 27- **transcoder**: Rust audio conversion service (ffmpeg) 28 29</details> 30 31<details> 32<summary>local development</summary> 33 34### prerequisites 35 36- [uv](https://docs.astral.sh/uv/) for Python 37- [bun](https://bun.sh/) for frontend 38- [just](https://github.com/casey/just) for task running 39- [docker](https://www.docker.com/) for dev services (redis) 40 41### quick start 42 43```bash 44# install dependencies 45uv sync 46cd frontend && bun install && cd .. 47 48# start dev services (redis for background tasks) 49just dev-services 50 51# run backend (hot reloads at http://localhost:8001) 52just backend run 53 54# run frontend (hot reloads at http://localhost:5173) 55just frontend run 56``` 57 58### useful commands 59 60```bash 61# run tests 62just backend test 63 64# run linting 65just backend lint 66just frontend check 67 68# database migrations 69just backend migrate "migration message" 70just backend migrate-up 71 72# stop dev services 73just dev-services-down 74``` 75 76</details> 77 78<details> 79<summary>features</summary> 80 81### listening 82- audio playback with persistent queue across tabs 83- like tracks, add to playlists 84- browse artist profiles and discographies 85- share tracks, albums, and playlists with link previews 86- unified search with Cmd/Ctrl+K 87- teal.fm scrobbling 88 89### creating 90- OAuth authentication via ATProto (bluesky accounts) 91- upload tracks with title, artwork, tags, and featured artists 92- organize tracks into albums and playlists 93- drag-and-drop reordering 94- timed comments with clickable timestamps 95- artist support links (ko-fi, patreon, etc.) 96 97### data ownership 98- tracks, likes, playlists synced to your PDS as ATProto records 99- portable identity - your data travels with you 100- public by default - any client can read your music records 101 102</details> 103 104<details> 105<summary>project structure</summary> 106 107``` 108plyr.fm/ 109├── backend/ # FastAPI app 110│ ├── src/backend/ # application code 111│ │ ├── api/ # public endpoints 112│ │ ├── _internal/ # services (auth, atproto, background tasks) 113│ │ ├── models/ # database schemas 114│ │ └── storage/ # R2 adapter 115│ ├── tests/ # pytest suite 116│ └── alembic/ # migrations 117├── frontend/ # SvelteKit app 118│ ├── src/lib/ # components & state 119│ └── src/routes/ # pages 120├── moderation/ # Rust labeler service 121├── transcoder/ # Rust audio service 122├── redis/ # self-hosted Redis config 123├── docs/ # documentation 124└── justfile # task runner 125``` 126 127</details> 128 129<details> 130<summary>costs</summary> 131 132~$20/month: 133- fly.io (backend + redis + moderation): ~$14/month 134- neon postgres: $5/month 135- cloudflare (pages + r2): ~$1/month 136- audd audio fingerprinting: $5-10/month (usage-based) 137 138live dashboard: https://plyr.fm/costs 139 140</details> 141 142## links 143 144- **production**: https://plyr.fm 145- **staging**: https://stg.plyr.fm 146- **API docs**: https://api.plyr.fm/docs 147- **python SDK / MCP server**: [plyrfm](https://github.com/zzstoatzz/plyr-python-client) ([PyPI](https://pypi.org/project/plyrfm/)) 148- **documentation**: [docs/README.md](docs/README.md) 149- **status**: [STATUS.md](STATUS.md) 150 151### mirrors 152- **github**: https://github.com/zzstoatzz/plyr.fm 153- **tangled**: https://tangled.sh/@zzstoatzz.io/plyr.fm