[2026-09-22] eagle: personal/plans/watchlist-tmdb-missing-marker.md personal/tech/lampac-deployment.md
This commit is contained in:
1 parent
d10bc1a5d0
commit
a334332c5b
2 files changed
+382
-6
No files matched your search
@@ -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
|
||||
|
||||
Reference in new issue
Block a user