# lyssnarr — plan ## Goal Self-hosted music-discovery web app on the Pi5. A Jellyseerr-style UI where Björn can (a) search for new artists, albums and tracks, and (b) get **scheduled** AI-generated suggestions based on two taste signals: recent listening in the local library (Jellyfin) and tracks recently added to his YouTube Music playlists (via Youtubarr's data). Every result can be added to Lidarr with one click, opened in YouTube Music, or played inline in the app. ## Stack - **Backend:** Node ≥ 20, Fastify, better-sqlite3 (suggestion history + feedback), node-cron (scheduled generation) - **Frontend:** Vue 3 + Vite; dark, poster/card-based UI modelled on Jellyseerr (top search bar, discover grid, action buttons per card); built to static files served by the backend - **Container:** single arm64 image, multi-stage Dockerfile (frontend build → backend deps → slim runtime), mirrors Archivum ## Deploy target Pattern B (container on Pi5): Gitea Actions on the Pi5 runner → `localhost:5000/lyssnarr:latest` → Dockge stack `/srv/dockge-staks/lyssnarr/` → NPM vhost `https://lyssnarr.brasse-pc.eu` (public from day one → the app ships with login from day one: single user, bcrypt-hashed password from the stack `.env`, signed session cookie). ## Integrations | What | How | |------|-----| | **Lidarr** | REST API (`http://lidarr:8686`): add/monitor artists & albums, check what's already in the library | | **MusicBrainz** | search + canonical MBIDs (Lidarr adds are MBID-based) | | **YouTube Music** | unofficial YT Music search from Node → browse/video IDs for "open in YT Music" deep links, thumbnails for the cards, inline playback via YouTube IFrame embed | | **Gemini API** | suggestion generation; `GEMINI_API_KEY` + model via env | | **Youtubarr** | read-only mount of its SQLite (`/srv/docker/youtubarr/data/db.sqlite3`) → "recently added to playlists" signal | | **Jellyfin** | play-history signal — blocked until a music library exists in Jellyfin (milestone 6) | ## UI sketch (Jellyseerr-like) - Top: search bar with artist/album/track scope - Landing "Upptäck": latest suggestion batch as poster cards, each with Gemini's one-line motivation - Card actions: **➕ Lidarr** · **▶ Spela** (inline YouTube embed) · **↗ YT Music** (deep link) - Badge on cards already in the Lidarr library - History page with earlier batches ## Milestones 1. **Skeleton end-to-end** — repo, CI, Dockerfile, dockge stack, NPM vhost, login; an empty authenticated shell reachable on `lyssnarr.brasse-pc.eu` 2. **Lidarr integration** — library state + add/monitor actions 3. **Search page** — MusicBrainz search enriched with YT Music thumbnails/links, add/play/open actions 4. **On-demand suggestions** — "generera nu": Gemini prompt built from Lidarr library + Youtubarr playlist adds 5. **Scheduler + history** — cron-generated batches, history page 6. **Jellyfin signal** — recent music plays feed the prompt (requires music library in Jellyfin) ## Roadmap / expansions (proposed — Björn confirms/strikes) - 👍/👎 feedback per suggestion, fed into the next Gemini prompt - Auto-add top suggestions to Lidarr as monitored (configurable) - Track-level batches exported as M3U playlists into Jellyfin - Library profile page (genre/decade distribution) - Webhook/notification when a new batch lands - Liked Music as a direct signal (ytmusicapi sidecar or Node port) ## Open questions - Gemini model: default `gemini-2.5-flash`, configurable via env — ok? - Auth: built-in single-user login vs Authentik forward-auth later - Artwork order: YT Music thumbnails first, Cover Art Archive fallback