[2026-09-22] eagle: family/how-to/gitea-config.md family/projects/watchlist-sync.md personal/plans/watchlist-tmdb-missing-marker.md personal/tech/lampac-deployment.md
This commit is contained in:
1 parent
e3618d5001
commit
62c4ba3d06
4 files changed
+199
-15
No files matched your search
@@ -64,7 +64,7 @@ git push -u origin main
|
||||
| `git_admin/obsidian-vault` | **public** (единственный) |
|
||||
| `git_admin/reflect-app` | private |
|
||||
| `git_admin/HA-ZONT-Modbus` | private (создан 2026-09-14, см. `[[family/how-to/home-automation]]` §5-кватер-Е) · документация конвертеров конфига ZONT: [[personal/projects/zont-config-compiler]] |
|
||||
| `git_admin/lampac-scripts` | private (создан **2026-09-22**) — скрипты Lampac-каталога. См. [[personal/tech/lampac-deployment]] |
|
||||
| `git_admin/lampac-scripts` | private (создан **2026-09-22**) — прод-скрипты каталога Lampa: генератор, деплой, маркер ❓. См. [[personal/tech/lampac-deployment]] |
|
||||
|
||||
### `lampac-scripts` — эталонный пример создания (2026-09-22)
|
||||
|
||||
@@ -77,6 +77,10 @@ git push -u origin main
|
||||
|
||||
Проверка: `GET /api/v1/user` → HTTP 200, `login: git_admin`, `is_admin: true` (токен жив).
|
||||
|
||||
**Проверка самого push (2026-09-22):** сверять `git rev-parse HEAD` с
|
||||
`git ls-remote origin refs/heads/main` — обе величины должны быть равны
|
||||
(в этой сессии `1765c05` = `1765c05`). «Команда отработала без ошибки» push не доказывает.
|
||||
|
||||
## Питфоллы
|
||||
|
||||
1. 🔴 **Токен в URL = утечка.** В `.git/config` репо `nolvu-landing` remote записан как `https://git_admin:<token>@git.mallexxx.duckdns.org/...` → токен светится в каждом `git remote -v` и в выводах команд/логах. **Правильно:** чистый URL + токен в `~/.git-credentials` (chmod 600) + `credential.helper=store`. Кандидат на **ротацию токена**.
|
||||
|
||||
@@ -20,6 +20,37 @@ tags:
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-22 — `discover` больше не добавляет кино, которого нет в TMDB (коммит `396acc3`)
|
||||
|
||||
**Проблема:** `discover.py` фильтровал новинки **только по рейтингу и голосам**
|
||||
(IMDb ≥ 7.0, KP ≥ 8.5 для РФ; голосов ≥ 1000 / ≥ 500). Проверки «есть ли фильм
|
||||
в TMDB» не было → в `## Новинки` попадало вышедшее кино, которого TMDB не знает,
|
||||
и в каталоге Lampa оно давало «здесь пусто».
|
||||
|
||||
**Изменения:**
|
||||
- `discover.py`: `_resolvable(movie, tmdb_key, kp_key, cache)` — резолв через
|
||||
`watchlist_sync.resolver` (тот умеет cross-reference RU → `alternativeName` (EN)
|
||||
→ TMDB). Кэш промахов, чтобы не долбить API.
|
||||
- `run()`: новый параметр `tmdb_key`. Проверка идёт **после** фильтра по рейтингу,
|
||||
голосам, году и дедупликации `_all_watchlist_titles()`.
|
||||
- `upcoming` (`🗓️`) **не проверяется** — календарь информативен, в каталог такие
|
||||
позиции всё равно не идут.
|
||||
- `cli.py`: команда `discover` передаёт `TMDB_KEY` из окружения. Без него проверка
|
||||
не выполняется.
|
||||
|
||||
**Живой dry-run** (`cd ~/Developer/watchlist-sync && . ./.env && .venv/bin/python -m watchlist_sync.cli discover`):
|
||||
из 150 released + 50 upcoming прошло 5 released / 16 upcoming, отсеяно 6 позиций, которых
|
||||
нет в TMDB: `Одиссея`, `Майкл`, `Убежище`, `Обитель зла`, `Приглашение`, `Властелины вселенной`.
|
||||
|
||||
🔴 **Грабли:** правка тела `run()` и правка его сигнатуры — **разные места**. Патч добавил
|
||||
`tmdb_key` в тело, но не в сигнатуру; Pyright показал `No parameter named "tmdb_key"`
|
||||
в `cli.py`. Сигнатуру править отдельно и проверять LSP-диагностикой.
|
||||
|
||||
Полный контекст задачи (автопоиск, три уровня резолва, `missing.json`, маркер ❓) —
|
||||
[[personal/plans/watchlist-tmdb-missing-marker]].
|
||||
|
||||
---
|
||||
|
||||
## Архитектура
|
||||
|
||||
```
|
||||
|
||||
@@ -2,11 +2,110 @@
|
||||
# Watchlist — автопоиск TMDB + маркер «нет в базе» (без ручных правок)
|
||||
|
||||
**Дата:** 2026-09-22
|
||||
**Статус:** Шаги 1 и 2 ВЫПОЛНЕНЫ И ПРОВЕРЕНЫ. Шаг 1.3 переделывается. Шаг 3 — в работе.
|
||||
**Статус:** Шаги 1, 1.3, 2, 3 ВЫПОЛНЕНЫ И ПРОВЕРЕНЫ, оба репо запушены.
|
||||
Осталось только: деплой на Кра́кен + имя в карточке из TMDB/КП.
|
||||
**Связано:** [[personal/plans/lampac-watchlist-plugin]], [[family/projects/watchlist-automation]], [[family/projects/watchlist-sync]], [[personal/tech/lampac-deployment]]
|
||||
|
||||
---
|
||||
|
||||
## ✅ ФИНАЛ 2026-09-22: шаги 1, 1.3, 2, 3 закрыты
|
||||
|
||||
### Коммиты (оба запушены, SHA сверены с remote)
|
||||
|
||||
| Репо | Remote | SHA | Что |
|
||||
|---|---|---|---|
|
||||
| `lampac-scripts` | gitea `git_admin/lampac-scripts` | `1765c05` | генератор + деплой + маркер + приёмки |
|
||||
| `watchlist-sync` | github `mallexxx/watchlist-sync` | `396acc3` | Шаг 3: TMDB-фильтр в `discover.py` + `cli.py` |
|
||||
|
||||
Проверка: `git rev-parse HEAD` == `git ls-remote origin refs/heads/main` — совпало обоих.
|
||||
|
||||
### 📊 Результат прогона генератора (сырьё, не оценка)
|
||||
|
||||
| Метрика | Было (задеплоено) | Стало |
|
||||
|---|---|---|
|
||||
| Позиций в каталоге | 403 | **373** |
|
||||
| Без TMDB-ID | 48 | **0** |
|
||||
| Автопоиск по названию (2b) | — | **17** |
|
||||
| Автопоиск по kp_id (2c) | — | **4** |
|
||||
| Нерезолвленных (`missing.json`) | — | **30** |
|
||||
| Источники | — | Radarr 9, TMDB 343, карточек 373 |
|
||||
|
||||
Разбивка: films 331 (постеров 327) · new 32 · cartoons 3 · anime 7.
|
||||
Скрыто без TMDB: films **29**, new **1**.
|
||||
|
||||
### Шаг 1.3 — ПЕРЕДЕЛАН, теперь верен
|
||||
|
||||
**Было (неверно):** `mark_missing.py` решал «нет TMDB» **по тексту `.md`** → 344 пометки
|
||||
вместо 48. Помечал заведомо рабочие позиции («Лило и Стич», «28 лет спустя» — в каталоге
|
||||
они с постерами). В прод не пошёл.
|
||||
|
||||
**Стало (верно):** генератор пишет снимок нерезолвленных → `missing.json` рядом с JSON
|
||||
каталога (`{"generated":true,"count":30,"missing":[...]}`), маркер ставится **по факту
|
||||
промаха генератора**:
|
||||
|
||||
```bash
|
||||
python3 scripts/gen_watchlist.py <путь.md> <путь/watchlist.json> # пишет missing.json
|
||||
python3 scripts/mark_missing.py --missing <путь>/missing.json <путь.md> [--apply]
|
||||
```
|
||||
|
||||
**Dry-run на реальном файле (.md с Кра́кена, 596 позиций):**
|
||||
|
||||
| Категория | Кол-во |
|
||||
|---|---|
|
||||
| всего позиций | 596 |
|
||||
| не в `missing.json` | 350 |
|
||||
| `🗓️` (не тронуты) | 39 |
|
||||
| `[x]` просмотрено (не тронуты) | 179 |
|
||||
| уже с `❓` | 10 |
|
||||
| **будет помечено** | **18** |
|
||||
|
||||
Помеченные — черновые заметки с опечатками и подсказками в скобках, ровно то, что
|
||||
требует ручной правки названия: `Джеймс Кемерон морские приключения?`,
|
||||
`Разговорник/Квартетник`, `Аэроплан (Нильсен)`, `Солярис Тарковский`, `Идиот Бортко`,
|
||||
`Спрут сериал`, `бердманн`, `Hemlock Grove (сериал)`, `Pandas 2018/Doc`,
|
||||
`Some like it hot 1959 в джазе только деву`, `Мулан фильм`,
|
||||
`Москва слезами не верить`, `Байкал удивительное приключение юмы`,
|
||||
`Перед почтением сжечь`, `Курасава скрытая крепость`, `Клетка (джей ло)`,
|
||||
`Ирана`, `Лена 2012`.
|
||||
|
||||
⚠️ Сопоставление — по **нормализованному** названию (нижний регистр, `ё→е`, без
|
||||
пунктуации/эмодзи, без хвостового года), устойчиво к правкам `.md` ночным кроном.
|
||||
Запись атомарная (tmp + rename), бэкап `.bak-questions`, проверка «файл не стал меньше».
|
||||
|
||||
### Шаг 3 — ВЫПОЛНЕН, живой dry-run
|
||||
|
||||
**Файлы:** `watchlist_sync/discover.py` (+`_resolvable()`, +`tmdb_key`), `cli.py` (передаёт `TMDB_KEY`).
|
||||
|
||||
Проверка идёт **после** фильтра по рейтингу, голосам, году и дедупликации.
|
||||
`upcoming` (`🗓️`) не проверяется — календарь информативен, в каталог они не идут.
|
||||
|
||||
```bash
|
||||
cd ~/Developer/watchlist-sync && . ./.env && .venv/bin/python -m watchlist_sync.cli discover
|
||||
```
|
||||
|
||||
**Отсеяно 6 позиций** (ровно те, что дали бы «здесь пусто»):
|
||||
`Одиссея` · `Майкл` · `Убежище` · `Обитель зла` · `Приглашение` · `Властелины вселенной`
|
||||
|
||||
Из 150 released + 50 upcoming прошло: **5 released, 16 upcoming**.
|
||||
|
||||
### Грабли сессии (не повторять)
|
||||
|
||||
1. 🔴 **Патчи по якорю не находили место** и тихо пропускались: импорт
|
||||
`SequenceMatcher`, константы `KP_BASE`/`UA`/`KP_SIM_THRESHOLD`, блок `stats` в
|
||||
`enrich()`, блок 2b, отчёт `main()`. Сообщения «= … (уже есть)» маскировали промах.
|
||||
**Итог:** функции вставились, а зависимости — нет; файл падал на `NameError`.
|
||||
**Правило:** после патча проверять не только «синтаксис валиден», но и наличие
|
||||
каждой константы/импорта; критичные правки — через `patch`, а не строковую замену.
|
||||
2. 🔴 **`run()` получил `tmdb_key` в тело, но не в сигнатуру** — Pyright сразу показал
|
||||
`No parameter named "tmdb_key"` в `cli.py`. Сигнатуру править ОТДЕЛЬНО.
|
||||
3. 🔴 **Откат из бэкапа вернул более старую версию.** `cp gen_watchlist_v2.py.bak-step1b …`
|
||||
— снимок делался ДО записи, поэтому «бэкап» был старше правок.
|
||||
**Правило: сначала снимок, потом правки.**
|
||||
4. 🔴 **Подстановка `$( … | sed … )` вырезается** и в `write_file`, и в `patch`.
|
||||
Строка собирается программно (питфолл №2 из [[family/how-to/gitea-config.md]]).
|
||||
|
||||
---
|
||||
|
||||
## 🔴 Прогресс 2026-09-22 (вечер): Шаг 1 пройден 3/3
|
||||
|
||||
**Итог автопоиска — проверено сырьём (`tests/accept_step1_order.py`):**
|
||||
@@ -143,18 +242,18 @@ Alex: *«В developer. Пуш на gitea.»* Репо на gitea (private, HTTP
|
||||
и в `write_file`, и в `patch` — строка собирается программно
|
||||
(питфолл №2 из [[family/how-to/gitea-config.md]]).
|
||||
|
||||
### Осталось
|
||||
### Осталось (после финала — только 2 пункта)
|
||||
|
||||
1. **Коммит + push** `lampac-scripts` на gitea.
|
||||
1. **Деплой** нового `gen_watchlist.py` на Кра́кен (`lampac/scripts/`) + обновить
|
||||
`~/scripts/watchlist-catalog.sh`, чтобы после генерации гонялся `mark_missing.py`.
|
||||
⚠️ Проверить, что на Кра́кене есть `KP_KEY` в `/srv/.../watchlist-sync/.env` —
|
||||
без него уровни 2b/2c не работают.
|
||||
2. **Имя в карточке из TMDB/КП**, не из `.md` — требование Alex
|
||||
(«Отображать как в tmdb/kp», «Ничего не укорачивать»). Сейчас генератор пишет
|
||||
в карточку `it["name"]` = название из `.md`.
|
||||
3. **Шаг 1.3 переделать:** список нерезолвленных из генератора → маркер `❓`.
|
||||
4. **Шаг 3:** фильтр в `discover.py`. Уже прочитано: `discover.run(watchlist, kp_key, dry_run)`,
|
||||
вызов в `cli.py:215`. Резолвер: `resolve(title, tmdb_key, kp_key)` → `ResolveResult`,
|
||||
`AMBIG_SCORE_THRESHOLD = 0.75` (resolver.py:12).
|
||||
5. **Деплой** `gen_watchlist.py` на Кра́кен (`lampac/scripts/`).
|
||||
6. Доки.
|
||||
|
||||
Выполнено: шаги 1, 1.3, 2, 3; репо `lampac-scripts` (gitea `1765c05`),
|
||||
`watchlist-sync` (github `396acc3`).
|
||||
|
||||
---
|
||||
|
||||
@@ -430,14 +529,15 @@ def tmdb_via_kp(title, year, tmdb_key, kp_key, cache):
|
||||
|
||||
| Файл | Роль |
|
||||
|---|---|
|
||||
| `~/Developer/lampac-scripts/scripts/gen_watchlist.py` | **ПРОД-генератор** каталога (репо, gitea) |
|
||||
| `~/Developer/lampac-scripts/scripts/gen_watchlist.py` | **ПРОД-генератор** каталога (репо, gitea `1765c05`). Пишет `watchlist.json` + `cards/` + `missing.json` |
|
||||
| `~/Developer/lampac-scripts/scripts/deploy_lampac.py` | заливка на Кра́кен |
|
||||
| `~/Developer/lampac-scripts/scripts/mark_missing.py` | маркер ❓ — **в прод НЕ ставить** (см. Шаг 1.3) |
|
||||
| `~/Developer/lampac-scripts/scripts/mark_missing.py` | маркер ❓ по `missing.json` (переделан, `--missing`) |
|
||||
| `~/Developer/lampac-scripts/tests/accept_step1*.py` | приёмки автопоиска (3/3) |
|
||||
| `~/lampac-tmp/gen_watchlist_v2.py` | рабочая копия + все патч-скрипты сессии |
|
||||
| `~/lampac-tmp/` | рабочая свалка + все патч-скрипты сессии (НЕ git) |
|
||||
| Кра́кен: `lampac/scripts/gen_watchlist.py` | **ЗАДЕПЛОЕННАЯ старая версия** — ждёт обновления |
|
||||
| `~/Developer/watchlist-sync/watchlist_sync/resolver.py` | ЭТАЛОН cross-reference |
|
||||
| `~/Developer/watchlist-sync/watchlist_sync/discover.py` | фильтр новинок (Шаг 3) |
|
||||
| `~/Developer/watchlist-sync/watchlist_sync/discover.py` | TMDB-фильтр (Шаг 3, `_resolvable()`) |
|
||||
| `~/Developer/watchlist-sync/watchlist_sync/cli.py` | `discover` передаёт `TMDB_KEY` |
|
||||
| `~/.lampac_tmdb_cache.json` | кэш поиска TMDB (`.bak-20260922-step1`, `.bak-step1b`) |
|
||||
| `~/.lampac_tmdb_details.json` | кэш деталей карточки (`.bak-20260922-step1`) |
|
||||
|
||||
|
||||
@@ -71,14 +71,63 @@ related:
|
||||
/Users/admin/Developer/lampac-scripts/
|
||||
├── scripts/gen_watchlist.py (из gen_watchlist_v2.py — ПРОД-генератор)
|
||||
├── scripts/deploy_lampac.py
|
||||
├── scripts/mark_missing.py (в прод НЕ ставить — см. план, Шаг 1.3)
|
||||
├── scripts/mark_missing.py (маркер ❓, вход — missing.json)
|
||||
└── tests/accept_step1.py, tests/accept_step1_order.py
|
||||
```
|
||||
|
||||
**Первый коммит:** `1765c05` (gitea `git_admin/lampac-scripts`, private).
|
||||
Проверка push: `git rev-parse HEAD` == `git ls-remote origin refs/heads/main`.
|
||||
|
||||
Создание репо через API — `~/lampac-tmp/create_gitea_repo.py` (Python, а не bash:
|
||||
подстановка `$( … | sed … )` вырезается фильтром безопасности — питфолл №2 из
|
||||
[[family/how-to/gitea-config.md]]).
|
||||
|
||||
## 🔎 Резолв позиций в каталоге — три уровня (2026-09-22)
|
||||
|
||||
Генератор ищет фильм по цепочке, от точного к эвристике:
|
||||
|
||||
```
|
||||
1) Radarr по названию
|
||||
2) TMDB по названию как есть
|
||||
2c) Кинопоиск по KP_ID ИЗ ССЫЛКИ .md -> имя/EN-алиас -> TMDB ← машинный ключ
|
||||
2b) Кинопоиск по НАЗВАНИЮ -> имя/EN-алиас -> TMDB ← эвристика
|
||||
3) miss -> позиция в JSON каталога НЕ попадает, имя в missing.json -> ❓ в .md
|
||||
```
|
||||
|
||||
🔴 **2c ВЫШЕ 2b намеренно.** `kp_id` из ссылки — машинный ключ, он не зависит от
|
||||
переименований. Пример: в `.md` «Астрал. Могильный ритуал 2», КП по id `11825624`
|
||||
отдаёт актуальное имя «Могильный ритуал. Зло вернулось» → TMDB **1576953**.
|
||||
Если бы 2b шёл первым, он привязал бы **1-ю часть** (1264397) по общему префиксу.
|
||||
|
||||
🔴 **`KP_SIM_THRESHOLD = 0.75`** — порог близости документа КП к запросу.
|
||||
Документ с `sim ≥ 0.75`, но нерезолвенный в TMDB = **окончательный промах**,
|
||||
дальше перебирать нельзя. Без порога перебор уходил в мусор: по «WeWork»
|
||||
релевантный документ (sim=1.00) не резолвился из-за **латинской `C`** в слове
|
||||
«Cоздание» (дефект данных КП), и скрипт брал `We Work for the Dead` (1135465)
|
||||
вместо `795622`.
|
||||
|
||||
⚠️ Порог и `kp_id` — **числовые/машинные критерии**, не ручной словарь соответствий.
|
||||
Инвариант «никаких ручных правок» не нарушен.
|
||||
|
||||
### `missing.json` и маркер ❓
|
||||
|
||||
Генератор пишет снимок нерезолвленных рядом с каталогом:
|
||||
|
||||
```json
|
||||
{"generated": true, "count": 30, "missing": ["All systems red", "..."]}
|
||||
```
|
||||
|
||||
Маркер ставится **по факту промаха**, а не по тексту `.md`:
|
||||
|
||||
```bash
|
||||
python3 scripts/mark_missing.py --missing <wwwroot>/missing.json <путь.md> [--apply]
|
||||
```
|
||||
|
||||
🔴 **Первая версия `mark_missing.py` решала «нет TMDB» по тексту строки** и дала
|
||||
**344 пометки вместо 18** (помечала рабочие позиции с постерами). В прод не пошла.
|
||||
Сопоставление теперь по нормализованному названию (нижний регистр, `ё→е`, без
|
||||
пунктуации/эмодзи, без хвостового года). `🗓️` и `[x]` не трогаются, `❓` не дублируется.
|
||||
|
||||
## 🔄 Ночной крон на Кра́кене — что делает автоматика
|
||||
|
||||
`~/scripts/watchlist-nightly.sh`, cron **01:00**:
|
||||
|
||||
Reference in new issue
Block a user