Files
obsidian-vault/family/projects/media-toolbox-kraken.md
T

235 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
created: '2026-05-13'
updated: '2026-05-14'
status: in-progress
tags:
- kraken
- media
- jellyfin
- transmission
- swift
- project
---
# Media Toolbox на Кракене
> Цель: полноценный медиасервер на Кракене (RPi 5) — перенос библиотеки с HTPC, автосортировка через media-pipeline (Swift), Jellyfin, торренты.
---
## Архитектура (целевая)
```
HTPC (Bazzite 192.168.1.86)
└── rsync → Kraken HDD /srv/.../media/
Kraken (RPi 5, 192.168.1.14)
├── /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/media/
│ ├── movies/ ← фильмы (127 папок)
│ ├── cartoons/ ← мультфильмы (126 папок)
│ ├── series/ ← сериалы (45 папок)
│ ├── documentaries/ ← документальные (35 папок)
│ └── downloads/complete ← Transmission
├── Docker: Transmission (128 торрентов, порт 9091)
├── Jellyfin native (порт 8096)
└── Docker: media-pipeline:kraken (Swift CLI, arm64)
media-pipeline (~/Developer/media_files_db, ветка kraken-agent)
├── scan → resolve → apply (sync)
├── NFO-файлы для Jellyfin/Kodi
├── Transmission RPC для обновления путей
└── unresolved.json — реестр нераспознанных
```
---
## Текущий статус (2026-05-14, сессия 5)
### Sync результаты (последний запуск — dry_run=false)
| Категория | Resolved | Unresolved | Статус |
|-----------|----------|------------|--------|
| movies | ✅ | 2 (generation.p, Black Mirror dup) | NFO пишутся |
| series | ✅ | 1 (Black Mirror — homonym) | NFO пишутся |
| cartoons | ✅ | 6 | в работе |
| documentaries | ✅ | 6 | Tier 4 запускается |
| **Итого** | **401** | **15** | sync запущен |
> `dry_run` выключен (2026-05-14), запущен `sync` — NFO пишутся на диск.
### Что работает
- ✅ Docker образ `media-pipeline:kraken` задеплоен (ветка `kraken-agent`)
- ✅ Фильмы: 127/127 NFO
- ✅ Сериалы: все resolved (Black Mirror, Ну погоди!, и др. — через resolve-manual)
- ✅ Кеш API-ответов: `/config/cache`, 30-дневный TTL
- ✅ Transmission download-complete hook установлен
-`resolve-manual` работает для movie/series/single-file
### Открытые задачи
#### 1. 🔴 [ОБЯЗАТЕЛЬНО К ИСПОЛНЕНИЮ] Довести media-pipeline до 0 unresolved без resolve-manual
**Принцип:** `resolve-manual` — не решение. Тул должен резолвить всё автоматически.
**Текущее состояние:** 32 unresolved после sync (dry_run=false). Разбивка:
**Группа A — старые source-папки (scan подхватывает оригиналы после apply):**
`apply` создаёт canonical папки с симлинками, но оригинальные папки (`flow.aka.straume...`, `bezumnyj_maks_3...` и т.д.) остаются и при следующем scan снова попадают в unresolved. Это архитектурный баг.
- **Нужно:** scanner должен пропускать папки, чьи файлы уже используются как цели симлинков в canonical структуре (или: хранить список resolved source-paths в unresolved.json и пропускать их при scan).
**Группа B — мультики (tie/ambiguity):**
`козленок`, `тигренок`, `нехочуха.xvid`, `чебурашка.m4v`, `котенок по имени гав.m4v`, `25е - первый день`, `рики тики тави`, `приключения фунтика`, `незнайка`, `миграция`
- Причины: KP возвращает несколько кандидатов с одинаковым весом (tie), или IMDB/web search не находит по транслитерации.
- **Нужно:** улучшить tie-breaking (год из папки/файла, popularity score из KP), расширить кириллические варианты запроса.
**Группа C — документалки:**
`bbc. the real jungle book bear 2012`, `bbc. секреты собак`, `penguin meet the family (2020)`, `бегемоты - жизнь в воде`, `гиганты моря 2011`, `таинственная жизнь собак (hdtvrip 720p, 2013)`, `тайная жизнь собак (2016г)`, `prehistoric.planet.s02.1080p`, `жизнь птиц 1998`, `пингвины. шпион в толпе`, `супер белки (2018)`, `шпион в снегах 2018`
- Tier 4 (IMDb scrape) запускается, но candidates = 0 — title matching слишком строгий для BBC-документалок.
- **Нужно:** для documentaries/ добавить relaxed matching (убирать "bbc.", год, технические теги из запроса перед поиском).
#### 5. 🔴 Торренты: Transmission не видит 271/293 файлов
**Проблема:** Transmission ищет файл по `downloadDir/torrent_name`. После pipeline `apply` файлы переименованы в canonical форму (`Furiosa - A Mad Max Saga (2024)/Furiosa - A Mad Max Saga (2024).mkv`), а торрент ожидает оригинальное имя (`Furiosa.A.Mad.Max.Saga.2024.1080p....mkv`) прямо в `/media/movies/`. Совпадений нет → `haveValid=0` у 271 торрентов.
**22 торрента с файлами** — только те что в `/downloads/complete` (свежескачанные, pipeline ещё не обработал).
**Нужно:** реализовать `torrent-fix` subcommand: для каждого торрента искать файл по имени (case-insensitive fuzzy) в source директориях `/media/movies/`, `/media/cartoons/` и т.д., и вызывать `torrent-set-location` RPC.
#### 6. 🔴 Мультфильмы в library/movies (классификационный баг)
**Проблема:** `library/cartoons = 0 items`, `library/movies = 202 items` из которых **106 — мультфильмы** (симлинки ведут в `/media/cartoons/`). Pipeline при `apply` не учитывает source directory для определения выходной категории — всё льётся в `movies`.
**Примеры неправильно классифицированных:** Despicable Me, Encanto, Luca, Умка, Чебурашка, Бременские музыканты, Ёжик в тумане, и ещё ~100 советских мультиков.
**Нужно:** в `MediaFinalizer`/`apply` логике использовать source dir (`/media/cartoons/``output.cartoons`, `/media/documentaries/``output.documentaries`) вместо TMDb genre для определения выходной папки.
- Настроить библиотеки в Jellyfin (http://192.168.1.14:8096)
- NFO файлы готовы (716 шт.), Jellyfin должен их подхватить
#### 4. 🟢 Hermes cron на Кракене
- Периодический запуск sync (новые загрузки через Transmission)
---
## Принятые решения (архитектурные)
| Решение | Описание |
|---------|----------|
| **Unresolved = last resort** | `unresolved.json` — НЕ мусорка. Это очередь для AI-агента (Tier 5), который по крону подбирает нераспознанные и разрешает их через LLM + web search. Для данной библиотеки цель: Tier 0-4 (TMDb → KP → IMDb scrape → web search) должны закрывать всё — в `unresolved.json` не должно попадать ни одного item'а из текущей библиотеки. |
| **Web search enabled** | `providers.webSearch.enabled=true` в config.json. IMDb scrape как Tier 4 для всего, что не нашли TMDb/KP. Tier 4 должен срабатывать до того, как item уходит в unresolved.json |
| **Документалки приоритет KP** | BBC/Discovery документалки плохо индексированы в TMDb. KP часто знает их под русскими названиями. Стратегия: сначала KP с русским названием из папки, потом IMDb |
| **resolve-manual** | Только для экстренных случаев, не как регулярный процесс |
| **Single-file NFO** | Для `.mkv`/`.m4v` файлов NFO создаётся рядом (`film.nfo`), не внутри |
---
## Исправленные баги
### Баг 1: Двойной вызов binary (КРИТИЧЕСКИЙ)
`docker run ... media-pipeline:kraken media-pipeline sync` → бинарь получал `media-pipeline` как аргумент.
**Фикс:** `ENTRYPOINT ["media-pipeline"]`
### Баг 2: TitleSimilarity — симметричный Jaccard
`encanto_2021_bdrip_by_dalemake` vs `Encanto`: lengthRatio=0.2 → rejected.
**Фикс:** Asymmetric scoring — candidate-coverage Jaccard когда query длиннее. Коммит `2704ce3`
### Баг 3: maxCallsPerRun = 8
8 API-вызовов → 192/200 items никогда не искались.
**Фикс:** 8 → 500. Коммит `2704ce3`
### Баг 4: Series-гипотезы для одиночных файлов
Одиночные `.avi`/`.mkv` без S/E маркеров получали series-гипотезу → TMDb искал по `/search/tv`.
**Фикс:** `videos.count < 2 && !hasAnyEpisodeMarkers → return nil`. Коммит `17c2ddc`
### Баг 5: HTTP кеш не персистился
`cacheDirectory = /usr/local/bin/cache` — удалялся при `docker run --rm`.
**Фикс:** Autodetect `/config` mount → `/config/cache`. Коммит `5a1053c`
### Баг 7: Tier 4 (web search) не запускался для контента не в TMDb/KP
**Проблема:** `MediaPlanner` гейтил Tier 4 на `hasLiveUnresolved()` — но когда TMDb/KP возвращают 0 кандидатов, арбитр фаерит `provider-not-found`, который прунит все гипотезы. После этого `hasLiveUnresolved=false` → Tier 4 никогда не запускался.
**Фикс:**
- `MediaPlanner`: Tier 4/5 теперь гейтятся на `!hasWinner` (нет `.winning` гипотезы), а не `hasLiveUnresolved`
- `ProviderSearchStrategy`: добавлен флаг `includePrunedHypotheses` — когда `true`, поиск идёт и по `.pruned` ветками
- `WebSearchStrategy.webSearchDefaults`: `includePrunedHypotheses=true`
**Коммит:** `115f757`
### Баг 8: KP API URL смена домена (301 redirect)
`api.kinopoisk.dev` переехал на `api.poiskkino.dev`. Swift `URLSession` при редиректе теряет `X-API-KEY` заголовок → KP возвращает `{"docs":[]}` → кешируется как валидный пустой ответ → советские мультики и BBC не резолвились неделями.
**Фикс:** (1) обновлён URL в `KinopoiskAPI.swift`; (2) `HTTPClient.fetch` получил `shouldCache: ((Data) -> Bool)?` — KP не кеширует ответы с пустым `docs`.
### Баг 9: Leet-speak в именах файлов
`ni4ego_horoshego`, `o_4em_govoryat_muzh4iny` — цифра `4` = `ч` в русском warez-транслите. Стандартная транслитерация не покрывает.
**Фикс:** `String.decodeLeetSpeak()` в `StringExtensions.swift` + дополнительный variant в `NameTokenization.variants`.
### Баг 6: resolve-manual NFO path для single-файлов
`resolve-manual` писал NFO внутрь файла вместо рядом.
**Фикс:** Detect `isDirectory`, для файлов → `deletingPathExtension().appendingPathExtension("nfo")`. Коммит `c0fdc59`
---
## Конфиг на Кракене
```
/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/docker/media-pipeline/
├── config.json ← TMDb/KP ключи, Transmission RPC, directories
├── unresolved.json ← реестр нераспознанных (создаётся автоматически)
├── cache/ ← HTTP кеш 30 дней
└── on-download-complete.sh
```
**Запуск sync:**
```bash
docker run --rm \
-v /srv/.../media:/media \
-v /srv/.../docker/media-pipeline:/config \
media-pipeline:kraken \
sync --config /config/config.json
```
**Force-resolve одного item:**
```bash
docker run --rm ... media-pipeline:kraken \
resolve-manual --config /config/config.json \
--media-path '/media/cartoons/bremenskie.muzykanty' \
--tmdb 14327
```
---
## Технические детали
| | |
|--|--|
| HTPC | `bazzite@192.168.1.86`, Data: `/run/media/bazzite/Data/`, WoL: `B0:6E:BF:60:6D:64` |
| Кракен | `kraken@192.168.1.14`, HDD: `/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/` |
| Jellyfin | http://192.168.1.14:8096 |
| Transmission | http://192.168.1.14:9091 |
| Исходники | `~/Developer/media_files_db/`, ветка `kraken-agent` |
| Docker образ | `media-pipeline:kraken` (arm64, Colima 24GB) |
| kraken-ssh | `ssh kraken-ssh` → 10.99.1.2:22 через WireGuard (обновлено 2026-05-14) |
---
## Источник торрентов (важно)
Торренты на Кракене (128 шт.) импортированы из **Windows Transmission-daemon** на HTPC:
```
/run/media/bazzite/Windows/windows/serviceprofiles/localservice/appdata/local/transmission-daemon/
├── torrents/ ← 210 .torrent файлов
└── resume/ ← 214 resume (пути, статус)
```
Валидация resume (2026-05-14): **185/214 файлов есть на HTPC**. 29 missing:
- ~15 медиафайлов с утраченного диска `X:/Movies/` — потеряны безвозвратно
- ~14 игр/архивов из `Downloads/Unsorted/` — не медиа, не важно
Отдельно: **uTorrent** (`/run/media/bazzite/Windows/program files/utorrent/`) — 131 .torrent файл, resume.dat с 18 записями. Из них только 6 хешей совпадают с Кракеном.
`Karnavalnaya.noch.1956.BDRip.AVC.mkv` — есть в uTorrent и в Transmission на Кракене (`downloaded=0`). Файла нет нигде — **никогда не скачивался**.
## Журнал
- **2026-05-13 сессия 1:** HTPC разбужен, rsync запущен (~1.3TB), торрент-база импортирована (128 торрентов из Windows Transmission-daemon)
- **2026-05-13 сессия 2:** Docker build arm64, deploy на Кракен, first sync
- **2026-05-13 сессия 3:** `kraken-agent` ветка: UnresolvedStore, resolve-manual, agent, torrent-fix subcommands
- **2026-05-14 сессия 4:** 5 системных багов исправлены. Sync: 222/317 resolved (70%).
- **2026-05-14 сессия 5:** resolve-manual для 13 items. unresolved: 24 → 8. NFO path bug fix. kraken-ssh → WireGuard.
- **2026-05-14 сессия 6:** dry_run=false, sync запущен → 401 resolved, 32 unresolved. `apply` создаёт canonical папки + симлинки (оригиналы не трогает). 716 NFO написано. Валидация торрентов HTPC.
- **2026-05-15 сессия 7:** Торренты: 467 скопированы с HTPC, 323 добавлены в Transmission (294 итого после удаления 50 игр/нон-медиа). rsync: movies + мультфильмы + BBC документалки. Фиксы в коде: (1) best-effort collapse при исчерпании tierов, (2) дедупликация dir+file регионов в RegionPartitioner, (3) strip .aka./full.screen из TitleParser, (4) scanner пропускает canonical dirs по маркеру `.media-pipeline-canonical`, (5) Roman numerals в транслитерации (Ампир V). Финал: 19 unresolved.
- **2026-05-16 сессия 8:** Обнаружен корневой баг: KP API переехал `api.kinopoisk.dev``api.poiskkino.dev` (301 redirect, Swift теряет X-API-KEY). Исправлен URL. Удалены 359 невалидных KP-кеш записей. Добавлен leet-speak decode (`4``ch`: ni4ego→nichego, muzh4iny→muzhchiny). Починен кеш: KP пустые `docs:[]` больше не кешируются (были причиной повторных промахов после rate-limit/redirect). **Текущий unresolved: 22. Завтра KP лимит сбросится → ожидаем ≤5.**