diff --git a/family/how-to/arr-stack-kraken.md b/family/how-to/arr-stack-kraken.md index 79d059c6..60df2af7 100644 --- a/family/how-to/arr-stack-kraken.md +++ b/family/how-to/arr-stack-kraken.md @@ -81,21 +81,18 @@ Prowlarr → Radarr + Sonarr → Transmission → Jellyfin ## Cron'ы на Kraken (crontab) -⚠️ **Фактическое состояние (проверено 2026-09-20): строки watchlist в crontab ОТСУТСТВУЮТ.** Watchlist pipeline мёртв с 2026-06-20 — детали и разбор в [[family/projects/watchlist-automation]]. +✅ **Watchlist-крон ВОССТАНОВЛЕН 2026-09-20 21:21** (был мёртв с 2026-06-20). Бэкап `~/crontab-backup-20260920-212155.txt`. Детали и разбор — в [[family/projects/watchlist-automation]]. -Фактически в `crontab -l` юзера `kraken` сейчас: +Актуальное `crontab -l` юзера `kraken`: ``` 0 * * * * bash ~/scripts/sync-vault.sh # Obsidian sync 0 * * * * pgs-to-srt.sh /media/downloads/complete # PGS→SRT новые 0 3 * * * pgs-to-srt.sh /media # PGS→SRT вся библиотека +0 1 * * * bash ~/scripts/watchlist-nightly.sh # watchlist nightly ✅ восстановлен +0 9 * * 0 bash ~/scripts/watchlist-discover.sh # watchlist discover ✅ восстановлен ``` -Должно быть (НЕ восстановлено, ждёт решения 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) -``` +⚠️ **`media-router.sh` (роутер symlink'ов, каждые 10 мин) в crontab ОТСУТСТВУЕТ.** В таблице «Два параллельных пути» выше он описан как работающий по cron 10min — фактически его там нет. Проверить, нужен ли: без него symlink'и в `/media/{movies,cartoons,...}/` не создаются автоматически. Точная проверка наличия любого крон-джоба (не верить доке, смотреть систему): ```bash @@ -104,6 +101,17 @@ 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 +systemctl is-active cron # демон жив? +``` + +**Установка крон-джоба безопасно (с бэкапом):** +```bash +crontab -l > ~/crontab-backup-$(date +%Y%m%d-%H%M%S).txt +cp ~/crontab-backup-*.txt /tmp/crontab-new.txt +# дописать строки в /tmp/crontab-new.txt +crontab /tmp/crontab-new.txt +crontab -l # проверка +grep -c watchlist /var/spool/cron/crontabs/kraken # демон подхватил? ``` ## API Keys @@ -555,6 +563,50 @@ python3 /tmp/wl_dedupe.py --apply # запись + авто-бэкап .dedup `_zulip_ping()` (`cli.py`) требует `ZULIP_URL` / `ZULIP_API_KEY` / `ZULIP_BOT_EMAIL`, которых **нет в `.env`** репо → `[warn] not set — skipping ping`. Уведомления о нерезолвленных items до Alex **не доходят** (59 штук ушли молча). +## Подготовка к авто-удалению просмотренного (2026-09-20) + +Требование Alex: удалять `[x]` при заполнении диска >90%, через API Radarr. План и открытые вопросы — [[family/plans/watchlist-cleanup]]. Здесь — только инфраструктурные факты, добытые при разведке. + +### ⚠️ `df` ВРЁТ про заполнение — считать через `shutil.disk_usage` + +``` +df -h → 88% (учитывает root-резерв ext4) +shutil.disk_usage → 83.7% (реальные 1647 / 1968 GB, free 220.8 GB) +``` +Разница ~4%. Порог «>90%» проверять **только** через `shutil.disk_usage`, иначе сработает на 86%. + +### Jellyfin: заголовок авторизации и отсутствие `DatePlayed` + +```python +# ПРАВИЛЬНО (как в watchlist_sync/jellyfin.py:_auth) +{"Authorization": 'MediaBrowser Token=""'} +# НЕПРАВИЛЬНО +{"X-Emby-Token": token} # → 401 +``` +Рабочие вызовы: +``` +GET /Users → 200; юзеры alex, lisa +GET /Users/{uid}/Items?IsPlayed=true&IncludeItemTypes=Movie&Fields=DatePlayed,Path +``` + +🔴 **`DatePlayed` возвращается `None` для всех просмотренных.** Логику, зависящую от даты просмотра, строить нельзя. `IsPlayed=true` работает, `UserData.Played` работает — дата нет. + +**Jellyfin видит просмотренными всего 6 фильмов** (Король Лев, Меч короля, Эль рояль, Остров сокровищ, Схватка с дьяволом, Труп невесты) — все из `/media/movies` (ручные торренты). Ни одного из `/media/movies-radarr` (18 фильмов, 702 ГБ). То есть пересечение `[x]` ∩ Radarr-файлы **пусто**. + +### Radarr: состояние библиотеки (замер 2026-09-20) + +- 46 фильмов в базе, **18 с файлами**, суммарно **702 ГБ**. +- Топ по размеру: Babylon 98.8 GB, Schindler's List 95.9, Midsommar 91.9, Triangle of Sadness 85.6, Chaos Walking 62.7, Unhinged 60.9. +- `recycleBin: ''` (корзина не настроена), `recycleBinCleanupDays: 7`, `deleteEmptyFolders: False`. +- **Все 18 monitored=True.** Если удалить файл, не сняв monitored, Radarr скачает заново. + +Проверка одним вызовом: +```bash +KEY=$(grep -oP '(?<=)[^<]+' /srv/...6194539b.../docker/radarr/config/config.xml) +curl -s "http://localhost:7878/radarr/api/v3/movie?apikey=$KEY" \ + | jq -r '.[] | select(.hasFile) | "\(.id)\t\(.sizeOnDisk/1e9|floor)GB\t\(.monitored)\t\(.title)"' +``` + ## Notes - See [[arr-stack-taiga]] for Taiga (secondary) arr stack diff --git a/family/plans/watchlist-cleanup.md b/family/plans/watchlist-cleanup.md new file mode 100644 index 00000000..2255f9a1 --- /dev/null +++ b/family/plans/watchlist-cleanup.md @@ -0,0 +1,95 @@ +# План: авто-удаление просмотренного (watchlist cleanup) + +**Дата:** 2026-09-20 +**Статус:** требование получено, механизм НЕ написан +**Связано:** [[watchlist-automation]], [[arr-stack-kraken]] + +--- + +## Что сказал Alex (дословно) + +> «Да, давай удалять то на чем стоит чекбокс при заполнении более 90%» + +Расшифровка — **три факта, и всё**: +1. Удалять то, **на чём стоит чекбокс** → `[x]` в watchlist. +2. **При заполнении диска > 90%.** +3. Механизм — **через API Radarr** (Alex: «Видимо через апи»), не `rm`. + +## ❌ Чего Alex НЕ говорил (придумано агентом, отвергнуто) + +Первая версия этого плана содержала выдуманные параметры, выданные за решение Alex. Alex отреагировал: **«Не как в твоём блядь предложении»**. + +**Выдумано и НЕ подтверждено:** +- ~~Задержка 7 дней после просмотра~~ — не просил +- ~~Только секция `## Фильмы`~~ — не ограничивал +- ~~`monitored: false`~~ — не обсуждал +- ~~`recycleBin` / корзина~~ — не просил +- ~~Лимит 10 файлов за прогон~~ — не просил + +⚠️ **Урок:** не выдавать свои догадки за решение пользователя. Alex сказал три слова — делать ровно это, остальное спрашивать. + +## Секция `## Правила отбора` — что проверено фактами + +## Факты, замеренные 2026-09-20 + +### Заполнение диска + +**Реальное заполнение — 83.7%**, порог 90% НЕ достигнут. + +```python +shutil.disk_usage(media) → total 1967.8 GB | used 1647.0 GB | free 220.8 GB → 83.7% +``` + +⚠️ `df -h` показывает **88%** — считает с root-резервом (~5% ext4). Для порога «90%» брать **`shutil.disk_usage`**, а не `df`, иначе порог сработает раньше на ~4%. + +### Кандидаты на удаление: 0 + +Пересечение `[x]` в watchlist ∩ фильмы с файлами в Radarr → **пусто**. + +- Фильмов в Radarr с файлами: **18** (702 ГБ). Топ: Babylon 98.8, Schindler's List 95.9, Midsommar 91.9, Triangle of Sadness 85.6 ГБ. +- Все 18 — недавние закачки, ещё не отмечены `[x]`. +- Jellyfin считает просмотренными **6** фильмов: Король Лев, Меч короля, Эль рояль, Остров сокровищ, Схватка с дьяволом, Труп невесты — все старые файлы из `/media/movies`, ни один **не из `/media/movies-radarr`**. + +**Вывод:** механизм напишется и будет работать, но сегодня удалит 0 файлов. Сработает, когда посмотришь что-то из Radarr-библиотеки. Если нужно, чтобы он **реально освобождал место** — сначала разобраться, почему `[x]` не появляется у новых фильмов (Jellyfin видит только 6 старых). + +### 🔴 Jellyfin НЕ отдаёт `DatePlayed` + +Все просмотренные вернули `DatePlayed=None`. **Опираться на дату просмотра в логике нельзя.** + +Рабочий вызов (заголовок важен — `Authorization`, НЕ `X-Emby-Token`): +```python +headers = {"Authorization": 'MediaBrowser Token="%s"' % token} +# GET /Users → 200, юзеры alex / lisa +# GET /Users/{uid}/Items?IsPlayed=true&IncludeItemTypes=Movie&Fields=DatePlayed,Path +``` +⚠️ `X-Emby-Token` даёт **401**. Именно так делает `watchlist_sync/jellyfin.py:_auth()`. + +## Архитектура (черновик, требует подтверждения Alex) + +``` +1. disk_usage(media) < 90% ? → exit 0 (silent) +2. parse watchlist → [x] строки +3. Radarr: найти фильм, hasFile? +4. DELETE /api/v3/movie/{id}?deleteFiles=true ← через API, как сказал Alex +5. лог +``` + +**Открытые вопросы (спрашивать, не додумывать):** +- [ ] Удалять вместе с файлом запись из Radarr, или оставлять? (иначе Radarr monitored → скачает заново) +- [ ] Все секции или только `## Фильмы`? +- [ ] Корзина или безвозвратно? +- [ ] Лимит за прогон? +- [ ] Ставить ли в cron, или запускать вручную? + +## Безопасность + +- **Порог проверять через `shutil.disk_usage`, не `df`.** +- **Dry-run обязателен** — первый прогон только показывает, что удалил бы. +- Операция необратима при отсутствии корзины — подтверждение Alex перед первым реальным запуском. + +--- + +## Связанные заметки + +- [[watchlist-automation]] — полный pipeline, статус крона, правила отбора sync-down +- [[arr-stack-kraken]] — *arr стек, пути конфигов, API diff --git a/family/projects/watchlist-automation.md b/family/projects/watchlist-automation.md index 93c7f765..3a6d1a26 100644 --- a/family/projects/watchlist-automation.md +++ b/family/projects/watchlist-automation.md @@ -83,9 +83,37 @@ Jellyfin (8096) → rescan → виден контент **Важно:** `process_thumbs` автоматически определяет отступ из `## Фильмы` и сохраняет при переносе. `SECTION_THUMBDN = "## Новинки👎"` (без пробела) — должно точно совпадать с заголовком. -## 🔴 Крон pipeline ОТСУТСТВУЕТ (аудит 2026-09-20) — но баг с мусором УЖЕ ИСПРАВЛЕН +## ✅ Крон pipeline ВОССТАНОВЛЕН (2026-09-20 21:21) -**Автодобавление фильмов НЕ работает по расписанию.** Скрипты живы, но их никто не запускает. +**Задача закрыта.** Pipeline был мёртв с 2026-06-20 (проверено аудитом ниже), теперь расписание вернули. + +Установлено в crontab юзера `kraken`: +``` +# Watchlist: process-thumbs + resolve + sync-down + sync-up (ежедневно 01:00) +0 1 * * * bash /home/kraken/scripts/watchlist-nightly.sh >> /tmp/watchlist-nightly.log 2>&1 + +# Watchlist: discover — новинки из KP API (воскресенье 09:00) +0 9 * * 0 bash /home/kraken/scripts/watchlist-discover.sh >> /tmp/watchlist-discover.log 2>&1 +``` + +**Как ставилось** (идемпотентный скрипт, бэкап перед установкой): +```bash +crontab -l > ~/crontab-backup-$(date +%Y%m%d-%H%M%S).txt # бэкап +crontab /tmp/crontab-new.txt # установка +crontab -l # проверка +``` +Бэкап: `~/crontab-backup-20260920-212155.txt` + +**Проверено после установки:** +- `systemctl is-active cron` → `active` +- `grep -c watchlist /var/spool/cron/crontabs/kraken` → **2** (обе строки подхвачены демоном) +- Логи пишутся в `/tmp/` — **теряются при перезагрузке**. Перенести в постоянное место, если нужно сохранять историю. + +⚠️ **В `docker exec hermes-kraken hermes cron list` по-прежнему «No scheduled jobs»** — это НЕ про watchlist. Watchlist-скрипты детерминированные, живут в системном cron, в Hermes-планировщике их не должно быть. Не искать их там. + +## 🔴 Аудит 2026-09-20: как выглядело состояние ДО восстановления (историческая справка) + +**На момент аудита автодобавление фильмов НЕ работало по расписанию.** Скрипты были живы, но их никто не запускал. Доказательства (проверено 2026-09-20): - `crontab -l` юзера `kraken` — watchlist-строк **НЕТ**. Есть только `sync-vault.sh` (каждый час) и два `pgs-to-srt` (часовой + 03:00). @@ -447,16 +475,16 @@ Sonarr API base: http://localhost:8989/sonarr/api/v3/ ``` Проверка закачки: `queue` в Radarr показывает `grabbed/downloading`; `history` даёт точное имя взятого релиза. Transmission — `docker exec transmission transmission-remote --list` (RPC-юзер в `settings.json` пустой). -## Cron Jobs (на Кракене с 2026-05-27) +## Cron Jobs (на Кракене, восстановлены 2026-09-20) -Весь watchlist pipeline работает на Кракене (мигрировал с Eagle 2026-05-27). +Весь watchlist pipeline работает на Кракене (мигрировал с Eagle 2026-05-27). **Крон был мёртв с 2026-06-20 по 2026-09-20, восстановлен** (детали в начале документа). | Job | Расписание | Скрипт | |-----|-----------|--------| | `watchlist-nightly` | ежедн. 01:00 | `~/scripts/watchlist-nightly.sh` | | `watchlist-discover` | вс 09:00 | `~/scripts/watchlist-discover.sh` | -⚠️ Фактический путь — `~/scripts/`, **не** `~/.hermes/scripts/` (в доке ранее было ошибочно). Оба скрипта вызывают CLI напрямую через `uv run --project $WS`, без LLM. `uv` лежит в `~/.local/bin/uv`. +⚠️ Фактический путь — `~/scripts/`, **не** `~/.hermes/scripts/`. Оба скрипта вызывают CLI напрямую через `uv run --project $WS`, без LLM. `uv` лежит в `~/.local/bin/uv`. `WS` в обоих скриптах: `/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/watchlist-sync` — **другой UUID**, чем фактический корень репо (см. ниже). Возможный источник поломки: проверить, что путь резолвится. @@ -564,12 +592,9 @@ Jellyfin library mapping: Movies → `movies`, Cartoons → `mixed` (movies + ep - ✅ **[2026-09-20] Фикс `sync_down.py` РЕАЛИЗОВАН** — коммит `ada47da`. `resolved.sort()` убран, добавлен `MIN_RATING = 6.0` с видимым `print`. Нулевые рейтинги отсекаются (решение Alex: «отсекать»). - ✅ **[2026-09-20] Приоритет `⭐` (U+2B50) РЕАЛИЗОВАН** — коммит `7db9385`. ⭐ первыми из всех секций, **обходит** фильтр `MIN_RATING`. `⭐` срезается из запроса TMDB (`parser._clean` через `str.replace`, НЕ через end-anchored класс). `✭` (U+272D) приоритетом не считается; `[x]` пропускается; под-буллеты кандидатов не считаются. - ✅ **[2026-09-20] Реальный прогон с новой логикой выполнен** — 19:53, `Done`, +3 фильма. Батч по порядку файла, ⭐ первым. -- 🔴 **[2026-09-20] Восстановить cron для watchlist pipeline** — ГЛАВНАЯ незакрытая задача. Pipeline мёртв с 20 июня. Скрипты проверены вручную (2 прогона 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] Крон ВОССТАНОВЛЕН** — установлен 21:21 в crontab юзера `kraken`, бэкап `~/crontab-backup-20260920-212155.txt`. `nightly` 01:00 + `discover` вс 09:00, логи в `/tmp/`. Первая проверка в бою — прогон в 01:00. +- 🟡 **[2026-09-20] Логи крона в `/tmp/`** — теряются при перезагрузке. Перенести в постоянное место (`~/logs/` или на диск), если нужна история прогонов. +- 🟡 **[2026-09-20] Удаление просмотренных фильмов при заполнении диска >90%** — требование Alex, механизм НЕ написан. См. [[family/plans/watchlist-cleanup]]. Замер 2026-09-20: диск **83.7%**, кандидатов на удаление **0** (пересечение `[x]` ∩ файлы Radarr пусто). Jellyfin **не отдаёт `DatePlayed`** (`None` у всех) — планировать без опоры на дату просмотра. - 🟡 **[2026-09-20] `sync-down` берёт всего 5 за прогон** — при 250 кандидатах разбор очереди займёт ~50 ночей. Рассмотреть увеличение `--batch` (сейчас `--batch 5` в `watchlist-nightly.sh`). Особенно актуально, раз фильтр `<6.0` уже отсеял 18. - 🟡 **[2026-09-20] Разобрать 5 застрявших закачек в очереди Radarr** со статусом `warning`: `Brokeback Mountain`, `Мортал Комбат 2`, `Sorry to Bother You`, `Город бога`, `День хомячка`. Висят давно, релиз не находится/не качается. - 🟡 **[2026-09-20] `Oficina do Diabo` / `Мастерская Сатаны` (2025)** — в Radarr, но релиз не найден. Ждёт RSS. Проверить через несколько дней.