[2026-09-25] eagle: personal/plans/lampac-watchlist-plugin.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-25 21:40:31 +06:00
1 parent 7bf5d22101
commit 1d5408abe6
1 file changed
+118 -2
+118 -2
View File
@@ -8,7 +8,7 @@ related:
- '[[family/projects/watchlist-automation]]'
- '[[family/documents/movies-watchlist]]'
- '[[personal/plans/lampac-watched-to-watchlist]]'
status: sync-down-feed-implemented-matcher-parity-blocked
status: investigation-2026-09-25-all-screens-feed-and-latency
tags:
- lampac
- lampa
@@ -24,13 +24,129 @@ tags:
- card-parse
- feed
- matcher-parity
- partnext
- latency
title: Watchlist в UI Lampa — каталог из списка
type: plan
updated: '2026-09-24'
updated: '2026-09-25'
---
# Watchlist в UI Lampa — каталог из списка
## 🔍 2026-09-25: РАССЛЕДОВАНИЕ — фид виден на всех экранах + «долго грузится»
**Жалоба Alex (дословно):** «есть проблема с watchlist фидом в лампе: он отображается
не только на "главной" но даже когда я выбираю категорию например "документальные"
в разделе Фильмы, то есть независимо от активного экрана. и он как будто долго
прогружается относительно основного CUB списка, почему он не моментально проявляется,
он же статичный».
**Статус: расследование завершено, причина установлена, фикс НЕ применён (ждёт апрува).**
### Причина 1 — фид на всех экранах: в `plugin-cub.js` НЕТ фильтра по экрану
Файл: `/Users/admin/lampac-tmp/plugin-cub.js` (196 строк, сборка `build_plugin.py`;
это тот же файл, что залит в Lampac как `module/Catalog/plugin.js`).
`wlPatchPartNext()` (строки 155–193) — перехват глобального `Lampa.Api.partNext`:
```js
Lampa.Api.partNext = function (parts, parts_limit, partLoaded, partEmpty) {
try {
if (Lampa.Arrays.isArray(parts) && !parts.__wl_done) {
var menu = window.__wl_menu;
if (menu && Object.keys(menu).length) {
parts.__wl_done = true;
wlInject(parts, menu); // ← БЕЗУСЛОВНАЯ вставка
}
```
**Ни одного обращения к активному экрану** — нет проверки `Lampa.Activity.active()`,
`activity.url`, `Lampa.Storage.field('source')` или чего-либо подобного.
Механика: `partNext` — глобальный API, через него строят страницу ВСЕ источники.
`plugin.js:30` (`main()`) и `plugin.js:36` (`category()`) **оба** вызывают
`Lampa.Api.partNext(parts_data, parts_limit, ...)`. Отсюда:
- CUB рисует главную → перехват срабатывает → наши 4 секции сверху;
- вход в категорию («документальные» внутри Фильмов) → Lampa перестраивает страницу
через **тот же** `partNext` → перехват срабатывает снова → фид снова сверху.
`wlInject()` (строки 121–127) кладёт секции через `unshift` в **начало** пула, поэтому
они рисуются поверх содержимого любой категории — ровно то, на что жалуется Alex.
### Причина 2 — «долго грузится»: замеры (не догадки)
Всё замерено `curl` на Кра́кене по `127.0.0.1:9118` (порт только изнутри хоста):
| Запрос | Время | `size_download` |
|---|---|---|
| `GET /catalog/list?plugin=watchlist&cat=films` — повторный | **4 мс** | 107 640 |
| тот же — **первый (холодный кэш)** | **2 250 мс** | 107 640 |
| `GET /watchlist-films.json` — чистая статика мимо Catalog | **1 мс** | 88 156 |
| `GET /catalog/list?plugin=watchlist&cat=new` | 2–147 мс | 8 512 |
| **`GET /catalog/card?plugin=watchlist&uri=movie%2F424781&type=movie`** | **66 118 мс** | 939 |
🔴 **ПИТФОЛЛ ЗАМЕРА: `curl -w '%{size_download}'` показывает размер СЖАТОГО тела.**
Я сначала прочитал 107 640 как «фид всего 105 КБ, грузиться нечему» — это ошибка.
Реальные размеры: `watchlist-films.json` = **88 156 несжатых** при 347 позициях,
`cards.json` = **548 219** (данные `ls -la` на Кра́кене). Для замеров объёма брать
`ls -la` или `%{size_download}` вместе с `Accept-Encoding: identity`.
**Что из этого следует:**
1. **4 мс на прогретом кэше** — данные отдаются мгновенно, «статичный» — правда.
2. **2.25 с на ПЕРВОМ холодном запросе категории** — это парсинг JSON парсерами
модуля Catalog (`content.nodes`, `args`) при пустом `hybridCache`. Дальше — кэш.
Отсюда ощущение «не моментально проявляется»: категория, которую давно не открывали,
платит 2+ секунды, а родной CUB-список тем временем уже отрисован.
3. **66 секунд на карточке фильма** — отдельный, более серьёзный баг. 66 с на файл
939 байт из локального каталога — это не диск. `card_parse.initUrl` исполняется как
C#, `node: card`, читается `wwwroot/cards/card-movie-NNN.json`. Внутри
`CardController` что-то ждёт (таймаут внешнего вызова / `reactionsGet` к cub).
**Не диагностировано до конца — следующий шаг.**
4. **Наши секции стартуют позже родных:** `partNext` собирает пул, `parts_limit = 6`,
наши секции идут через `unshift` и грузятся отдельным HTTP-запросом на каждую
(`/catalog/list?plugin=watchlist&cat=<code>`) — 4 запроса. Родной фид CUB приходит
одним запросом, поэтому «проявляется» раньше.
### Контракт Lampac (проверено, НЕ трогать без причины)
`catalog/sites/watchlist.yaml` на Кра́кене
(`/srv/dev-disk-by-uuid-6194539b-.../lampac/catalog/sites/watchlist.yaml`):
- `plugin: watchlist` (🔴 без него ключ = `displayname` = «Мой список» → `ModInit.goInit`
вырезает кириллицу регуляркой `[^a-z0-9\-]` → site="" → HTTP 400 → «ЗДЕСЬ ПУСТО»).
- `host: http://127.0.0.1:9118`, категории `Новинки/Films/Мультфильмы/Аниме`.
- 🔴 **Первая категория в списке ИГНОРИРУЕТ `format`** и берёт `list.uri` напрямую —
поэтому первой стоит «Новинки» (`list.uri: watchlist-new.json`).
- `card_parse.initUrl` конвертирует `uri` `movie/424781` → `cards/card-movie-424781.json`,
`node: card`. `card_args.tmdb_id` обязан быть **числом** (через `format: long.TryParse`),
иначе карточка = «здесь пусто».
**Nightly-пайплайн** (`/home/kraken/scripts/watchlist-nightly.sh`, крон `0 1 * * *`,
пользователь `kraken` НА КРА́КЕНЕ): `sync-vault pull` → `process-thumbs --apply` →
`resolve --recheck --apply` → **`sync-down --apply`** (сборка фида, `LAMPAC_ROOT=`UUID-путь)
→ `sync-up --apply` → backup `TimeCode.sql` (`sqlite3 .backup`) → `sync-from-lampac --apply`
→ `sync-vault push`. Рестарта lampac в скрипте НЕТ и он не нужен (`wwwroot/` bind-mount,
тот же inode) — но при залипшем каталоге в UI помогает обновление страницы / переключение
категории. На 2026-09-25 `watchlist-catalog.sh` уже убран в `.bak-removed-20260924-181942`,
отдельной строки крона `30 2 * * *` в crontab **нет** (п.2 из списка незакрытого — закрыт).
### Открытые шаги (для следующей сессии)
1. **Фикс «фид на всех экранах»:** добавить в `wlPatchPartNext` проверку активного экрана —
инжектить только когда `Lampa.Activity.active()` указывает на главную, иначе
пропускать. Точный предикат определить CDP-пробой на живом ТВ (`probe_ui.py`):
прочитать `Lampa.Activity.active()` на главной и внутри категории, сравнить.
2. **Диагностировать 66 с на карточке** — `docker logs lampac` + трейс `CardController`.
3. **Matcher-parity** (главный блокер с 2026-09-24, см. ниже) — всё ещё не закрыт.
**Правило диагностики этой сессии:** не читать `%{size_download}` как «размер фида»
(это gzip). И — `ifconfig` на Кра́кене отсутствует, ssh-команды через `bash -c` иначе
падают шумом.
---
## 🔴 2026-09-24 (вечер): ПЕРЕПИСЫВАНИЕ — один sync-скрипт вместо отдельного генератора
**Требование Alex:** «перепиши по нормальному чтобы не отдельный скрипт на лампу был