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 dev 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├── docs/ # documentation 123└── justfile # task runner 124``` 125 126</details> 127 128<details> 129<summary>costs</summary> 130 131~$35-40/month: 132- fly.io backend (prod + staging): ~$10/month 133- fly.io transcoder: ~$0-5/month (auto-scales to zero) 134- neon postgres: $5/month 135- audd audio fingerprinting: ~$10/month 136- cloudflare (pages + r2): ~$0.16/month 137 138</details> 139 140## links 141 142- **production**: https://plyr.fm 143- **staging**: https://stg.plyr.fm 144- **API docs**: https://api.plyr.fm/docs 145- **python SDK / MCP server**: [plyrfm](https://github.com/zzstoatzz/plyr-python-client) ([PyPI](https://pypi.org/project/plyrfm/)) 146- **documentation**: [docs/README.md](docs/README.md) 147- **status**: [STATUS.md](STATUS.md) 148 149### mirrors 150- **github**: https://github.com/zzstoatzz/plyr.fm 151- **tangled**: https://tangled.sh/@zzstoatzz.io/plyr.fm