Swara
An original web music player — search, streaming, and library features with its own visual identity, स्वर.
- Next.js 16
- TypeScript
- Tailwind CSS v4
- SQLite
- yt-dlp
Overview
Swara (स्वर) is a from-scratch web music player: search, streaming, artist and album pages, queues, playlists, history, and stats — wrapped in four switchable themes and a YouTube-Music-style listening experience.
It runs as a local server app today (a desktop portable build exists too), so it is presented as a working prototype. Everything listed as built below was implemented and tested, not mocked.
Problem / Goal
I wanted a music player I fully controlled — one where the interface, the themes, and the playback behavior were all mine to design. The question was how far a web app could go: could it feel like a native player while streaming, managing a library, and remembering everything?
Approach
- Server resolves streams (via yt-dlp with a cached 3-hour window) and the browser plays them through a redirect — keeping the client light and the media logic in one place.
- Artist and album metadata from the iTunes Search API, so discovery pages have real data without a proprietary backend.
- Local SQLite for queue, favorites, playlists, and history — the app remembers, privately, on the machine.
Selected features
- Search with artist and album pages (iTunes Search API)Built
- Streaming playback via server-side resolution + 302 redirectBuilt
- Queue, favorites, playlists, listening history and statsBuilt
- Four themes, keyboard shortcuts, Media Session API integrationBuilt
- Desktop portable buildBuilt
- Hosted multi-user deploymentPlanned
Constraints & challenges
Streaming without a streaming license
The honest constraint of the project: playback resolves through publicly available sources via yt-dlp rather than a licensed catalog. The architecture keeps that layer server-side and cacheable, so the client stays a clean player — and the limitation is stated plainly instead of hidden.
Making the web feel native
Keyboard shortcuts, Media Session API hooks for OS-level controls, and instant-feeling navigation were what made it stop feeling like a website. Each was small work with outsized effect on perceived quality.
Outcome & lessons
- 01State the constraint plainly; design around it instead of pretending it isn't there.
- 02A handful of native-feeling details (media keys, shortcuts) sell the whole experience.
- 03Caching the expensive layer (stream resolution) is what makes the app feel fast.