[2026-09-25] eagle: personal/plans/lampac-watchlist-plugin.md personal/tech/lampac-deployment.md
This commit is contained in:
1 parent
f295d5e903
commit
f184b707a1
2 files changed
+208
-13
No files matched your search
@@ -8,7 +8,7 @@ related:
|
||||
- '[[family/projects/watchlist-automation]]'
|
||||
- '[[family/documents/movies-watchlist]]'
|
||||
- '[[personal/plans/lampac-watched-to-watchlist]]'
|
||||
status: main-screen-filter-WORKS-2026-09-25-accepted-committed-5e55a47-prefetch-pending
|
||||
status: third-fix-2026-09-25-component-filter+wlPrefetch-deployed-awaiting-verdict
|
||||
tags:
|
||||
- lampac
|
||||
- lampa
|
||||
@@ -444,14 +444,8 @@ cats = NOMANIFEST
|
||||
|
||||
1. ✅ **ПРИЁМКА ПРОЙДЕНА 2026-09-25** — фильтр `wlOnMain()` работает, фид виден только
|
||||
на главной. Доказательство: на экране `movie` секций в DOM нет при заполненном `menu`.
|
||||
2. 🔄 **ПРЕДЗАГРУЗКА `__wl_menu`** — единственный незакрытый пункт этой задачи,
|
||||
выполняется сразу после коммита `5e55a47`. Корень отставания — асинхронный `/catalog`
|
||||
в `loadCatalogs()`: меню приходит ПОСЛЕ первого `partNext`. Решение: подтягивать
|
||||
`menu` синхронно в `startPlugin()`, параллельно с `loadCatalogs()`, чтобы `wlInject`
|
||||
срабатывал в первом раунде среза. Правка идёт в те же два файла в репе
|
||||
(`lampac-scripts/scripts/plugin-cub.js` + `INJECT` в `build_plugin.py`) + новый
|
||||
инвариант сборщика. Порядок деплоя — как обычно: сборка → `node --check` → бэкап →
|
||||
`scp` → рестарт Lampa на ТВ → замер CDP.
|
||||
2. 🔄 **ПРЕДЗАГРУЗКА `__wl_menu`** — ВЫПОЛНЕНА, но НЕ ЗАКРЫТА: см. «ТРЕТИЙ ФИКС»
|
||||
ниже. Требуется ещё один заход (фильтр по `component` + вставка при возврате).
|
||||
3. **Диагностировать 66 с на карточке** — `docker logs lampac` + трейс `CardController`.
|
||||
Запрос: `GET /catalog/card?plugin=watchlist&uri=movie%2F424781&type=movie`
|
||||
→ 66 118 мс, 939 Б.
|
||||
@@ -460,6 +454,131 @@ cats = NOMANIFEST
|
||||
Развилка «`lampac_plugin/` в `watchlist-sync` vs бэкапы» **закрыта**: плагин
|
||||
принадлежит `lampac-scripts` (там же `gen_watchlist.py`, `deploy_lampac.py`).
|
||||
|
||||
---
|
||||
|
||||
## 🔴🔴 2026-09-25 (финал): ТРЕТИЙ ФИКС — фильтр по `component` + `wlPrefetch()`
|
||||
|
||||
### Приёмка Alex частичная: два новых симптома
|
||||
|
||||
Alex после заливки `wlPrefetch`:
|
||||
|
||||
> «Так, хорошо, Сейчас при загрузке приложения сработало, коммить.
|
||||
> Но когда я с главной ушел в раздел фильмы там снова были watchlist разделы
|
||||
> А когда вернулся на главную опять разделы watchlist не сверху»
|
||||
|
||||
То есть: **при холодном старте — правильно** (секции сверху, фильтр держит), но
|
||||
навигация ломает обе части: уход в «Фильмы» → секции появились; возврат на главную →
|
||||
секции не сверху.
|
||||
|
||||
### 🔴 ГЛАВНАЯ НАХОДКА: на главной `url` ПУСТОЙ, а `component === 'main'`
|
||||
|
||||
Замер на живой Lampa (CDP) в момент, когда открыта именно главная
|
||||
(`?component=main&source=cub&page=1`):
|
||||
|
||||
```
|
||||
active_full = url= | title=Главная - CUB | component=main | source=cub | page=1 | params=obj | activity=obj
|
||||
act_url_direct = "" ← url ПУСТОЙ, а не 'main'
|
||||
act_act_url = undefined ← вложенный activity.url тоже пуст
|
||||
menu = Новинки,Фильмы,Мультфильмы,Аниме
|
||||
cats = NOMANIFEST
|
||||
```
|
||||
|
||||
🔴 **Вывод: проверка `url === 'main'` НЕ РАБОТАЕТ ВООБЩЕ.** Она не срабатывала ни разу —
|
||||
её проходила только смягчающая ветка `if (!act) { if (!catalogs) return true; }`.
|
||||
Как только `Manifest.catalogs` заполнится, **фильтр начал бы резать саму главную**.
|
||||
Это была мина, а не рабочее условие.
|
||||
|
||||
**Правильное поле — `component`:** главная `→ 'main'`, категория `→ 'category_full'` /
|
||||
`'category'`. Оно стабильно на обоих экранах, в отличие от `url`.
|
||||
|
||||
```js
|
||||
function wlComp(a) {
|
||||
if (!a) return '';
|
||||
if (a.component) return String(a.component);
|
||||
if (a.activity && a.activity.component) return String(a.activity.component);
|
||||
return '';
|
||||
}
|
||||
// в wlOnMain(): if (comp === 'main') return true;
|
||||
// смягчающая ветка: if (!comp) { пустые catalogs → true }
|
||||
```
|
||||
|
||||
### Замер, доказавший что секции ВСЁ-ТАКИ вставлялись
|
||||
|
||||
```
|
||||
cat_header = Сейчас смотрят | Рекомендуем посмотреть | Последнее добавление | Огонь! |
|
||||
В высоком качестве | Новинки | Фильмы | Мультфильмы | Аниме | Фэнтези | ...
|
||||
↑↑↑↑↑↑↑↑ наши 4 секции — ЕСТЬ, но ПОСЛЕ родных
|
||||
wl_done = false
|
||||
```
|
||||
|
||||
То есть на главной секции присутствовали, но стояли **после** «В высоком качестве» —
|
||||
ровно тот симптом «сильно после первых секций», который Alex и называл.
|
||||
|
||||
### `wlPrefetch()` — предзагрузка меню при старте
|
||||
|
||||
```js
|
||||
function wlPrefetch() {
|
||||
if (window.__wl_prefetched) return;
|
||||
window.__wl_prefetched = true;
|
||||
wlMenu(function (m) { console.log('[watchlist] меню предзагружено: ' + Object.keys(m || {}).join(',')); });
|
||||
}
|
||||
// в startPlugin(), рядом с wlPatchPartNext():
|
||||
// if(window.appready){wlPatchPartNext();wlPrefetch();} else { … 'ready' → wlPatchPartNext();wlPrefetch(); }
|
||||
```
|
||||
|
||||
`/catalog` тянется **параллельно** `loadCatalogs()`, чтобы `__wl_menu` лежал в памяти
|
||||
к моменту первой отрисовки главной. Меряно: `menu` заполнен при
|
||||
`Manifest.catalogs = NOMANIFEST` → **на `loadCatalogs()` полагаться нельзя**, нужен
|
||||
независимый запрос.
|
||||
|
||||
### Состояние сборки и деплоя
|
||||
|
||||
```
|
||||
python3 build_plugin.py → 14/14 инвариантов, 18947 байт
|
||||
node --check plugin-cub.js → SYNTAX OK
|
||||
```
|
||||
|
||||
**Инварианты (14):** `INJECT=1`, `partNext def=1`, `wlInject def=1`,
|
||||
`unshift (не push)=1`, `push в INJECT=0`, `startPlugin=1`,
|
||||
`нет network.silent в INJECT=0`, **`wlOnMain def=1`**, **`wlComp def=1`**,
|
||||
**`wlComp читает component=1`**, **`wlOnMain guard=1`**, **`wlPrefetch def=1`**,
|
||||
**`wlPrefetch call=3`**. Инварианты `wlUrl def` / `wlUrl верхний уровень` — **убраны**
|
||||
вместе с `wlUrl()` (поле оказалось не тем).
|
||||
|
||||
**Деплой выполнен:** бэкап `catalog/plugin.js.bak-before-comp-<ts>` →
|
||||
`scp` (18947 Б) → проверка в контейнере
|
||||
`docker exec lampac grep -c "wlPrefetch\|wlComp" /lampac/module/Catalog/plugin.js` → **4**
|
||||
→ рестарт Lampa на ТВ через `luna-send` (`--- закрываю --- --- запускаю --- --- готово ---`).
|
||||
|
||||
### 🔴 Что ОСТАЛОСЬ (следующая сессия, начать отсюда)
|
||||
|
||||
**Гипотезы по двум симптомам (НЕ проверены, гадать не нужно — мерить):**
|
||||
|
||||
1. **Уход в «Фильмы» → секции снова появились.** Переход идёт через `category()` /
|
||||
`category_full` (`plugin.js:36`). Фильтр по `component` там должен давать `false`,
|
||||
НО `component` на экране Фильмов в замере **не логировался** — на тот момент
|
||||
фиксировался только `url`. Возможные варианты: `component` на Фильмах тоже
|
||||
`'main'`; либо вставка на этом экране идёт не из `partNext`.
|
||||
→ Проверить `component` на экране Фильмов ОТДЕЛЬНОЙ пробой.
|
||||
2. **Возврат на главную → секции не сверху.** `wlPrefetch()` **одноразовый**
|
||||
(`__wl_prefetched`). На возврате `__wl_menu` уже заполнен, но `wlInject` не
|
||||
срабатывает в первом раунде; плюс `unshift` в голову `parts` работает, только если
|
||||
`partNext` вызван **заново с новым массивом** — на возврате Lampa может
|
||||
переиспользовать уже отрисованный пул.
|
||||
→ Нужен трейс порядка вызовов `partNext` на «главная → Фильмы → главная»
|
||||
(`console.log` с номерами вызовов).
|
||||
|
||||
**Порядок работ:** сначала ЗАМЕР по обоим пунктам (пока Lampa в текущем состоянии,
|
||||
без рестарта), потом правка, потом обычный цикл: сборка → `node --check` → бэкап →
|
||||
`scp` → рестарт Lampa на ТВ → замер CDP → приёмка Alex.
|
||||
|
||||
**Коммит правки (третий фикс) НЕ сделан** — апрув истёк по таймауту. Файлы лежат в
|
||||
`/Users/admin/lampac-tmp/`, в `~/Developer/lampac-scripts/scripts/` ещё НЕ скопированы.
|
||||
После приёмки — скопировать и закоммитить тем же порядком, что `5e55a47`.
|
||||
|
||||
**Правило:** `git commit` через `ssh`/длинную команду может уйти в таймаут апрува —
|
||||
подтверждение Alex обязательно, повторять команду автоматически нельзя.
|
||||
|
||||
**Правило диагностики этой сессии:** не читать `%{size_download}` как «размер фида»
|
||||
(это gzip) — брать `ls -la` или `Accept-Encoding: identity`. И — `ifconfig` на Кра́кене
|
||||
отсутствует: каждая ssh-команда печатает `bash: line 1: ifconfig: command not found`
|
||||
|
||||
@@ -43,7 +43,7 @@ related:
|
||||
|
||||
| Слой | Путь | Примечание |
|
||||
|---|---|---|
|
||||
| **Mac, репо** | `~/Developer/lampac-scripts/scripts/build_plugin.py` | сборщик, 12 инвариантов |
|
||||
| **Mac, репо** | `~/Developer/lampac-scripts/scripts/build_plugin.py` | сборщик, 14 инвариантов |
|
||||
| **Mac, репо** | `~/Developer/lampac-scripts/scripts/plugin-cub.js` | 🔴 собранный выход, РУКАМИ не правим |
|
||||
| Mac, скрэтч | `/Users/admin/lampac-tmp/` | рабочая папка, вне git — не источник истины |
|
||||
| Кра́кен, хост | `/srv/dev-disk-by-uuid-6194539b-.../lampac/catalog/plugin.js` | bind-mount, вне git |
|
||||
@@ -71,6 +71,27 @@ git commit -m "..." && git push origin main
|
||||
(`watchlist.json`, `watchlist-<cat>.json`, `cards.json`, `cards/`, `missing.json`).
|
||||
Попытка `scp` оттуда падает с «No such file or directory» — это не сбой сети.
|
||||
|
||||
### 🔴 CDP-пробы на ТВ (порт 9998) — питфоллы, стоившие сессии
|
||||
|
||||
| Питфолл | Симптом | Как правильно |
|
||||
|---|---|---|
|
||||
| **Цель искать по `url`, а не `title`** | сразу после рестарта Lampa `title=""`, `url=about:blank` → скрипт молча не находит цель, проба даёт пустоту | выбирать `"com.lampac.tv" in t.get("url")`, НЕ `title == "Lampac"` |
|
||||
| **Первый замер — гонка** | `ready=false, plugin=false, patch=false, act_url=ERR` выглядит как «плагин не доехал» | подождать/опрашивать `ready`, пока не станет `true` |
|
||||
| **`JSON.stringify(active())` падает** | `TypeError: Converting circular structure to JSON` | собирать поля по одному или строку вручную |
|
||||
| **Отсутствующее поле без обёртки** | CDP отвечает без `result.value` — выглядит как «все пробы пустые» (получили 9 `<none>` подряд) | каждую пробу оборачивать в `String(...)` / `typeof ...`, проверять `subtype == "error"` |
|
||||
| **`Log.enable` + `Runtime.enable` дают 0 строк** | консольные сообщения, напечатанные ДО подключения, не отдаются | читать логи СРАЗУ после рестарта, либо подтверждать состояние пробами, а не логами |
|
||||
|
||||
⚠️ **`docker restart lampac` НЕ сбрасывает кэш `catalog.js` в браузере webOS** — нужен
|
||||
рестарт приложения на ТВ через `luna-send`. И **не спать** в ожидании: Alex на паузу
|
||||
`sleep 20` отреагировал резко («Чё нахуй за слип 20?!») — вместо сна опрашивать состояние.
|
||||
|
||||
🔴 **Правило диагностики:** не читать `curl -w %{size_download}` как «размер фида» —
|
||||
это размер ПОСЛЕ распаковки gzip. Брать `ls -la` или `Accept-Encoding: identity`.
|
||||
Пример: `watchlist-films.json` = 88 КБ несжатых при 347 позициях, а `cards.json` = 548 КБ.
|
||||
|
||||
⚠️ **`ifconfig` на Кра́кене отсутствует** — каждая `ssh kraken` печатает
|
||||
`bash: line 1: ifconfig: command not found` безвредным шумом. Это НЕ ошибка команды.
|
||||
|
||||
### Порядок деплоя
|
||||
|
||||
```
|
||||
@@ -93,6 +114,59 @@ ssh kraken 'docker exec lampac grep -c "<маркер>" /lampac/module/Catalog/p
|
||||
следующая сборка затрёт правку. Инварианты в `checks{}` обязаны покрывать любую
|
||||
новую функцию — иначе регресс пройдёт молча.
|
||||
|
||||
### 🔴🔴 Как определить активный экран Lampa — по `component`, НЕ по `url`
|
||||
|
||||
**ИЗМЕРЕНО на живом ТВ 2026-09-25.** Форма объекта:
|
||||
|
||||
```
|
||||
Lampa.Activity.active() → {url, title, component, source, page, params, activity}
|
||||
Lampa.Activity.active().activity → {component, object, slide, body, is_started, is_stopped}
|
||||
```
|
||||
|
||||
🔴 **На главной `url` ПУСТОЙ.** Реальный замер в момент, когда открыта главная
|
||||
(`?component=main&source=cub&page=1`):
|
||||
|
||||
```
|
||||
url = "" title = "Главная - CUB" component = "main"
|
||||
source = "cub" page = 1
|
||||
```
|
||||
|
||||
`url === 'main'` **не срабатывает никогда.** Если строить фильтр секций на `url`,
|
||||
он либо не работает, либо работает случайно — через смягчающую ветку «пусто +
|
||||
`Manifest.catalogs` пуст». Как только манифест заполнится, **фильтр начнёт резать
|
||||
саму главную** и секции исчезнут.
|
||||
|
||||
**Правильное поле — `component`:**
|
||||
| Экран | `component` | `url` |
|
||||
|---|---|---|
|
||||
| Главная | `main` | `""` (пусто) |
|
||||
| Категория / Фильмы | `category_full` / `category` | `movie`, `cartoons`, … |
|
||||
|
||||
```js
|
||||
function wlComp(a) {
|
||||
if (!a) return '';
|
||||
if (a.component) return String(a.component);
|
||||
if (a.activity && a.activity.component) return String(a.activity.component);
|
||||
return '';
|
||||
}
|
||||
// фильтр: if (wlComp(Lampa.Activity.active()) === 'main') → вставляем
|
||||
```
|
||||
|
||||
⚠️ `url` при этом остаётся полезным для другого: на экране Фильмов он даёт
|
||||
`"movie"`. Замер `act_url = "movie"` использовался как доказательство работы фильтра.
|
||||
|
||||
### 🔴 `Manifest.catalogs` и `window.__wl_menu` рассинхронизированы
|
||||
|
||||
Меряно одновременно: `menu = Новинки,Фильмы,Мультфильмы,Аниме` при
|
||||
`Manifest.catalogs = NOMANIFEST`. То есть `__wl_menu` заполнен, а штатный манифест —
|
||||
нет. **На `loadCatalogs()` полагаться нельзя**, для меню нужен независимый запрос
|
||||
(`wlPrefetch()` в `startPlugin()`, параллельно `loadCatalogs()`).
|
||||
|
||||
Без предзагрузки первый `partNext` застаёт `__wl_menu` пустым → уходит в
|
||||
асинхронный `wlMenu()` → пока летит запрос, родной `cub.main()` уже отрисовал свои
|
||||
секции и `slice(0, parts_limit)` отработал → наши секции попадают в пул только
|
||||
следующим раундом. Alex видел это как «есть, но сильно после первых секций».
|
||||
|
||||
### 🔴 Перезапуск Lampa на ТВ обязателен
|
||||
|
||||
`docker restart lampac` **НЕ сбрасывает** кэш `catalog.js` в браузере webOS — ТВ
|
||||
@@ -1724,10 +1798,12 @@ node --check plugin-cub.js
|
||||
`lampac-tmp` вне git, файлы там не переживут чистку. Коммит: `5e55a47`.
|
||||
|
||||
Детерминирован: режет `[до startPlugin] + INJECT + [новый startPlugin] + '})();'`,
|
||||
проверяет инварианты. **Текущий набор (12):** `INJECT=1`, `partNext def=1`,
|
||||
проверяет инварианты. **Текущий набор (14):** `INJECT=1`, `partNext def=1`,
|
||||
`wlInject def=1`, `unshift (не push)=1`, `push в INJECT=0`, `startPlugin=1`,
|
||||
`нет network.silent в INJECT=0`, плюс добавленные 2026-09-25 —
|
||||
**`wlOnMain def=1`, `wlOnMain guard=1`, `wlUrl def=1`, `wlUrl верхний уровень=1`**.
|
||||
`нет network.silent в INJECT=0`, `wlOnMain def=1`, `wlComp def=1`,
|
||||
`wlComp читает component=1`, `wlOnMain guard=1`, `wlPrefetch def=1`,
|
||||
`wlPrefetch call=3`. Инварианты `wlUrl*` **убраны** вместе с `wlUrl()` —
|
||||
поле `url` оказалось не тем (см. раздел про `component`).
|
||||
|
||||
🔴 **Правило: новая функция в INJECT = новый инвариант в `checks{}`.** Иначе
|
||||
регресс (например, потерянный фильтр по экрану) пройдёт сборку молча и всплывёт
|
||||
|
||||
Reference in new issue
Block a user