# [plyr.fm](https://plyr.fm)
audio streaming app
check the [plyr.fm artist page](https://plyr.fm/u/plyr.fm) for the latest [auto-generated](.github/workflows/status-maintenance.yml) development podcast!
tech stack
### backend
- **framework**: [FastAPI](https://fastapi.tiangolo.com)
- **database**: [Neon PostgreSQL](https://neon.com)
- **storage**: [Cloudflare R2](https://developers.cloudflare.com/r2/)
- **background tasks**: [docket](https://github.com/zzstoatzz/docket) (Redis-backed)
- **hosting**: [Fly.io](https://fly.io)
- **observability**: [Pydantic Logfire](https://logfire.pydantic.dev)
- **auth**: [atproto OAuth 2.1](https://atproto.com/specs/oauth)
### frontend
- **framework**: [SvelteKit](https://kit.svelte.dev) with Svelte 5 runes
- **runtime**: [Bun](https://bun.sh)
- **hosting**: [Cloudflare Pages](https://pages.cloudflare.com)
- **styling**: vanilla CSS (lowercase aesthetic)
### services
- **transcoder**: Rust audio conversion service (ffmpeg, Fly.io)
- **moderation**: Rust ATProto labeler for copyright/sensitive content (Fly.io)
- **mood search**: [CLAP](https://github.com/LAION-AI/CLAP) audio embeddings ([Modal](https://modal.com))
- **genre classification**: [effnet-discogs](https://replicate.com/) ML tagging ([Replicate](https://replicate.com))
- **vector search**: [turbopuffer](https://turbopuffer.com) for semantic audio queries
local development
### prerequisites
- [uv](https://docs.astral.sh/uv/) for Python
- [bun](https://bun.sh/) for frontend
- [just](https://github.com/casey/just) for task running
- [docker](https://www.docker.com/) for dev services (redis)
### quick start
```bash
# 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
```bash
# 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 by artist, album, tag, or playlist
- share tracks and albums with embeddable players and link previews
- mood search - describe a vibe, get matching tracks (CLAP embeddings)
- unified search with Cmd/Ctrl+K (fuzzy match across tracks, artists, albums, tags, playlists)
- genre browsing and tag filtering
- platform media controls (Media Session API)
- teal.fm scrobbling and now-playing reporting
### creating
- OAuth authentication via ATProto (bluesky accounts), multi-account support
- upload tracks with title, artwork, tags, and featured artists
- lossless audio support (AIFF/FLAC) with automatic MP3 transcoding for universal playback
- auto-tagging via ML genre classification
- organize tracks into albums and playlists with drag-and-drop reordering
- timed comments with clickable timestamps
- artist support links and supporter-gated content
- copyright scanning via audio fingerprinting
- content reporting and automated sensitive content filtering
### data ownership
- tracks, likes, playlists synced to your PDS as ATProto records
- bulk media export (download all your tracks)
- portable identity - your data travels with you
- public by default - any client can read your music records
> 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).
project structure
```
plyr.fm/
├── backend/ # FastAPI app & Python tooling
│ ├── src/backend/ # application code
│ ├── tests/ # pytest suite
│ └── alembic/ # database migrations
├── frontend/ # SvelteKit app
│ ├── src/lib/ # components & state
│ └── src/routes/ # pages
├── services/
│ ├── transcoder/ # Rust audio transcoding (Fly.io)
│ ├── moderation/ # Rust content moderation (Fly.io)
│ └── clap/ # ML embeddings (Python, Modal)
├── infrastructure/
│ └── redis/ # self-hosted Redis (Fly.io)
├── docs/ # documentation
└── justfile # task runner
```
costs
~$25/month:
- fly.io (backend + transcoder + redis + moderation): ~$14/month
- neon postgres: $5/month
- cloudflare (pages + r2): ~$1/month
- audd audio fingerprinting: $5-10/month (usage-based)
- modal (CLAP embeddings): free tier / scales to zero
- replicate (genre classification): <$1/month
live dashboard: https://plyr.fm/costs
## links
- **docs**: https://docs.plyr.fm
- **production**: https://plyr.fm
- **staging**: https://stg.plyr.fm
- **API docs**: https://api.plyr.fm/docs
- **python SDK / MCP server**: [plyrfm](https://github.com/zzstoatzz/plyr-python-client) ([PyPI](https://pypi.org/project/plyrfm/))
- **status**: [STATUS.md](STATUS.md)
### mirrors
- **github**: https://github.com/zzstoatzz/plyr.fm
- **tangled**: https://tangled.sh/@zzstoatzz.io/plyr.fm