[2026-09-20] eagle: family/how-to/arr-stack-kraken.md family/plans/watchlist-cleanup.md family/projects/watchlist-automation.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-20 21:26:08 +06:00
1 parent bbb970dcd7
commit 7e5cff5704
3 files changed
+191 -19

No files matched your search

+60 -8
View File
@@ -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="<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 '(?<=<ApiKey>)[^<]+' /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
+95
View File
@@ -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
+36 -11
View File
@@ -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. Проверить через несколько дней.