Initial commit — Movie Night media discovery app

AI-powered web app that recommends unwatched movies from a Jellyfin
library based on natural language mood input. Jellyfin auth, modular
LLM backend (Claude/OpenAI/Ollama), two-tier pre-filter + AI ranking,
mobile-responsive dark theme UI with poster cards and deep links.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-14 19:20:56 -07:00
commit 3d5de06b44
30 changed files with 1881 additions and 0 deletions
+160
View File
@@ -0,0 +1,160 @@
# Media Discovery Tool — Research & Planning
## Problem Statement
With ~32TB of media (mostly movies and TV shows), choosing what to watch has become its own challenge. The goal is a simple, AI-powered tool that:
- Knows what's in the library and what's been watched
- Accepts natural language mood/theme descriptions ("light fun movie after a hard week", "pizza and movie night with the kids")
- Recommends unwatched titles that match
- Optionally: swipe/card UI for browsing picks together
---
## Landscape Scan (March 2026)
### Tinder-Style Swipe Apps
| Project | Jellyfin? | AI? | Status | Notes |
|---------|-----------|-----|--------|-------|
| **[Swiparr](https://github.com/m3sserstudi0s/swiparr)** | Yes (+ Plex, Emby, TMDb) | No | Active (~299 stars), Docker support | Best swipe project for our stack. Group sessions where multiple users swipe and get matched on shared picks. Mobile-first PWA. **No mood/AI layer.** |
| **[MovieMatch](https://github.com/LukeChannings/moviematch)** | No (Plex only) | No | Mature, last update ~Aug 2025 | The original "Tinder for Plex." Multiple users swipe, matches appear on agreement. |
| **[Plexensus](https://github.com/OperationFman/Plexensus)** | No (Plex only) | No | Smaller, less maintained | Similar concept to MovieMatch. |
**Verdict:** Swiparr is the closest to what we'd want for a swipe UI, but none of these have any AI/mood-based filtering. They just shuffle the deck randomly.
### AI/LLM-Powered Recommendation Tools
| Project | Jellyfin? | Mood Input? | LLM Support | Status | Notes |
|---------|-----------|-------------|-------------|--------|-------|
| **[Recommendarr](https://github.com/fingerthief/recommendarr)** | Yes (+ Plex, Radarr, Sonarr) | Yes | OpenAI, Ollama, LM Studio, any OpenAI-compatible | **Repo deleted/private — avoid** | Was the closest to what we wanted. GitHub repo returns 404 as of March 2026. Possibly related to huntarr supply-chain incident. |
| **[SuggestArr](https://github.com/giuseppe99barchetta/SuggestArr)** | Yes (+ Plex, Emby) | Yes (natural language search) | OpenAI, Ollama, Gemini, LiteLLM | Active (v2.4.3, 1.1k stars, MIT) | Clean project, no security concerns. **Deployed and tested.** AI search works but the tool is focused on suggesting *new content to add* via Jellyseerr, not discovering what's already in the library. Keeping deployed for its content pipeline use case. |
| **[Discovarr](https://github.com/sqrlmstr5000/discovarr)** | Yes (+ Plex) | Partial | Gemini, OpenAI-compatible | Smaller, less mature | FastAPI + Vue.js. Tracks watch history. |
| **[PlexIs](https://github.com/JulesMellot/PlexIs)** | Yes (+ Plex) | Theme/keyword search | GROQ, Ollama, OpenAI | Active | AI-powered *collection* manager — creates themed collections, not a recommendation UI. |
| **[plex-recommendations-ai](https://github.com/rocstack/plex-recommendations-ai)** | No (Plex only) | No | OpenAI | Smaller | Auto-creates a Plex collection with AI picks. ~$0.01/day. |
### Jellyfin-Native Plugins
| Plugin | Approach | Notes |
|--------|----------|-------|
| **[LocalRecs](https://github.com/rdpharr/jellyfin-plugin-localrecs)** | TF-IDF + cosine similarity | Privacy-first, no cloud. Per-user virtual libraries. Handles 2,000+ items. No LLM, no mood input. |
| **[JellyNext](https://github.com/luall0/jellynext)** | Trakt-powered recommendations | Links Trakt account, creates per-user virtual libraries. One-click Jellyseerr downloads. Not AI-based. |
| **Jellyfin built-in** | Basic "because you watched X" | Limited. [Feature request](https://features.jellyfin.org/posts/2737) open for a local recommendation engine. |
### Other Interesting Patterns
- **[plex-recommendation](https://github.com/wgeorgecook/plex-recommendation)** — RAG-powered (LangChain in Go), feeds watch history into LLM chain with Postgres caching
- **[MovieGPT](https://github.com/rafaelpierre/moviegpt)** — RAG + vector DB for semantic movie search (not library-integrated)
- **[AudioMuse AI](https://brainsteam.co.uk/2025/8/16/smart-jellyfin-playlists-AudioMuseAI/)** — Music, not movies, but interesting: describes mood in English → converts to SQL queries against Jellyfin. Same pattern we'd want.
---
## Evaluation Results (March 14, 2026)
### Deployed & Tested
| Tool | Status | Verdict |
|------|--------|---------|
| **Swiparr** | Deployed on bondelie-media (port 4321) | Fun swipe UI, good for "both swipe and match" sessions. No AI. **Keeping.** |
| **SuggestArr** | Deployed on bondelie-media (port 5100) | AI search works but focused on adding new content via Jellyseerr, not browsing existing library. **Keeping for content pipeline.** |
| **Recommendarr** | Deployed, then removed | GitHub repo gone (404). Registration required undocumented curl workaround. Likely related to huntarr incident. **Removed.** |
### Conclusion
**No existing tool solves our core problem:** "Tell me what mood you're in and I'll recommend something unwatched from your existing library."
- Swiparr does swipe UI but no intelligence
- SuggestArr does AI but for adding new content, not browsing existing
- Recommendarr is dead
- Jellyfin plugins are too basic (no natural language, no mood)
**Decision: Build a custom tool.**
---
## Custom Build — Integration Points on bondelie-media
### Jellyfin API (port 8096)
- `GET /Users/{userId}/Items` — Full library listing with metadata
- `GET /Users/{userId}/Items?IsPlayed=false` — Unwatched items
- `GET /Users/{userId}/Items?IsPlayed=true` — Watch history
- `GET /Items/{itemId}` — Detailed metadata (genres, cast, overview, ratings, year)
- `GET /Items/{itemId}/Images` — Poster art for card UI
- Watch status per user (Kenny vs. wife may have different watch states)
### Radarr API (port 7878)
- `GET /api/v3/movie` — All movies with TMDb metadata, quality info, file paths
- Rich metadata: genres, ratings, year, overview, studio, runtime
### Sonarr API (port 8989)
- `GET /api/v3/series` — All TV series with TVDb metadata
- Episode-level tracking (partially watched shows)
### Jellystat API (port 3004)
- Viewing statistics — what's been watched most, recently, etc.
- Could inform "you haven't watched anything like X in a while" suggestions
## Custom Build — Proposed MVP Architecture
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Simple Web UI │────▶│ Python Backend │────▶│ Claude API │
│ (mood input) │◀────│ (FastAPI) │◀────│ (matching) │
└─────────────────┘ └──────────────────┘ └─────────────┘
│ ▲
▼ │
┌──────────────────┐
│ Jellyfin API │
│ Radarr API │
│ (library + art) │
└──────────────────┘
```
### Flow
1. User opens app, types mood: "pizza and movie night with the kids"
2. Backend fetches unwatched movies from Jellyfin (with metadata + posters)
3. Backend sends movie list + mood to Claude API
4. Claude returns ranked recommendations with brief explanations
5. UI shows top picks with posters, ratings, year, and "why this fits"
6. Pick one and deep link to Jellyfin to start watching
### Tech Stack (Proposed)
- **Backend:** Python 3.12 + FastAPI
- **Frontend:** Simple HTML/CSS/JS (or Svelte for reactivity) — not a heavy framework
- **AI:** Anthropic Claude API (claude-sonnet-4-6 for speed/cost)
- **Data:** On-demand Jellyfin API calls, cached locally (SQLite or just JSON)
- **Deployment:** Docker Compose on bondelie-media
## Key Design Questions for Custom Build
1. **Movies only for MVP, or include TV shows?**
- Movies are simpler (watched/not watched is binary)
- TV shows have partial progress complexity
2. **Per-user or household?**
- Jellyfin tracks watch state per user
- "Unwatched by both" is the sweet spot for movie night
3. **Claude API vs. local LLM (Ollama)?**
- Claude API: better quality, simple, costs pennies per query
- Ollama: free, private, but needs good hardware and more tuning
4. **How much metadata to send to the LLM?**
- Full library could be thousands of movies — pre-filter by genre/year first?
- Or cache embeddings and do semantic search before LLM ranking?
5. **Caching strategy?**
- Library metadata doesn't change often — cache and refresh periodically?
- Watch state changes more frequently
## Next Steps
- [x] Deploy Swiparr on bondelie-media — done, keeping
- [x] Deploy SuggestArr on bondelie-media — done, keeping for content pipeline
- [x] Deploy Recommendarr — done, removed (dead project)
- [x] Decide build vs. adopt — **building custom**
- [ ] Plan custom build architecture
- [ ] Set up project scaffolding
- [ ] Get API keys from Jellyfin
- [ ] Prototype Claude API with sample movie metadata + mood prompts
- [ ] Build UI
- [ ] Dockerize and deploy