[2026-09-22] eagle: personal/plans/watchlist-tmdb-missing-marker.md personal/tech/lampac-deployment.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-22 18:24:10 +06:00
1 parent d10bc1a5d0
commit a334332c5b
2 files changed
+382 -6

No files matched your search

+163 -3
View File
@@ -14,6 +14,7 @@ tags:
related:
- '[[personal/plans/lampac-kraken]]'
- '[[personal/plans/lampac-watchlist-plugin]]'
- '[[personal/plans/watchlist-tmdb-missing-marker]]'
- '[[personal/tech/multistream-single-flow-limit]]'
- '[[family/how-to/kraken-network]]'
- '[[family/how-to/tv-luna-send]]'
@@ -82,6 +83,88 @@ related:
подстановка `$( … | sed … )` вырезается фильтром безопасности — питфолл №2 из
[[family/how-to/gitea-config.md]]).
## 🚀 Деплой генератора на Кра́кен (проверено 2026-09-22)
### 🔴🔴 Питфолл: `load_env()` искал `.env` только по Mac-пути
```python
# БЫЛО — генератор на Кра́кене не находил ключей вообще
for p in (Path("/Users/admin/Developer/watchlist-sync/.env"),):
```
Симптом на Кра́кене: `[ERR] нет TMDB_KEY в .env` → **каталог собирался на одних
Кинопоиск-ссылках, без TMDB-ID и постеров.** Никакой резолв не выполнялся, хотя
код для него был. Именно это объясняет, почему в JSON не было TMDB-ID у половины
позиций — не «слабый резолв», а его полное отсутствие.
**СТАЛО** — перебор 5 мест, печать прочитанных файлов в stderr:
```python
candidates = [
os.environ.get("WATCHLIST_ENV", ""),
"/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/watchlist-sync/.env",
"/srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/watchlist-sync/.env",
str(Path.home() / "Developer" / "watchlist-sync" / ".env"),
str(Path.home() / ".config" / "watchlist-sync" / ".env"),
]
```
Патч: `~/lampac-tmp/patch_envpath.py`. **Урок:** при деплое скрипта на другую
машину — первым делом проверять абсолютные пути к конфигам, а не логику.
### Установка: только `sudo install`, не `cp`
```bash
scp -q ~/Developer/lampac-scripts/scripts/gen_watchlist.py kraken:/tmp/gen_watchlist.py
ssh kraken "sudo install -o kraken -g kraken -m 600 /tmp/gen_watchlist.py \
$H/scripts/gen_watchlist.py"
```
`$H` = `/srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/lampac`
🔴 **Права — источник немого провала.** `$H/scripts/` = `kraken:kraken`, но
`~/scripts/` = `root:root 755`. Простой `cp` в `~/scripts/` падает на
`Permission denied` (бэкап крона-скрипта так и не сделался с первого раза).
Скрипты генератора — `600 kraken:kraken`; крон-обёртки в `~/scripts/` — `755 root:root`.
**Проверка после заливки — три уровня, все обязательны:**
```bash
md5 -q <локальный файл> # сверка с Кра́кеном
ssh kraken "md5sum $H/scripts/gen_watchlist.py" # суммы должны совпасть
ssh kraken "python3 -m py_compile $H/scripts/gen_watchlist.py && echo OK"
ssh kraken "bash -n ~/scripts/watchlist-catalog.sh && echo OK"
```
### Что задеплоено (2026-09-22)
| Файл | Путь | Права | md5 |
|---|---|---|---|
| генератор | `$H/scripts/gen_watchlist.py` | `kraken:kraken 600` | `3c7d4df34ee20f84b92c1b4be46d8382` |
| маркер | `$H/scripts/mark_missing.py` | `kraken:kraken 600` | `43b3bb15e2aaad1ccb352d705990406c` |
| крон-скрипт | `~/scripts/watchlist-catalog.sh` | `root:root 755` | `17672d62285de5f33e0a89776ba34416` |
Бэкап прежнего генератора: `$H/scripts/gen_watchlist.py.bak-20260922-175754`.
### Боевой прогон (эталон для сравнения)
```bash
ssh kraken "cd $H && python3 $H/scripts/gen_watchlist.py \
/home/kraken/obsidian/family/documents/movies-watchlist.md \
$H/wwwroot/watchlist.json"
```
| Метрика | Значение |
|---|---|
| позиций | **373** |
| без TMDB-ID | **0** |
| films / new / cartoons / anime | 331 / 32 / 3 / 7 |
| постеров | 327 / 32 / 3 / 7 |
| `missing.json` | 30 |
| источники | Radarr 9 · TMDB 343 · автопоиск 2b 17 · 2c 4 · miss 30 |
`watchlist.json` 102 456 Б · `missing.json` 1 239 Б · карточек в `cards/` — 373.
## 🔎 Резолв позиций в каталоге — три уровня (2026-09-22)
Генератор ищет фильм по цепочке, от точного к эвристике:
@@ -109,6 +192,35 @@ related:
⚠️ Порог и `kp_id` — **числовые/машинные критерии**, не ручной словарь соответствий.
Инвариант «никаких ручных правок» не нарушен.
### 🔴 Кэш промахов — генератор чистит его САМ
`~/.lampac_tmdb_cache.json` (на Кра́кене) кэширует и успехи, и **промахи (`None`)**.
Проблема: промах писался **навсегда**. Если Alex правит название так, что ключ кэша
не меняется (регистр, пробел, порядок слов) — запрос в сеть **не уходит**,
возвращается старый `None`, и `❓` не снимается никогда. Плюс копятся `None`
по давно не используемым названиям.
**Решение — `clear_failed_cache(cache)` в генераторе**, вызывается в `main()` сразу
после `load_cache()`:
```python
cleared = clear_failed_cache(cache) # удаляет все None
if cleared:
print(f"[i] кэш: снято промахов {cleared} (будут перепроверены)", file=sys.stderr)
```
- Успешные резолвы (числовой TMDB-ID) **не трогаются** — они верны, а повторная
проверка ~350 записей на каждом прогоне бессмысленна.
- Промахи (~50) перезапрашиваются всегда — это ровно те позиции, ради которых
правки и делаются. Стоимость: секунды.
⚠️ **Ручная чистка больше не нужна.** До этого фикса приходилось гонять
`clear_cache_kraken.py` руками — теперь это часть прогона.
Патч: `~/lampac-tmp/patch_autoclear_cache.py`. Бэкап: `.bak-cacheclear`.
Сумма после заливки: `c556c52b8cf4714686add4083c4afc09`.
### `missing.json` и маркер ❓
Генератор пишет снимок нерезолвленных рядом с каталогом:
@@ -130,14 +242,35 @@ python3 scripts/mark_missing.py --missing <wwwroot>/missing.json <путь.md> [
## 🔄 Ночной крон на Кра́кене — что делает автоматика
**По watchlist заданий ПЯТЬ, а не одно** (проверено `crontab -l`, 2026-09-22):
```
0 1 * * * watchlist-nightly.sh process-thumbs → resolve → sync-down → sync-up
0 9 * * 0 watchlist-discover.sh новинки из KP (воскресенье)
0 2 * * * watchlist-cleanup.sh сносит просмотренное при диске >90%
30 2 * * * watchlist-catalog.sh JSON-каталог для Lampa
0 * * * * sync-vault.sh синк vault (не watchlist, но связан)
```
`~/scripts/watchlist-nightly.sh`, cron **01:00**:
```
sync-vault (pull) → process-thumbs --apply → resolve --recheck --apply
→ sync-down --apply --batch 2 → sync-up --apply → sync-vault (push)
```
`~/scripts/watchlist-catalog.sh`, cron **30 2 * * *** — генерация JSON + рестарт lampac.
`~/scripts/watchlist-cleanup.sh`, cron **0 2 * * *** — сносит просмотренное при заполнении диска.
### 🔴 Разделение ролей: кто пишет в `.md`, кто отправляет в закачку
| Скрипт | Что делает | Закачка |
|---|---|---|
| `discover` (вс 09:00) | **только пишет в `.md`** — добавляет новинки | ❌ ничего не отправляет |
| `sync-down` (в nightly) | шлёт в **Radarr**: `radarr_add()` + `radarr_search()` (`sync_down.py:155,158`) | ✅ отправляет, **но через Radarr**, не напрямую в torrent |
| `resolve --recheck` | резолвит позиции, **снимает маркер сам**, когда фильм найден | ❌ |
| `cleanup` (02:00) | удаляет файлы просмотренного при заполнении диска | ❌ |
| `catalog` (02:30) | генерация JSON + `mark_missing` + `docker restart lampac` | ❌ |
🔴 **Лимит закачки ЕСТЬ.** `--batch 2` — снижен с `5` после инцидента 2026-09-21
(диск 100%). Плюс проверка свободного места `_free_gb()` в `sync_down.py`.
«Проходит весь список без лимитов» — **неверно**, идёт по 2 позиции за прогон.
🔴 **`resolve --recheck --apply` снимает маркер сам**, когда фильм находится.
Это работа резолвера `watchlist_sync/resolver.py` — НЕ генератора каталога и НЕ ручная.
@@ -229,8 +362,35 @@ services:
WAF на префиксе `/catalog/` — **10 запросов/сек**.
### 🔴 Питфолл №1: первая категория игнорирует `format`
### ⚠️ Открытый вопрос: `displayindex` не поднимает «Мой список» выше встроенных блоков
Замечено Alex 2026-09-22: каталог watchlist в ленте идёт **после** блоков
«Сейчас Смотрят» и «Рекомендуем посмотреть». Это **не задумано**.
`watchlist.yaml`: `displayindex: 1` — **самый низкий** из всех каталогов:
| `displayindex` | Каталог |
|---|---|
| **1** | **watchlist («Мой список»)** |
| 10 | Rezka |
| 15 | Kinobase |
| 20 | Filmix, FilmixApp |
| 25 | KinoPub |
| 30 | VoKino |
| 35 | Eneyida |
| 40 | KinoUkr |
| 45 | GetsTV |
| 60 | AniLiberty |
«Сейчас Смотрят» и «Рекомендуем посмотреть» — **встроенные каталоги Lampa**,
их нет в `catalog/sites/`, поэтому `displayindex` их не сдвигает: Lampa держит
свои блоки отдельным списком.
**Что проверять при разборе:** доступен ли приоритет встроенных блоков в
`init.conf`/настройках Lampa, или встроенные всегда идут первыми.
Понижать `displayindex` ниже 1 бессмысленно — он уже минимальный.
### 🔴 Питфолл №1: первая категория игнорирует `format`
`ListController.cs:50` строит базовый URL **до** обработки `format`:
```csharp