[2026-09-20] eagle: family/how-to/arr-stack-kraken.md family/projects/watchlist-automation.md family/projects/watchlist-sync.md
This commit is contained in:
1 parent
d7ce0a9a70
commit
bd743da99c
3 files changed
+234
-30
No files matched your search
@@ -81,15 +81,31 @@ Prowlarr → Radarr + Sonarr → Transmission → Jellyfin
|
||||
|
||||
## Cron'ы на Kraken (crontab)
|
||||
|
||||
⚠️ **Фактическое состояние (проверено 2026-09-20): строки watchlist в crontab ОТСУТСТВУЮТ.** Watchlist pipeline мёртв с 2026-06-20 — детали и разбор в [[family/projects/watchlist-automation]].
|
||||
|
||||
Фактически в `crontab -l` юзера `kraken` сейчас:
|
||||
```
|
||||
0 * * * * bash ~/scripts/sync-vault.sh # Obsidian sync
|
||||
0 * * * * pgs-to-srt.sh /media/downloads # PGS→SRT новые
|
||||
0 * * * * pgs-to-srt.sh /media/downloads/complete # PGS→SRT новые
|
||||
0 3 * * * pgs-to-srt.sh /media # PGS→SRT вся библиотека
|
||||
```
|
||||
|
||||
Должно быть (НЕ восстановлено, ждёт решения Alex):
|
||||
```
|
||||
0 1 * * * bash ~/scripts/watchlist-nightly.sh # watchlist nightly
|
||||
0 9 * * 0 bash ~/scripts/watchlist-discover.sh # watchlist discover
|
||||
*/10 * * * * bash .../media-pipeline/media-router.sh # media router (Telegram)
|
||||
```
|
||||
|
||||
Точная проверка наличия любого крон-джоба (не верить доке, смотреть систему):
|
||||
```bash
|
||||
crontab -l # юзер kraken
|
||||
sudo crontab -l # root
|
||||
sudo ls -la /var/spool/cron/crontabs/ # все юзерские
|
||||
sudo grep -rl watchlist /var/spool/cron/ /etc/cron.d/ /etc/crontab
|
||||
systemctl --user list-timers --all ; systemctl list-timers --all | grep -i watchlist
|
||||
```
|
||||
|
||||
## API Keys
|
||||
|
||||
| Service | API Key |
|
||||
@@ -432,9 +448,64 @@ sudo docker inspect <name> -f '{{index .Config.Labels "com.docker.compose.projec
|
||||
|
||||
Все сервисы стека (`radarr`, `sonarr`, `prowlarr`, `flaresolverr`, `transmission`) **плюс `jellyfin` и `portainer`** размечены label `com.centurylinklabs.watchtower.enable=true` → обновляются автоматически (7 контейнеров, проверено `scanned=7`). Полный разбор и список того, что НЕ обновляется: [[family/how-to/kraken-watchtower]]. Теория: [[personal/tech/watchtower-docker-updates]].
|
||||
|
||||
## Watchlist-sync: ручной запуск и баг дублирования (2026-09-20)
|
||||
|
||||
> Детальный разбор бага и полная механика — в [[family/projects/watchlist-automation]]. Здесь — операционная выжимка.
|
||||
|
||||
### Ручной запуск (пока крон не восстановлен)
|
||||
|
||||
```bash
|
||||
ssh kraken
|
||||
bash ~/scripts/watchlist-nightly.sh # pull → process-thumbs → resolve → sync-down → sync-up → push
|
||||
```
|
||||
Отдельные шаги:
|
||||
```bash
|
||||
cd /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/watchlist-sync
|
||||
uv run --project . watchlist-sync <resolve|sync-down|sync-up|process-thumbs|discover> [--apply] [--recheck] [--batch N]
|
||||
```
|
||||
`uv` = `~/.local/bin/uv`. Без `--apply` — dry-run.
|
||||
|
||||
### 🔴 Баг `mark_ambiguous()` — исправлен
|
||||
|
||||
`watchlist_sync/parser.py`, функция `mark_ambiguous()`: паттерн снимал **только саму `❓`-строку**, а замена вставляла новые кандидаты **перед** старыми → под-буллеты дублировались **на каждом прогоне** `resolve` (+3 строки / +100 байт за раз). `❓`-строки при этом НЕ дублировались — только под-буллеты под ними.
|
||||
|
||||
```python
|
||||
# ФИКС: захват всего блока — маркер + под-буллеты
|
||||
_SUB_BULLETS = r'(?:\n[ \t]{4,}-[ \t]*(?!\[[ xX]\])[^\n]*)'
|
||||
pattern = re.compile(
|
||||
r'(^[ \t]*-[ \t]*\[ \][ \t]*)[❓]?[ \t]*(' + escaped + r')[ \t]*'
|
||||
r'(?P<subs>' + _SUB_BULLETS + r'*)',
|
||||
re.MULTILINE
|
||||
)
|
||||
```
|
||||
|
||||
**Правило для парсеров этого файла:** под-буллет кандидата = отступ **≥4 пробела** + буллет + **НЕ чекбокс** (`- [ ]`/`- [x]`). Строки фильмов имеют отступ **2 пробела** — их надо исключать явно. Внутри `*`-группы **перенос строки обязателен** (`(?:` + `\n` + ...) + `*`): если сделать `\n?` опциональным, regex перешагивает на следующую строку и **проглатывает соседние фильмы** (проверено — так потеряли `❓ The kill room`, `The burial`, `Past lives`).
|
||||
|
||||
**Верификация:** прогнать `mark_ambiguous()` 3× на свежей копии → размер обязан быть **идентичным**. Плюс проверка, что 0 не-кандидатных строк потеряно.
|
||||
|
||||
### Скрипт дедупа кандидатов
|
||||
|
||||
Одноразовая чистка накопленных дублей: под каждой `❓`/`🗓️`-строкой оставить уникальные под-буллеты (ключ `title|year|rating`), порядок не менять, строки фильмов не трогать.
|
||||
```bash
|
||||
python3 /tmp/wl_dedupe.py # dry-run
|
||||
python3 /tmp/wl_dedupe.py --apply # запись + авто-бэкап .dedupe-backup-<ts>
|
||||
```
|
||||
Прогон 2026-09-20: **168 дублей в 15 блоках**, 26430 → 21032 байт (838 → 670 строк).
|
||||
|
||||
⚠️ **Скрипты этой сессии — в `/tmp` на Кракене** (`wl_dedupe.py`, `wl_fix_parser*.py`, `wl_verify*.py`); `/tmp` чистится при перезагрузке. Для постоянной копии — перенести в `~/scripts/`.
|
||||
|
||||
### Sonarr 400 «This series has already been added» — не сбой
|
||||
|
||||
При `sync-down` уже существующей серии Sonarr отвечает `400 SeriesExistsValidator` («Волшебный участок» = «Magical Police Department», tvdbId=442038). `arr.py::sonarr_add()` **не проверяет дубли перед POST** — в отличие от `radarr_add()`. Шумит в логе, данные не портит. Диагноз смотреть в теле ответа: `errorCode: SeriesExistsValidator`.
|
||||
|
||||
### Zulip-пинг не настроен
|
||||
|
||||
`_zulip_ping()` (`cli.py`) требует `ZULIP_URL` / `ZULIP_API_KEY` / `ZULIP_BOT_EMAIL`, которых **нет в `.env`** репо → `[warn] not set — skipping ping`. Уведомления о нерезолвленных items до Alex **не доходят** (59 штук ушли молча).
|
||||
|
||||
## Notes
|
||||
|
||||
- See [[arr-stack-taiga]] for Taiga (secondary) arr stack
|
||||
- Media pipeline pitfalls: [[media-pipeline-pitfalls]]
|
||||
- FlareSolverr / Cloudflare / Prowlarr-питфоллы: [[prowlarr-flaresolverr-cloudflare]]
|
||||
- Watchlist pipeline (полный flow, cron, баги): [[family/projects/watchlist-automation]]
|
||||
- Синтез: [[concepts/kraken-media-stack]]
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
created: '2026-05-20'
|
||||
updated: '2026-09-20'
|
||||
status: broken
|
||||
status: degraded
|
||||
tags:
|
||||
- kraken
|
||||
- watchlist
|
||||
@@ -81,7 +81,95 @@ Jellyfin (8096) → rescan → виден контент
|
||||
|
||||
**Побочный эффект — файл засран `❓`-мусором.** Так как `resolve --recheck` не бегает, ambiguous-строки копят дампы кандидатов: «Крестный отец» ×4 блока по 6 строк, «Nightmare Alley» ×31 строка, «Stand by me» ×40 строк, «Фарго» ×30. Секции `👍/👎` не обрабатываются — 40+ позиций висят в «Новинки», не переехав в основной список.
|
||||
|
||||
Аудит завершён без изменений на Кракане — ничего не трогалось. Три варианта для Alex: (1) восстановить крон, (2) сначала почистить `❓`-мусор, (3) оставить как есть.
|
||||
> ⚠️ **Уточнение (2026-09-20, позже в тот же день):** изначальная гипотеза «мусор скопился от многомесячного простоя» **НЕВЕРНА**. Дубли создавались на **каждом** прогоне `resolve` из-за бага в `mark_ambiguous()` (см. ниже). 33 строки у «Nightmare Alley» = 11 прогонов. Простой лишь позволил мусору накопиться незамеченным.
|
||||
|
||||
**Крон по-прежнему НЕ восстановлен** — Alex не просил, прогон делался вручную (см. «Ручной прогон»).
|
||||
|
||||
## ✅ Баг дублирования кандидатов в `mark_ambiguous()` — НАЙДЕН И ИСПРАВЛЕН (2026-09-20)
|
||||
|
||||
### Симптом
|
||||
Под каждой `❓`-строкой копились одинаковые дампы кандидатов. Рост ровно **+100 байт за прогон** (3 строки кандидатов) — подтверждено экспериментом: 26430 → 26530 → 26630 → 26730 байт.
|
||||
|
||||
### Корень (точная механика)
|
||||
В `watchlist_sync/parser.py`, функция `mark_ambiguous()`:
|
||||
|
||||
```python
|
||||
pattern = re.compile(
|
||||
r'(^\s*-\s*\[ \]\s*)[❓]?\s*(' + escaped + r')\s*$', # ← матчит ТОЛЬКО строку ❓
|
||||
re.MULTILINE
|
||||
)
|
||||
...
|
||||
replacement = rf'\1❓ \2\n{cand_lines}' # ← новые кандидаты
|
||||
new_text = pattern.sub(replacement, text, count=1) # ← ВСТАВЛЯЮТСЯ перед старыми
|
||||
```
|
||||
|
||||
Паттерн снимал **только саму `❓`-строку**. Замена вставляла `\n` + 3 новых кандидата, а старые 33 строки оставались **ниже** — реплейс не знал о них. Итог: каждый прогон добавляет ещё один блок кандидатов поверх существующих.
|
||||
|
||||
**Важно:** `❓`-строки НЕ дублировались (каждая — одна). Дублировались **под-буллеты** под ними.
|
||||
|
||||
### Фикс
|
||||
Паттерн теперь захватывает **весь блок**: строку-маркер ПЛЮС её под-буллеты, и перезаписывает целиком.
|
||||
|
||||
```python
|
||||
# Candidate sub-bullet: indent of 4+ spaces, a bullet, NOT a checkbox line.
|
||||
# Each iteration REQUIRES its own leading newline -- otherwise `*` walks onto
|
||||
# the following line and swallows neighbouring items.
|
||||
_SUB_BULLETS = r'(?:\n[ \t]{4,}-[ \t]*(?!\[[ xX]\])[^\n]*)'
|
||||
|
||||
pattern = re.compile(
|
||||
r'(^[ \t]*-[ \t]*\[ \][ \t]*)[❓]?[ \t]*(' + escaped + r')[ \t]*'
|
||||
r'(?P<subs>' + _SUB_BULLETS + r'*)',
|
||||
re.MULTILINE
|
||||
)
|
||||
```
|
||||
|
||||
### ⚠️ Две НЕУДАЧНЫЕ версии паттерна (не повторять)
|
||||
1. **v1** — `(?:\n[ \t]+-[^\n]*\n?)*`: `\n?` опционален, поэтому `*` перешагивал на следующую строку **без разделителя** и проглатывал соседние фильмы. Потеряны `❓ The kill room`, `The burial`, `Past lives`. Откачено.
|
||||
2. **v2** — то же плюс негативный lookahead: не помогло, `[^\n]*` из предыдущей итерации уже захватил хвост следующей строки.
|
||||
3. **v3 (рабочая)** — перенос обязателен внутри каждой итерации (`(?:` + `\n` + ...) + `*`), якорь не нужен.
|
||||
|
||||
**Правило для парсеров этого файла:** под-буллет кандидата = отступ **≥4 пробела**, это буллет и он **НЕ чекбокс** (`- [ ]` / `- [x]`). Строки фильмов имеют отступ 2 пробела — именно поэтому их надо исключать явно.
|
||||
|
||||
### Проверка фикса
|
||||
На чистой копии (md5 `40295fac...`) — 3 прогона `mark_ambiguous()`:
|
||||
```
|
||||
run 1: size=25430
|
||||
run 2: size=25430
|
||||
run 3: size=25430
|
||||
```
|
||||
Размер стабилен. Потеряно **0** не-кандидатных строк. `Past lives` на месте. 838 → 808 строк (минус 30 = старые дубли, 33 → 3).
|
||||
|
||||
### Чистка существующих дублей
|
||||
Скрипт `/tmp/wl_dedupe.py` (дедуп по `title|year|rating`, первое вхождение сохраняется, порядок не меняется; строки фильмов не трогаются). Прогон `--apply`:
|
||||
- **168 дублей в 15 блоках**, 26430 → 21032 байт (838 → 670 строк).
|
||||
- Топ: `Nightmare alley` 33→3, `Stand by me` 30→3, `Фарго` 30→3, `Left behind` 21→4, `Крестный отец` 12→3, `Godfathers` 12→3.
|
||||
|
||||
### Ручной прогон `watchlist-nightly.sh` (от юзера `kraken`)
|
||||
```
|
||||
bash ~/scripts/watchlist-nightly.sh
|
||||
```
|
||||
Прошёл до `Done`, без падений. Результат: **270 resolved (38 horror), 37 ambiguous, 22 not found**. `sync-down` добавил 4 фильма в Radarr (Американская история X, Мастерская сатаны, Я ругаюсь, Гладиатор), `Scream` уже был → помечен `⬇️`. `sync-up`: 7 played items из Jellyfin, 1 отмечен. Vault закоммичен и запушен (`Committed: family/documents/movies-watchlist.md`, `Pushed ✓`).
|
||||
|
||||
**После прогона дублей: 0** (проверено отдельным скриптом). Секции целы: Новинки / Фильмы / Мультфильмы / Аниме / Новинки👎 / Связанные заметки.
|
||||
|
||||
### 🟡 Побочная находка: Zulip-пинг не настроен на Кракене
|
||||
`_zulip_ping()` требует `ZULIP_URL`, `ZULIP_API_KEY`, `ZULIP_BOT_EMAIL`, но их **нет в `.env`** репо watchlist-sync. При 59 нерезолвленных items → `[warn] ... not set — skipping ping`. Уведомления о нерезолвленных до Alex не доходят.
|
||||
|
||||
### 🟡 Побочная находка: Sonarr 400 «This series has already been added»
|
||||
При `sync-down` для «Волшебный участок»: `400 Bad Request` на `/sonarr/api/v3/series`. Причина безобидная — **серия уже в Sonarr** (tvdbId=442038, «Magical Police Department»). `arr.py::sonarr_add()` не проверяет дубли перед POST, поэтому Sonarr отвечает `SeriesExistsValidator`. Не сбой, но шумит в логе — стоит добавить pre-check (как в `radarr_add`).
|
||||
|
||||
### Бэкапы (перед правками)
|
||||
```
|
||||
~/obsidian/family/documents/movies-watchlist.md.bak-20260920-192909 (838 строк, 26430 б)
|
||||
~/obsidian/family/documents/movies-watchlist.md.dedupe-backup-20260920-193111
|
||||
/srv/.../watchlist-sync/watchlist_sync/parser.py.bak-20260920-192909
|
||||
```
|
||||
|
||||
### Статус на конец сессии
|
||||
- ✅ Фикс `parser.py` применён на Кракене, записан на диск, **`ast.parse` OK**.
|
||||
- 🔴 **Фикс НЕ закоммичен** в репо watchlist-sync (git status показывает только `?? arr.py.bak-web4k-...`). Нужен коммит.
|
||||
- ✅ Файл watchlist вычищен и закоммичен в vault.
|
||||
- 🔴 Крон по-прежнему отсутствует — pipeline живёт только вручную.
|
||||
|
||||
## Cron Jobs (на Кракене с 2026-05-27)
|
||||
|
||||
@@ -102,7 +190,26 @@ Jellyfin (8096) → rescan → виден контент
|
||||
|
||||
**Пути на Кракене (HDD UUID 49e8f586-3839-4c5d-a1e1-58bfc3579ade):**
|
||||
- `/home/kraken/obsidian` → symlink на `/srv/dev-disk-by-uuid-.../obsidian`
|
||||
- `~/Developer/watchlist-sync` → symlink. **Реальный корень репо** (проверено 2026-09-04): `/srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/watchlist-sync` — находится **в корне диска, НЕ под `Developer/`** (в доке ранее путь был ошибочный). Внутри: `watchlist_sync/` (cli.py, arr.py, sync_down.py, sync_up.py, resolver.py, parser.py, discover.py, jellyfin.py), `.venv` (py3.11+httpx+click), `.resolve_cache.json`, pyproject.toml.
|
||||
- `/home/kraken/Developer/watchlist-sync` → symlink на `/srv/dev-disk-by-uuid-49e8f586-.../watchlist-sync`
|
||||
|
||||
✅ **Путь репо в скриптах ВЕРНЫЙ** (проверено 2026-09-20). В `watchlist-nightly.sh` и `watchlist-discover.sh`:
|
||||
```
|
||||
WS=/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/watchlist-sync
|
||||
UV=~/.local/bin/uv
|
||||
```
|
||||
`ls -la` подтверждает: `/srv/.../watchlist-sync` существует, внутри `watchlist_sync/`, `.venv/`, `.resolve_cache.json`, `pyproject.toml`, `.env` (есть, содержит TMDB_KEY/KP_KEY/RADARR_*/SONARR_*; **нет** ZULIP_*).
|
||||
|
||||
> Ранее в доке фигурировал путь `.../6194539b-.../watchlist-sync` «как реальный корень». На 2026-09-20 рабочий путь — **`49e8f586`**, и он же используется в скриптах. Не «исправлять» его обратно.
|
||||
|
||||
**Ещё одно подтверждённое отличие:** `~/scripts/` — **реальная директория** (`drwxr-xr-x root root`), а `~/.hermes/` на Кракане содержит **только** `skills/`. Скрипты лежат в `~/scripts/`, не в `~/.hermes/scripts/`.
|
||||
|
||||
### Как запускать CLI вручную (рабочая команда)
|
||||
```bash
|
||||
ssh kraken
|
||||
cd /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/watchlist-sync
|
||||
uv run --project . watchlist-sync <команда> # resolve / sync-down / sync-up / process-thumbs / discover
|
||||
```
|
||||
Или целиком пайплайн: `bash ~/scripts/watchlist-nightly.sh`
|
||||
|
||||
## Discover — Фильтрация
|
||||
|
||||
@@ -161,19 +268,34 @@ Jellyfin library mapping: Movies → `movies`, Cartoons → `mixed` (movies + ep
|
||||
### KP API Endpoint
|
||||
`api.kinopoisk.dev` редиректит на `api.poiskkino.dev/v1.4/movie`. Использовать destination redirect напрямую.
|
||||
|
||||
### 🔴 Жёстко зашитый `qualityProfileId: 1` в arr.py (корень жирных remux)
|
||||
Найдено 2026-09-04. В `watchlist_sync/arr.py` **`qualityProfileId: 1` захардкожен** и для Radarr, и для Sonarr:
|
||||
### 🔴 Жёстко зашитый `qualityProfileId` в arr.py (корень жирных remux) — РЕШЕНО
|
||||
Найдено 2026-09-04. В `watchlist_sync/arr.py` изначально был захардкожен **`qualityProfileId: 1`** и для Radarr, и для Sonarr:
|
||||
```python
|
||||
# radarr_add (~стр. 77) / sonarr_add (~стр. 112)
|
||||
# radarr_add (~стр. 77) / sonarr_add (~стр. 112)
|
||||
"qualityProfileId": 1,
|
||||
```
|
||||
Профиль 1 (Radarr) = **'Any'** — разрешает ВСЁ вплоть до Remux-2160p и BR-DISK. Поэтому **каждый новый фильм/сериал, добавляемый watchlist-sync, попадает в «Any»** и Radarr скачивает самый жирный доступный релиз (60GB remux'ы). Готового профиля «2160p, но без Remux» на Kraken нет (нужно создавать). Решение по стратегии — открыто (см. ниже). Чтобы новые шли в поддерживаемое качество: либо создать профиль «2160p без Remux/BR-DISK» и поменять `qualityProfileId` в `arr.py` (Radarr+Sonarr), либо сузить сам профиль 1, либо зашить `4` (HD-1080p).
|
||||
Профиль 1 (Radarr) = **'Any'** — разрешает ВСЁ вплоть до Remux-2160p и BR-DISK, поэтому каждый новый фильм/сериал попадал в «Any» и Radarr скачивал 60GB remux'ы.
|
||||
|
||||
✅ **Решение принято и применено 2026-09-04:** создан профиль **`WEB-4K (no remux)`** → Radarr id **7**, Sonarr id **7**; `arr.py` теперь пишет `qualityProfileId: 7`. Подробности профиля — в [[arr-stack-kraken]], секция «Качество загрузки для НОВЫХ фильмов/сериалов».
|
||||
|
||||
### ✅ Баг накопления кандидатов в `mark_ambiguous()` (найден и исправлен 2026-09-20)
|
||||
Кандидаты-под-буллеты под `❓`-строками дублировались **на каждом прогоне** `resolve` (+3 строки за раз), потому что `re.sub` снимал только саму `❓`-строку, а новые кандидаты вставлялись **перед** старыми. Паттерн исправлен на захват всего блока (маркер + под-буллеты). Полная механика, две неудачные версии паттерна и чистка 168 дублей — в [[family/projects/watchlist-automation]].
|
||||
|
||||
**Правило для парсеров watchlist:** под-буллет кандидата = отступ **≥4 пробела** + буллет + **НЕ чекбокс** (`- [ ]`/`- [x]`). Строки фильмов имеют отступ 2 пробела. Внутри `*`-группы перенос строки обязателен — иначе regex проглатывает соседние фильмы.
|
||||
|
||||
## Open Tasks
|
||||
|
||||
- 🔴 **[2026-09-20] Восстановить cron для watchlist pipeline** — pipeline мёртв с 20 июня (см. раздел выше). Решение за Alex: восстановить крон / сначала почистить `❓`-мусор / оставить как есть.
|
||||
- 🔴 **[2026-09-04] Решить стратегию качества загрузки новых фильмов** (см. профили в [[arr-stack-kraken]]). Корень — захардкоженный `qualityProfileId: 1` (`Any`) в `watchlist_sync/arr.py`. Пока НЕ менялось (НИЧЕГО не правилось, ждём решение Alex). Вопрос юзеру: сохранить 4K (→ создать профиль «2160p без Remux/BR-DISK» и сменить id в arr.py) или опустить до 1080p (id 4); и менять ли и для Sonarr (сериалы) тоже.
|
||||
- 🟡 Почистить `❓`-мусор в movies-watchlist.md (повторяющиеся дампы кандидатов после многомесячного простоя)
|
||||
- 🔴 **[2026-09-20] Закоммитить фикс `parser.py`** в репо watchlist-sync. Правка применена на Кракене, но не в git — при следующем `git pull`/пересоздании `.venv` можно потерять. Файл: `watchlist_sync/parser.py` (функция `mark_ambiguous`, `_SUB_BULLETS`).
|
||||
- 🔴 **[2026-09-20] Восстановить cron для watchlist pipeline** — pipeline мёртв с 20 июня. Скрипты готовы и проверены вручную (прогон 2026-09-20 прошёл чисто), нужно вернуть в crontab юзера `kraken`:
|
||||
```
|
||||
0 1 * * * bash ~/scripts/watchlist-nightly.sh
|
||||
0 9 * * 0 bash ~/scripts/watchlist-discover.sh
|
||||
```
|
||||
⚠️ В [[arr-stack-kraken]] эти строки в секции «Cron'ы на Kraken» указаны как действующие, хотя фактически их НЕТ — док в той части расходится с реальностью.
|
||||
- 🟡 **[2026-09-20] Настроить Zulip-пинг** — `ZULIP_URL` / `ZULIP_API_KEY` / `ZULIP_BOT_EMAIL` отсутствуют в `.env` watchlist-sync, 59 нерезолвленных items ушли в никуда без уведомления.
|
||||
- 🟡 **[2026-09-20] Добавить pre-check дублей в `sonarr_add()`** — сейчас при уже существующей серии прилетает `400 SeriesExistsValidator` и шумит в логе. В `radarr_add()` проверка есть.
|
||||
- 🔴 **[2026-09-04] Решить стратегию качества загрузки новых фильмов** — уже РЕШЕНО 2026-09-04 (профиль `WEB-4K (no remux)`, id 7 для Radarr и Sonarr). Осталось только убедиться, что старые `⬇️`-позиции, добавленные до фикса, не тянут remux.
|
||||
- 🟡 Оставшиеся `❓`-позиции (71 маркер) — **намеренно не чистятся вручную** (решение Alex 2026-09-20). Разбираются через `resolve --recheck` при работающем кроне.
|
||||
- 🟡 Передавать Transmission locations через router script при каждом импорте (сейчас вручную)
|
||||
- 🔴 rsync невыполненных фильмов с HTPC на Кракен (`Фильмы не перенесенные с htpc на кракен.md`)
|
||||
- 🟡 Watchlist sync-up: добавить перенесённые фильмы в нужные разделы
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
created: '2026-05-18'
|
||||
updated: '2026-05-18'
|
||||
status: planning
|
||||
updated: '2026-09-20'
|
||||
status: active
|
||||
tags:
|
||||
- kraken
|
||||
- jellyfin
|
||||
@@ -16,6 +16,8 @@ tags:
|
||||
|
||||
Репо: `~/Developer/watchlist-sync` → GitHub `mallexxx/watchlist-sync`
|
||||
|
||||
> ℹ️ **Эта заметка — исходный дизайн-документ проекта (Stage 1/2).** Актуальное состояние, рабочие пути, cron-статус и все найденные баги — в [[family/projects/watchlist-automation]]. Реализовано всё, кроме Stage 2 (рекомендации). Ниже сохранён дизайн; расхождения с реальностью помечены.
|
||||
|
||||
---
|
||||
|
||||
## Архитектура
|
||||
@@ -113,8 +115,12 @@ WATCHLIST_PATH=/vault/family/documents/movies-watchlist.md
|
||||
|
||||
| Job | Расписание | Скрипт |
|
||||
|-----|-----------|--------|
|
||||
| `watchlist-nightly` | ежедн. 01:00 | `~/.hermes/scripts/watchlist-nightly.sh` |
|
||||
| `watchlist-discover` | вс 09:00 | `~/.hermes/scripts/watchlist-discover.sh` |
|
||||
| `watchlist-nightly` | ежедн. 01:00 | `~/scripts/watchlist-nightly.sh` |
|
||||
| `watchlist-discover` | вс 09:00 | `~/scripts/watchlist-discover.sh` |
|
||||
|
||||
⚠️ Фактический путь — `~/scripts/`, **не** `~/.hermes/scripts/` (проверено 2026-09-20). Мигрировали с Eagle на Кракен 2026-05-27.
|
||||
|
||||
⚠️🔴 **Cron НЕ восстановлен после 2026-06-20** — pipeline запускается только вручную. См. [[family/projects/watchlist-automation]].
|
||||
|
||||
Используют `~/scripts/sync-vault.sh` для всех git-операций (stash/pull/pop/commit/push). **Не агентные** — скрипты вызывают CLI напрямую, никакого LLM в pipeline.
|
||||
|
||||
@@ -208,28 +214,33 @@ WATCHLIST_PATH=/vault/family/documents/movies-watchlist.md
|
||||
|
||||
## Имплементация: очерёдность задач
|
||||
|
||||
### Фаза 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`
|
||||
> Статусы проставлены 2026-09-20. Фазы 1-3 и cron реализованы и работают (проверено ручным прогоном `watchlist-nightly.sh`). Stage 2 (Фаза 4) — не начата.
|
||||
|
||||
### Фаза 2
|
||||
- [ ] `sync_up.py` — Jellyfin → `[x]` + сортировка
|
||||
- [ ] CLI: `watchlist-sync sync-up`
|
||||
- [ ] Cron на Кракене: sync-up каждые 24ч
|
||||
### Фаза 1 (MVP) — ✅ РЕАЛИЗОВАНО
|
||||
- [x] Инициализировать репо `~/Developer/watchlist-sync`, push на GitHub
|
||||
- [x] `parser.py` — парсинг .md, классификация строк
|
||||
- [x] `resolver.py` — TMDB `/search/multi` + KP fallback
|
||||
- [x] `sync_down.py` — add to Radarr/Sonarr (батч 5), пометить `⬇️`
|
||||
- [x] CLI: `watchlist-sync resolve --dry-run` и `--apply`
|
||||
- [x] CLI: `watchlist-sync sync-down --batch 5`
|
||||
|
||||
### Фаза 3
|
||||
- [ ] AI disambiguation job (Hermes Kraken cron)
|
||||
- [ ] Уточнение у Alex через Zulip для нерезолвленных
|
||||
### Фаза 2 — ✅ РЕАЛИЗОВАНО
|
||||
- [x] `sync_up.py` — Jellyfin → `[x]` + сортировка
|
||||
- [x] CLI: `watchlist-sync sync-up`
|
||||
- [x] Cron на Кракене: sync-up каждые 24ч — ⚠️ был, **умер 2026-06-20**, не восстановлен
|
||||
|
||||
### Фаза 4 (Stage 2)
|
||||
### Фаза 3 — ✅ РЕАЛИЗОВАНО (кроме Zulip)
|
||||
- [x] CLI `resolve --recheck` для повторного разбора `❓`
|
||||
- [ ] AI disambiguation job (Hermes Kraken cron) — не делался, вместо него детерминированный `--recheck`
|
||||
- [ ] Уточнение у Alex через Zulip для нерезолвленных — код есть (`_zulip_ping()` в `cli.py`), но `ZULIP_*` не в `.env` → молча скипается
|
||||
|
||||
### Фаза 4 (Stage 2) — ❌ НЕ НАЧАТА
|
||||
- [ ] `recommend.py` — профиль + TMDB recommendations
|
||||
- [ ] Три curated списка с подтверждением
|
||||
- [ ] Еженедельный cron job
|
||||
|
||||
> Файловая структура в разделе «Структура проекта» — тоже дизайн: реально `radarr.py`/`sonarr.py` объединены в `arr.py`, добавлены `discover.py`, `sync_down.py`, `sync_up.py`, `jellyfin.py`, `parser.py`, `resolver.py`, `cli.py`. Точный список — в [[family/projects/watchlist-automation]].
|
||||
|
||||
---
|
||||
|
||||
## Ключи и секреты
|
||||
|
||||
Reference in new issue
Block a user