3d5de06b44
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>
161 lines
9.1 KiB
Markdown
161 lines
9.1 KiB
Markdown
# 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
|