diff --git a/family/projects/watchlist-sync.md b/family/projects/watchlist-sync.md new file mode 100644 index 00000000..6fee0cc2 --- /dev/null +++ b/family/projects/watchlist-sync.md @@ -0,0 +1,252 @@ +--- +created: '2026-05-18' +updated: '2026-05-18' +status: planning +tags: + - kraken + - jellyfin + - radarr + - sonarr + - watchlist + - project +--- +# Watchlist Sync + +> Цель: автоматическая загрузка непросмотренных фильмов/сериалов из `family/documents/movies-watchlist.md` через Radarr/Sonarr, синхронизация просмотренных обратно из Jellyfin, и AI-curated рекомендации на основе профиля. + +Репо: `~/Developer/watchlist-sync` → GitHub `mallexxx/watchlist-sync` + +--- + +## Архитектура + +``` +movies-watchlist.md (Obsidian vault) + │ + ▼ +watchlist-sync (Python CLI) + ├── parse — читает .md, классифицирует [ ] / [x] / ❓ / ⬇️ + ├── resolve — TMDB + KP API → находит ID, тип (movie/series), рейтинг + ├── sync-down — непросмотренные → Radarr / Sonarr (батчами) + └── sync-up — Jellyfin watched history → [x] в .md + перемещение наверх + │ + ▼ +Hermes Kraken cron job + ├── каждые 6ч: resolve ❓ → LLM disambiguation → уточнение у Alex + └── каждые 24ч: sync-up из Jellyfin +``` + +--- + +## Stage 1: Core Sync + +### 1.1 Парсинг watchlist.md + +**Формат строк:** +- `- [ ] Название` — непросмотрено, не добавлено +- `- [ ] ⬇️ Название` — добавлено в очередь (скачивается/скачано) +- `- [ ] ❓ Название` — ambiguous, ждёт ручного уточнения +- `- [x] Название` — просмотрено + +**Источник файла на Кракене:** `/home/kraken/obsidian/family/documents/movies-watchlist.md` +(vault смонтирован в Hermes-контейнере как `/vault`) + +### 1.2 Резолв названий (TMDB + KP) + +**Алгоритм:** +1. Для каждого `- [ ]` без `⬇️` и `❓` — запрос к TMDB `/search/multi` (русский язык) +2. Если 0 результатов → fallback KP `/v1.4/movie/search?query=...` +3. **Однозначный результат** (score > 0.8, рейтинг ≥ 6.0, один кандидат) → определить тип (movie/tv), взять ID +4. **Ambiguous** (несколько кандидатов с близким score, или score < 0.8) → добавить `❓` перед названием, пропустить +5. **Не найдено** → добавить `❓`, пропустить + +**Пороги:** +- `min_rating: 6.0` — ниже 6 игнорировать (защита от мусора) +- `min_score: 0.75` — сходство названия (Jaccard/fuzzy) +- `max_candidates_for_auto: 1` — при 2+ близких кандидатах → ambiguous + +**Тип контента:** +- TMDB `media_type: movie` → Radarr +- TMDB `media_type: tv` → Sonarr +- KP `type: MOVIE/MINI_SERIES/TV_SERIES` → маппинг аналогично + +### 1.3 Загрузка (sync-down) + +**Батчинг:** +- Максимум **5 новых** в одном прогоне (защита от flood) +- Приоритет: порядок в файле (выше = важнее) +- После добавления в Radarr/Sonarr → заменить `- [ ]` на `- [ ] ⬇️` в .md + +**API:** +- Radarr: `POST /api/v3/movie` с `addOptions.searchForMovie: true` +- Sonarr: `POST /api/v3/series` с `addOptions.searchForMissingEpisodes: true` +- Проверка дублей перед добавлением (GET by tmdbId/tvdbId) + +**Конфиг** (`.env` / `config.json`, не в репо): +``` +RADARR_URL=http://localhost:7878 +RADARR_KEY=... +SONARR_URL=http://localhost:8989 +SONARR_KEY=... +TMDB_KEY=... +KP_KEY=... +JELLYFIN_URL=http://localhost:8096 +JELLYFIN_TOKEN=... +WATCHLIST_PATH=/vault/family/documents/movies-watchlist.md +``` + +### 1.4 Обратная синхронизация (sync-up) + +**Алгоритм:** +1. Jellyfin API: `GET /Users/{userId}/Items?IsPlayed=true&IncludeItemTypes=Movie,Series` +2. Для каждого просмотренного — fuzzy-match по названию с `⬇️` строками в .md +3. При совпадении (score > 0.85): + - Заменить `- [ ] ⬇️ Название` → `- [x] Название` + - Переместить строку на **первое место** среди `[x]` записей (под последней `[ ]`) +4. Обновить `.md`, git commit + +**Jellyfin userId:** получать через `GET /Users` (admin user = alex) + +### 1.5 AI Curation Job (Hermes Kraken) + +**Cron: каждые 6 часов** + +Промпт агенту на Кракене: +1. Прочитать `.md`, найти все `❓` строки +2. Для каждой — запросить TMDB/KP с расширенными вариантами запроса (LLM генерирует варианты: оригинальное название, транслит, английский перевод) +3. Если нашёл с уверенностью → убрать `❓`, поставить `⬇️` +4. Если нет → собрать список всех нерезолвленных и спросить Alex в Zulip `#personal::Kraken torrents`: + ``` + ❓ Не смог распознать 3 фильма, уточни: + • "Дворец полански" — возможно "The Palace" (Polanski, 2023)? [да/нет/другое] + • "Space merchants" — фильм или книга Пола? Нашёл несколько. + • "Ради нескольких строчек" — не нашёл. Уточни название. + ``` + +--- + +## Stage 2: Profile & Recommendations + +> После накопления истории просмотров (≥ 50 фильмов) + +### 2.1 Анализ профиля + +- Топ жанры по просмотренным `[x]` +- Любимые режиссёры / актёры (через TMDB credits) +- Средний рейтинг принятых фильмов +- Паттерны: когда смотрит (с женой / один / семья) — вывести из тегов/времени просмотра в Jellyfin + +### 2.2 Curated Lists (AI job, еженедельно) + +Три списка, **только рейтинг ≥ 6.0**, **не в watchlist уже**: + +| Список | Критерии | +|--------|----------| +| 🎬 Вдвоём с Лизой | Драма, комедия, триллер. Без слишком тяжёлого контента. | +| 💀 Один (трэш/боевики) | Хоррор, боевик, sci-fi, cult. Без ограничений. | +| 👨‍👩‍👧 Семейное с ребёнком | Возраст 7+. Мультфильмы, приключения, комедии. | + +**Источники кандидатов:** +- TMDB `/movie/recommendations` на основе топ-10 просмотренных +- TMDB `/movie/similar` для любимых жанров +- KP подборки (русское кино / советская классика) + +**Формат вывода** — добавить в конец `movies-watchlist.md`: +```markdown +## 🤖 Рекомендации (2026-W21) + +### 🎬 Вдвоём +- [ ] Past Lives (2023) ★8.0 — драма о двух корейцах разлучённых в детстве +... + +### 💀 Один +- [ ] Nosferatu (2024) ★7.2 — ремейк Эгgers'а +... + +### 👨‍👩‍👧 Семья +- [ ] The Wild Robot (2024) ★8.1 — анимация +... +``` + +После подтверждения Alex — строки перемещаются в основной список. + +--- + +## Структура проекта + +``` +~/Developer/watchlist-sync/ +├── watchlist_sync/ +│ ├── __init__.py +│ ├── parser.py — парсинг .md +│ ├── resolver.py — TMDB + KP API +│ ├── radarr.py — Radarr API client +│ ├── sonarr.py — Sonarr API client +│ ├── jellyfin.py — Jellyfin API client +│ ├── sync_down.py — непросмотренные → arr +│ ├── sync_up.py — Jellyfin → .md +│ └── recommend.py — Stage 2 recommendations +├── config.example.json — шаблон конфига (без секретов) +├── .env.example +├── .gitignore — .env, config.json, *.key +├── pyproject.toml +└── README.md +``` + +**Конфиг секреты:** только в `.env` (не в репо). `config.example.json` — шаблон. + +--- + +## Имплементация: очерёдность задач + +### Фаза 1 (MVP) +- [ ] Инициализировать репо `~/Developer/watchlist-sync`, push на GitHub +- [ ] `parser.py` — парсинг .md, классификация строк +- [ ] `resolver.py` — TMDB `/search/multi` + KP fallback +- [ ] `sync_down.py` — add to Radarr/Sonarr (батч 5), пометить `⬇️` +- [ ] CLI: `watchlist-sync resolve --dry-run` и `--apply` +- [ ] CLI: `watchlist-sync sync-down --batch 5` + +### Фаза 2 +- [ ] `sync_up.py` — Jellyfin → `[x]` + сортировка +- [ ] CLI: `watchlist-sync sync-up` +- [ ] Cron на Кракене: sync-up каждые 24ч + +### Фаза 3 +- [ ] AI disambiguation job (Hermes Kraken cron) +- [ ] Уточнение у Alex через Zulip для нерезолвленных + +### Фаза 4 (Stage 2) +- [ ] `recommend.py` — профиль + TMDB recommendations +- [ ] Три curated списка с подтверждением +- [ ] Еженедельный cron job + +--- + +## Ключи и секреты + +| Секрет | Где хранить | +|--------|-------------| +| TMDB API key | `.env` на Кракене (из `config.json` media-pipeline) | +| KP API key | `.env` (тот же что в media-pipeline config.json) | +| Radarr key | `.env` | +| Sonarr key | `.env` | +| Jellyfin token | `.env` | + +Ключи TMDB/KP уже есть в `/srv/.../docker/media-pipeline/config.json` — взять оттуда при деплое. + +`.gitignore`: +``` +.env +config.json +*.key +__pycache__/ +.venv/ +``` + +--- + +## Связанные проекты + +- [[family/projects/media-toolbox-kraken]] — *arr стек, Jellyfin, media-pipeline +- [[family/documents/movies-watchlist]] — источник данных diff --git a/work/briefs/inbox/2026-05-18.md b/work/briefs/inbox/2026-05-18.md index 572d2d37..1d670716 100644 --- a/work/briefs/inbox/2026-05-18.md +++ b/work/briefs/inbox/2026-05-18.md @@ -1,33 +1,30 @@ -## Inbox Triage — 2026-05-18 (since 2026-05-15T19:37:29) +## Inbox Triage — 2026-05-18 (since 09:34) ### New / Changed — Action Required -**[Ship Review]** — [Ship Review: iOS: Demo tracker blocking after chat in onboarding - 2-5 days](https://app.asana.com/0/0/1214147157456478) *(overdue since May 15)* -- **Costas** (Sun May 17, 13:07): @mentioned you + one other: "If the 3 tasks below are wrapped and QA passed, feel free to mark them complete and merge — even before Design Review is approved." Also asks to **port uncompleted tasks** to follow-up project → [1214592943696234](https://app.asana.com/1/137249556945/project/1208671677432066/task/1214592943696234) - - 3 tasks to check: [1214828145455319](https://app.asana.com/1/137249556945/project/1202406491309510/task/1214828145455319), [1214682678629766](https://app.asana.com/1/137249556945/project/1202406491309510/task/1214682678629766), [1214683268207886](https://app.asana.com/1/137249556945/project/1202926619948002/task/1214683268207886) -- **Alessandro** (Mon May 18, 06:01): Running another round of tests today, will share update. -- **Action**: Verify 3 tasks are complete + QA passed → merge. Port any uncompleted tasks to follow-up project. +**[@mention]** — [DRI <> Project Advisor async for Demo tracker blocking after chat in onboarding](https://app.asana.com/0/0/1213551072611261) — Alessandro at 09:35 ---- +Context: Alessandro summarised the remaining tasks for the Ship Review and tagged Alex with a specific action list: +1. Mark addressed issues as completed so they're visible to everyone +2. Disable the previous experiment and create a new experiment payload named `onboardingDuckAIQueryTrackersDemoExperiment` (per [this task](https://app.asana.com/1/137249556945/project/1214157224317277/task/1214601039604921)) +3. Merge the stacked [PR #4584](https://github.com/duckduckgo/apple-browsers/pull/4584) into the main feature branch for final testing +4. Move any unaddressed nice-to-have tasks to the follow-up project +5. Note: Alex is macOS maintenance DRI this week — delegate investigations where possible and keep focus on closing the Ship Review -**[@mention]** — [DRI <> Project Advisor async for iOS Address onboarding conflicts with unified input and ship AI onboarding winner](https://app.asana.com/0/0/1214592851898717) — Alessandro at Mon May 18, 05:22 -Context: "would probably be good to create a task with all the design questions and assign it to [designer] so he can go through them once he's back. Given you are both out, should we have an async kick-off for this one?" -Action: Respond — confirm or propose async kick-off; create a design questions task and assign to designer. +**Completed Must-Haves (per Alessandro):** +- ✅ Address Bar Toggle Selection: Revert Copy — addressed in [PR #4855](https://github.com/duckduckgo/apple-browsers/pull/4855) +- ✅ GJ7/ Fix address bar focus dismissing search suggestion dialog — resolved, cannot reproduce +- ✅ GJ8/ Change "Duck.ai" to "Ask AI" — addressed in PR #4855 +- ✅ Related task — addressed in PR #4855 -**[@mention]** — [DRI <> Project Advisor async…](https://app.asana.com/0/0/1214592851898717) — Costas at Sun May 17, 12:57 -Context: "would you mind focused on items that require less design/UX input this week, and ping me on anything that does — so I can prioritize it once working w/c 25th May." -Action: Acknowledge — plan to focus on non-design items; flag any design-dependent blockers. +**⏭️ Still in progress (Must Have):** [GJ7-related task](https://app.asana.com/1/137249556945/project/1206329551987282/task/1214682678629768) -**[@mention]** — [DRI <> Project Advisor async…](https://app.asana.com/0/0/1214592851898717) — Gary at Sat May 16, 06:02 -Context: June 15 deadline to ship experiment #1 treatment b (compatible with O-J unified input). Gary wants this kicked off Tuesday. Alessandro is advising. Asks Alex to coordinate with O-J release train. -Action: Coordinate with O-J team on timeline; plan kick-off this week. - ---- - -**[New Assignment]** — [macOS App Maintenance](https://app.asana.com/0/0/1214837564647979) *(due May 22)* — assigned by Rachel M at Fri May 15, 20:47 -Context: Rachel M handing maintenance over to you. Ongoing: rebranding fix in progress ([task](https://app.asana.com/1/137249556945/project/1199230911884351/task/1214816707188281)). Also FYI: reports of [visible issue](https://app.asana.com/1/137249556945/project/1204912272578138/task/1214650828403479) being handled. -Action: Acknowledge handover; monitor rebranding fix; be aware of visible issue reports. +**Nice to Haves** (move to follow-up if unaddressed): +- Try a Search or AI chat: Remove pointer +- You've Got This!: Remove pointer +- Try Visiting a Site: Remove Browser Toolbar +- Try Visiting a Site: Background ### New / Changed — Monitoring -- **[Tech input] Permissions on iOS** (task [1214732727456025](https://app.asana.com/0/0/1214732727456025)) — Sveta asked Alex on May 15; Brindy subsequently redirected to Tom Strba as the owner. No action needed from Alex — Tom is handling. Due today (May 18). +_(nothing new)_