[2026-09-25] eagle: personal/plans/lampac-watchlist-plugin.md
This commit is contained in:
1 parent
a0d298568c
commit
aed8c42aa3
1 file changed
+162
-18
@@ -8,7 +8,7 @@ related:
|
|||||||
- '[[family/projects/watchlist-automation]]'
|
- '[[family/projects/watchlist-automation]]'
|
||||||
- '[[family/documents/movies-watchlist]]'
|
- '[[family/documents/movies-watchlist]]'
|
||||||
- '[[personal/plans/lampac-watched-to-watchlist]]'
|
- '[[personal/plans/lampac-watched-to-watchlist]]'
|
||||||
status: investigation-2026-09-25-all-screens-feed-and-latency
|
status: main-screen-filter-implemented-2026-09-25-awaiting-tv-acceptance
|
||||||
tags:
|
tags:
|
||||||
- lampac
|
- lampac
|
||||||
- lampa
|
- lampa
|
||||||
@@ -26,6 +26,7 @@ tags:
|
|||||||
- matcher-parity
|
- matcher-parity
|
||||||
- partnext
|
- partnext
|
||||||
- latency
|
- latency
|
||||||
|
- wlonmain
|
||||||
title: Watchlist в UI Lampa — каталог из списка
|
title: Watchlist в UI Lampa — каталог из списка
|
||||||
type: plan
|
type: plan
|
||||||
updated: '2026-09-25'
|
updated: '2026-09-25'
|
||||||
@@ -41,14 +42,82 @@ updated: '2026-09-25'
|
|||||||
прогружается относительно основного CUB списка, почему он не моментально проявляется,
|
прогружается относительно основного CUB списка, почему он не моментально проявляется,
|
||||||
он же статичный».
|
он же статичный».
|
||||||
|
|
||||||
**Статус: расследование завершено, причина установлена, фикс НЕ применён (ждёт апрува).**
|
**Статус: ✅ ФИКС ПРИМЕНЁН И ЗАЛИТ 2026-09-25. Ждёт только перезапуска Lampa на ТВ
|
||||||
|
(ТВ `192.168.1.70` был выключен — ни ping, ни CDP-порт 9998 не отвечали).**
|
||||||
|
|
||||||
### Причина 1 — фид на всех экранах: в `plugin-cub.js` НЕТ фильтра по экрану
|
### ✅ РЕШЕНИЕ: `wlOnMain()` — строгий белый список по активному activity
|
||||||
|
|
||||||
Файл: `/Users/admin/lampac-tmp/plugin-cub.js` (196 строк, сборка `build_plugin.py`;
|
Alex: «В смысле всё кроме? **Только главный экран!**» — предикат сделан ЖЁСТКИМ
|
||||||
|
(`=== 'main'`), не «всё кроме списка исключений». Любое незнакомое имя activity
|
||||||
|
обязано по умолчанию секции НЕ получать.
|
||||||
|
|
||||||
|
```js
|
||||||
|
function wlOnMain() {
|
||||||
|
try {
|
||||||
|
var a = (window.Lampa && Lampa.Activity && Lampa.Activity.active)
|
||||||
|
? Lampa.Activity.active() : null;
|
||||||
|
var act = (a && a.activity && a.activity.url) ? a.activity.url : '';
|
||||||
|
if (act === 'main') return true;
|
||||||
|
console.log('[watchlist] не главная (' + (act || '?') + ') — секции пропущены');
|
||||||
|
return false;
|
||||||
|
} catch (e) {
|
||||||
|
console.log('[watchlist] wlOnMain error', e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Гард в перехватчике (`plugin-cub.js:193`):
|
||||||
|
```js
|
||||||
|
if (wlOnMain() && Lampa.Arrays.isArray(parts) && !parts.__wl_done) { ... wlInject(parts, menu); }
|
||||||
|
```
|
||||||
|
|
||||||
|
🔴 **Второе, неочевидное изменение:** `parts.__wl_done = true` теперь ставится ТОЛЬКО
|
||||||
|
внутри ветки фактической вставки. Раньше флаг мог выставиться до готовности
|
||||||
|
`window.__wl_menu` — и тогда вставка была бы закрыта НАВСЕГДА, главная осталась бы без
|
||||||
|
секций после возврата из категории.
|
||||||
|
|
||||||
|
**Файлы:**
|
||||||
|
- `/Users/admin/lampac-tmp/plugin-cub.js` — рабочая сборка (бэкап
|
||||||
|
`plugin-cub.js.bak-before-filter-<ts>`)
|
||||||
|
- `/Users/admin/lampac-tmp/build_plugin.py` — тот же текст в константе `INJECT`
|
||||||
|
(сборщик детерминированный; `plugin-cub.js` руками не правим) + **2 новых инварианта**:
|
||||||
|
`wlOnMain def` и `wlOnMain guard` — сборка падает, если фильтр пропал
|
||||||
|
|
||||||
|
**Проверки перед заливкой (все пройдены):**
|
||||||
|
```
|
||||||
|
python3 build_plugin.py → 10/10 инвариантов, 17241 байт
|
||||||
|
node --check plugin-cub.js → SYNTAX OK
|
||||||
|
```
|
||||||
|
|
||||||
|
**Деплой (выполнен):**
|
||||||
|
1. бэкап боевого — `catalog/plugin.js.bak-before-mainfilter-20260925-220809` (17476 Б)
|
||||||
|
2. `scp plugin-cub.js kraken:...6194539b.../lampac/catalog/plugin.js` → 19576 Б,
|
||||||
|
md5 `53ccdc306cf6a14f343eaeb67a8a29c3`
|
||||||
|
3. bind-mount проверен: `docker exec lampac grep -c wlOnMain
|
||||||
|
/lampac/module/Catalog/plugin.js` → **3**
|
||||||
|
4. по HTTP тоже отдаётся: `curl http://127.0.0.1:9118/catalog.js` → 41050 Б, `wlOnMain` ×3
|
||||||
|
|
||||||
|
**Осталось — перезапуск Lampa на ТВ** (webOS кэширует `catalog.js`, `docker restart
|
||||||
|
lampac` его НЕ сбрасывает):
|
||||||
|
```bash
|
||||||
|
scp /Users/admin/lampac-tmp/tv_restart.sh root@192.168.1.70:/tmp/ \
|
||||||
|
&& ssh root@192.168.1.70 'sh /tmp/tv_restart.sh'
|
||||||
|
```
|
||||||
|
|
||||||
|
**Приёмка = видно в UI** (не «API отвечает»): главная — 4 секции Watchlist сверху;
|
||||||
|
Фильмы → документальные — секций НЕТ. Если фид вылезет ещё где-то — в логе ТВ будет
|
||||||
|
строка `[watchlist] не главная (<имя>)`, по ней добавить имя в разбор.
|
||||||
|
|
||||||
|
**Что НЕ трогалось:** `window.__wl_menu`, `wlGet`/`wlAbs`/`wlHost`, `unshift`,
|
||||||
|
`watchlist.yaml`, `sync_down.py`, nightly-пайплайн.
|
||||||
|
|
||||||
|
### Причина 1 (диагноз) — в `plugin-cub.js` НЕ БЫЛО фильтра по экрану
|
||||||
|
|
||||||
|
Файл: `/Users/admin/lampac-tmp/plugin-cub.js` (сборка `build_plugin.py`;
|
||||||
это тот же файл, что залит в Lampac как `module/Catalog/plugin.js`).
|
это тот же файл, что залит в Lampac как `module/Catalog/plugin.js`).
|
||||||
|
|
||||||
`wlPatchPartNext()` (строки 155–193) — перехват глобального `Lampa.Api.partNext`:
|
`wlPatchPartNext()` — перехват глобального `Lampa.Api.partNext` — до фикса выглядел так:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
Lampa.Api.partNext = function (parts, parts_limit, partLoaded, partEmpty) {
|
Lampa.Api.partNext = function (parts, parts_limit, partLoaded, partEmpty) {
|
||||||
@@ -61,18 +130,16 @@ Lampa.Api.partNext = function (parts, parts_limit, partLoaded, partEmpty) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ни одного обращения к активному экрану** — нет проверки `Lampa.Activity.active()`,
|
**Ни одного обращения к активному экрану** — это не регресс, а исходное отсутствие
|
||||||
`activity.url`, `Lampa.Storage.field('source')` или чего-либо подобного.
|
проверки. Механика: `partNext` — глобальный API, через него строят страницу ВСЕ
|
||||||
|
источники. `plugin.js:30` (`main()`) и `plugin.js:36` (`category()`) **оба** вызывают
|
||||||
Механика: `partNext` — глобальный API, через него строят страницу ВСЕ источники.
|
|
||||||
`plugin.js:30` (`main()`) и `plugin.js:36` (`category()`) **оба** вызывают
|
|
||||||
`Lampa.Api.partNext(parts_data, parts_limit, ...)`. Отсюда:
|
`Lampa.Api.partNext(parts_data, parts_limit, ...)`. Отсюда:
|
||||||
- CUB рисует главную → перехват срабатывает → наши 4 секции сверху;
|
- CUB рисует главную → перехват срабатывает → наши 4 секции сверху;
|
||||||
- вход в категорию («документальные» внутри Фильмов) → Lampa перестраивает страницу
|
- вход в категорию («документальные» внутри Фильмов) → Lampa перестраивает страницу
|
||||||
через **тот же** `partNext` → перехват срабатывает снова → фид снова сверху.
|
через **тот же** `partNext` → перехват срабатывает снова → фид снова сверху.
|
||||||
|
|
||||||
`wlInject()` (строки 121–127) кладёт секции через `unshift` в **начало** пула, поэтому
|
`wlInject()` кладёт секции через `unshift` в **начало** пула, поэтому они рисуются
|
||||||
они рисуются поверх содержимого любой категории — ровно то, на что жалуется Alex.
|
поверх содержимого любой категории — ровно то, на что жаловался Alex.
|
||||||
|
|
||||||
### Причина 2 — «долго грузится»: замеры (не догадки)
|
### Причина 2 — «долго грузится»: замеры (не догадки)
|
||||||
|
|
||||||
@@ -134,16 +201,25 @@ Lampa.Api.partNext = function (parts, parts_limit, partLoaded, partEmpty) {
|
|||||||
|
|
||||||
### Открытые шаги (для следующей сессии)
|
### Открытые шаги (для следующей сессии)
|
||||||
|
|
||||||
1. **Фикс «фид на всех экранах»:** добавить в `wlPatchPartNext` проверку активного экрана —
|
1. ✅ **ЗАКРЫТО 2026-09-25** — фикс «фид на всех экранах»: `wlOnMain()` + гард в
|
||||||
инжектить только когда `Lampa.Activity.active()` указывает на главную, иначе
|
`wlPatchPartNext`, залито на Кра́кен. Осталась приёмка на ТВ (перезапуск Lampa +
|
||||||
пропускать. Точный предикат определить CDP-пробой на живом ТВ (`probe_ui.py`):
|
визуальная проверка главной и «Фильмы → документальные»).
|
||||||
прочитать `Lampa.Activity.active()` на главной и внутри категории, сравнить.
|
|
||||||
2. **Диагностировать 66 с на карточке** — `docker logs lampac` + трейс `CardController`.
|
2. **Диагностировать 66 с на карточке** — `docker logs lampac` + трейс `CardController`.
|
||||||
|
Единственный замеренный источник ощущения «не моментально», который НЕ объясняется
|
||||||
|
холодным `hybridCache` (2.25 с). Запрос:
|
||||||
|
`GET /catalog/card?plugin=watchlist&uri=movie%2F424781&type=movie` → 66 118 мс, 939 Б.
|
||||||
3. **Matcher-parity** (главный блокер с 2026-09-24, см. ниже) — всё ещё не закрыт.
|
3. **Matcher-parity** (главный блокер с 2026-09-24, см. ниже) — всё ещё не закрыт.
|
||||||
|
|
||||||
**Правило диагностики этой сессии:** не читать `%{size_download}` как «размер фида»
|
**Правило диагностики этой сессии:** не читать `%{size_download}` как «размер фида»
|
||||||
(это gzip). И — `ifconfig` на Кра́кене отсутствует, ssh-команды через `bash -c` иначе
|
(это gzip) — брать `ls -la` или `Accept-Encoding: identity`. И — `ifconfig` на Кра́кене
|
||||||
падают шумом.
|
отсутствует: каждая ssh-команда печатает `bash: line 1: ifconfig: command not found`
|
||||||
|
безвредным шумом, это НЕ ошибка команды.
|
||||||
|
|
||||||
|
**🔴 Питфолл инструментов этой сессии:** `execute_code` падал на `import`
|
||||||
|
(`No module named 'psutil'`) — расследование и правки сделаны через `terminal` +
|
||||||
|
`read_file` + `patch`, БЕЗ python-скриптов. `scp` файла `wwwroot/catalog.js` не нашёл:
|
||||||
|
такого пути НЕТ, `plugin.js` живёт в `lampac/catalog/plugin.js` и монтируется в
|
||||||
|
`/lampac/module/Catalog/plugin.js`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -492,6 +568,74 @@ Alex уточнил требование: «это же чистая дораб
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 🟢 ВОСЬМАЯ СЕССИЯ 2026-09-25: ФИЛЬТР «СЕКЦИИ ТОЛЬКО НА ГЛАВНОЙ» (PLAN)
|
||||||
|
|
||||||
|
**Задача Alex:** «watchlist фид отображается не только на главной, но даже когда я
|
||||||
|
выбираю категорию например "документальные" в разделе Фильмы» + «он как будто долго
|
||||||
|
прогружается относительно основного CUB списка». Требование: **ТОЛЬКО ГЛАВНЫЙ ЭКРАН**
|
||||||
|
(белый список, не чёрный — Alex: «В смысле всё кроме? Только главный экран!»).
|
||||||
|
|
||||||
|
### Диагноз (по коду, замеры)
|
||||||
|
|
||||||
|
1. **Причина «на любом экране».** `plugin-cub.js:164` — `wlPatchPartNext` вставляет
|
||||||
|
секции БЕЗУСЛОВНО:
|
||||||
|
```js
|
||||||
|
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.Api.partNext` — глобальный: через него строят страницу И `main()`
|
||||||
|
(`plugin.js:30`), И `category()` (`plugin.js:36`). Никакой проверки активного
|
||||||
|
экрана нет → `unshift` кладёт секции в голову пула на КАЖДОМ экране.
|
||||||
|
Фильтра по activity в коде НЕ БЫЛО — это не регресс, а исходное отсутствие.
|
||||||
|
|
||||||
|
2. **Замеры скорости (Kraken, `127.0.0.1:9118`):**
|
||||||
|
- `catalog/list?cat=films` прогретый кэш — **4 мс**; первый холодный — **2 250 мс**
|
||||||
|
(`hybridCache` модуля Catalog парсит JSON целиком при первом запросе)
|
||||||
|
- `watchlist-films.json` (чистая статика) — 1 мс
|
||||||
|
- 🔴 `catalog/card?uri=movie/424781` — **66 118 мс (66 сек!)** на 939 байт.
|
||||||
|
Это НЕ диск и не фид: `card_parse.initUrl` исполняется как C# и ждёт внутри
|
||||||
|
CardController. Отдельный баг, в эту правку не входит.
|
||||||
|
- ⚠️ `curl -w %{size_download}` показывает размер **после** распаковки gzip —
|
||||||
|
на этом легко обмануться: `watchlist-films.json` = 88 КБ несжатых при 347
|
||||||
|
позициях, а `cards.json` = **548 КБ**. Реальный объём фида в разы больше «видимого».
|
||||||
|
|
||||||
|
### Решение
|
||||||
|
|
||||||
|
Белый список по активному activity Lampa:
|
||||||
|
```js
|
||||||
|
function wlOnMain() {
|
||||||
|
try {
|
||||||
|
var a = Lampa.Activity && Lampa.Activity.active && Lampa.Activity.active();
|
||||||
|
var act = (a && a.activity && a.activity.url) ? a.activity.url : '';
|
||||||
|
return act === 'main'; // ТОЛЬКО главная
|
||||||
|
} catch (e) { return false; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Плюс `parts.__wl_done = true` ставить ТОЛЬКО при фактической вставке (иначе после
|
||||||
|
возврата из категории на главную секции не доберутся). `console.log` при пропуске —
|
||||||
|
для отладки на живом ТВ.
|
||||||
|
|
||||||
|
### Шаги
|
||||||
|
|
||||||
|
1. правка `plugin-cub.js` + `build_plugin.py` (INJECT + новый инвариант `wlOnMain`)
|
||||||
|
2. `python3 build_plugin.py && node --check plugin-cub.js`
|
||||||
|
3. бэкап боевого `catalog/plugin.js` → `scp` нового
|
||||||
|
4. **перезапуск Lampa на ТВ обязателен** (`tv_restart.sh` через `luna-send`;
|
||||||
|
`docker restart lampac` кэш webOS не сбрасывает)
|
||||||
|
5. 🔴 приёмка = **видно в UI**: главная — 4 секции сверху; Фильмы → документальные —
|
||||||
|
секций НЕТ. CDP-проба читает `Lampa.Activity.active().activity.url` на обоих экранах.
|
||||||
|
|
||||||
|
### Питфоллы, найденные при расследовании (не повторять)
|
||||||
|
|
||||||
|
- `ssh kraken` на каждом вызове печатает `bash: line 1: ifconfig: command not found` —
|
||||||
|
это безвредный шум из `~/.bashrc`, НЕ ошибка команды.
|
||||||
|
- 🔴 `execute_code` в этой сессии падает на `import` (`No module named 'psutil'`) —
|
||||||
|
работаем через `terminal` + `read_file` + `jq`, БЕЗ python.
|
||||||
|
- Обрыв `scp` из-за не найденного пути: `wwwroot/catalog.js` НЕ существует (в wwwroot
|
||||||
|
лежат только JSON фида) — `plugin.js` живёт в `lampac/catalog/plugin.js` и
|
||||||
|
монтируется в `/lampac/module/Catalog/plugin.js`.
|
||||||
|
|
||||||
## 🔴🔴 СЕДЬМАЯ СЕССИЯ: РАБОЧИЙ МЕХАНИЗМ НАЙДЕН — ПЕРЕХВАТ `Lampa.Api.partNext`
|
## 🔴🔴 СЕДЬМАЯ СЕССИЯ: РАБОЧИЙ МЕХАНИЗМ НАЙДЕН — ПЕРЕХВАТ `Lampa.Api.partNext`
|
||||||
|
|
||||||
**Статус: ✅ секции Watchlist рендерятся ВНУТРИ главной CUB. Проверено на живом ТВ через CDP.**
|
**Статус: ✅ секции Watchlist рендерятся ВНУТРИ главной CUB. Проверено на живом ТВ через CDP.**
|
||||||
|
|||||||
Reference in new issue
Block a user