audio streaming app
plyr.fm
1# [plyr.fm](https://plyr.fm)
2
3audio streaming app
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- **transcoder**: Rust audio conversion service (ffmpeg, Fly.io)
27- **moderation**: Rust ATProto labeler for copyright/sensitive content (Fly.io)
28- **mood search**: [CLAP](https://github.com/LAION-AI/CLAP) audio embeddings ([Modal](https://modal.com))
29- **genre classification**: [effnet-discogs](https://replicate.com/) ML tagging ([Replicate](https://replicate.com))
30- **vector search**: [turbopuffer](https://turbopuffer.com) for semantic audio queries
31
32</details>
33
34<details>
35<summary>local development</summary>
36
37### prerequisites
38
39- [uv](https://docs.astral.sh/uv/) for Python
40- [bun](https://bun.sh/) for frontend
41- [just](https://github.com/casey/just) for task running
42- [docker](https://www.docker.com/) for dev services (redis)
43
44### quick start
45
46```bash
47# install dependencies
48uv sync
49cd frontend && bun install && cd ..
50
51# start dev services (redis for background tasks)
52just dev-services
53
54# run backend (hot reloads at http://localhost:8001)
55just backend run
56
57# run frontend (hot reloads at http://localhost:5173)
58just frontend run
59```
60
61### useful commands
62
63```bash
64# run tests
65just backend test
66
67# run linting
68just backend lint
69just frontend check
70
71# database migrations
72just backend migrate "migration message"
73just backend migrate-up
74
75# stop dev services
76just dev-services-down
77```
78
79</details>
80
81<details>
82<summary>features</summary>
83
84### listening
85- audio playback with persistent queue across tabs
86- like tracks, add to playlists
87- browse by artist, album, tag, or playlist
88- share tracks and albums with embeddable players and link previews
89- mood search - describe a vibe, get matching tracks (CLAP embeddings)
90- unified search with Cmd/Ctrl+K (fuzzy match across tracks, artists, albums, tags, playlists)
91- genre browsing and tag filtering
92- platform media controls (Media Session API)
93- teal.fm scrobbling and now-playing reporting
94
95### creating
96- OAuth authentication via ATProto (bluesky accounts), multi-account support
97- upload tracks with title, artwork, tags, and featured artists
98- lossless audio support (AIFF/FLAC) with automatic MP3 transcoding for universal playback
99- auto-tagging via ML genre classification
100- organize tracks into albums and playlists with drag-and-drop reordering
101- timed comments with clickable timestamps
102- artist support links and supporter-gated content
103- copyright scanning via audio fingerprinting
104- content reporting and automated sensitive content filtering
105
106### data ownership
107- tracks, likes, playlists synced to your PDS as ATProto records
108- bulk media export (download all your tracks)
109- portable identity - your data travels with you
110- public by default - any client can read your music records
111
112> some features may be paywalled in the future for the financial viability of the project. if you have thoughts on what should or shouldn't be gated, open a [discussion on GitHub](https://github.com/zzstoatzz/plyr.fm/discussions) or [tangled](https://tangled.sh/@zzstoatzz.io/plyr.fm).
113
114</details>
115
116<details>
117<summary>project structure</summary>
118
119```
120plyr.fm/
121├── backend/ # FastAPI app & Python tooling
122│ ├── src/backend/ # application code
123│ ├── tests/ # pytest suite
124│ └── alembic/ # database migrations
125├── frontend/ # SvelteKit app
126│ ├── src/lib/ # components & state
127│ └── src/routes/ # pages
128├── services/
129│ ├── transcoder/ # Rust audio transcoding (Fly.io)
130│ ├── moderation/ # Rust content moderation (Fly.io)
131│ └── clap/ # ML embeddings (Python, Modal)
132├── infrastructure/
133│ └── redis/ # self-hosted Redis (Fly.io)
134├── docs/ # documentation
135└── justfile # task runner
136```
137
138</details>
139
140<details>
141<summary>costs</summary>
142
143~$25/month:
144- fly.io (backend + transcoder + redis + moderation): ~$14/month
145- neon postgres: $5/month
146- cloudflare (pages + r2): ~$1/month
147- audd audio fingerprinting: $5-10/month (usage-based)
148- modal (CLAP embeddings): free tier / scales to zero
149- replicate (genre classification): <$1/month
150
151live dashboard: https://plyr.fm/costs
152
153</details>
154
155## links
156
157- **docs**: https://docs.plyr.fm
158- **production**: https://plyr.fm
159- **staging**: https://stg.plyr.fm
160- **API docs**: https://api.plyr.fm/docs
161- **python SDK / MCP server**: [plyrfm](https://github.com/zzstoatzz/plyr-python-client) ([PyPI](https://pypi.org/project/plyrfm/))
162- **status**: [STATUS.md](STATUS.md)
163
164### mirrors
165- **github**: https://github.com/zzstoatzz/plyr.fm
166- **tangled**: https://tangled.sh/@zzstoatzz.io/plyr.fm