diff --git a/personal/plans/lampac-watchlist-plugin.md b/personal/plans/lampac-watchlist-plugin.md index 8a8e65b6..a10ba82f 100644 --- a/personal/plans/lampac-watchlist-plugin.md +++ b/personal/plans/lampac-watchlist-plugin.md @@ -7,7 +7,7 @@ related: - '[[family/projects/watchlist-sync]]' - '[[family/projects/watchlist-automation]]' - '[[family/documents/movies-watchlist]]' -status: accepted-in-ui-cub-sections-pending +status: cub-sections-patched-awaiting-tv-restart tags: - lampac - lampa @@ -68,23 +68,41 @@ updated: '2026-09-22' > Залито, отдаётся в сборке `/catalog.js` (35566 Б). **Ожидает приёмки в UI.** > Механика — [[personal/tech/lampac-deployment]] раздел «Внедрение секций Watchlist в CUB-фид». > +> **Обновление 2026-09-22 (шестая сессия): 🔴🔴 ПРИЧИНА «В CUB НИХУЯ НЕ ПОМЕНЯЛОСЬ» — `Manifest` НЕДОСТУПЕН В ОБЁРТКЕ.** +> Alex: «Ты вообще нихуя не поменял!!». Проверка через **CDP-пробу на живом ТВ** подтвердила +> его правоту: обёртка `Api.sources.cub.main` стояла (`__wl_injected: true`), но вызов +> `cub.main({})` возвращал **4 родные секции** и **ни одной нашей**. +> **Корень:** первая версия инжекта читала `Manifest.catalogs['watchlist']` напрямую, а +> `Manifest` объявлен **локально в замыкании плагина** → `ReferenceError: Manifest is not defined` +> → `catch` → молча отдавался родной фид. **Ошибки нет ни в UI, ни в логах.** +> **Фикс:** `window.__wl_menu` (заполняется в `loadCatalogs`) + `wlEnsureMenu()` с фолбэком +> на запрос `/catalog`. Переписан сборщик: **`build_plugin.py`** (детерминированный, +> с инвариантами `INJECT=1`/`def=1`/`startPlugin=1`, `node --check` + баланс скобок), +> вместо неидемпотентного `patch_cub_inject.py` (он вставлял INJECT дважды и ломал скобки). +> Залито (сборка **35440 Б**), **ждёт перезапуска Lampa на ТВ** — `docker restart lampac` +> НЕ перезагружает плагин в памяти ТВ. +> Механика + CDP-пробы — [[personal/tech/lampac-deployment]] раздел +> «🔴🔴 ШЕСТАЯ СЕССИЯ: ИСТИННАЯ ПРИЧИНА…». + > **Обновление 2026-09-22 (пятая сессия): ✅✅ ПРИЁМКА ALEX ПРОЙДЕНА — ФИЛЬМЫ ОТКРЫВАЮТСЯ И ПРОИГРЫВАЮТСЯ.** > Дословно: «фильмы из списка Watchlist теперь открываются и проигрываются». > Закрыт последний блокер — кириллический ключ плагина (`plugin: watchlist`). > Плюс устранён питфолл `Staticache` (кэш собранного `/catalog.js` переживал > заливку и выглядел как «патч не применяется» → `docker restart lampac`). > -> **Осталось (2026-09-22, конец сессии):** -> 1. **5 фильмов с Кинопоиск-ID** (`film/NNNNN/`) — «Рассекая волны: экспедиция „Лас Бальсас“», -> «Хамнет», «Цена вершины», «Астрал. Могильный ритуал 2», «О добре и зле». +> **Осталось (2026-09-22, конец шестой сессии):** +> 1. **Секции CUB в UI** — 🔴 инжект залит, но требовал **перезапуска Lampa на ТВ** +> (причина «ничего не поменялось» — `Manifest` в обёртке, см. выше). После перезапуска +> проверить через `probe_cub_main.py`: должно быть **8 секций** (4 родные CUB + 4 наши). +> 2. **5 фильмов с Кинопоиск-ID** (`film/NNNNN/`) — «Рассекая волны: экспедиция „Лас Бальсас“», +> «Хамнет», «Эхопраксия», «Цена вершины», «Астрал. Могильный ритуал 2», «О добре и зле», +> WeWork (2024). > TMDB не нашёл (2025 год) → нет карточки и постера → клик даёт «здесь пусто». > **Нужен выбор Alex:** заглушка с кнопкой поиска торрента либо дорисовать `tmdb_id`. -> 2. **~51 название без постера** — проблема ЗАПИСИ В СПИСКЕ, не скрипта: +> 3. **~51 название без постера** — проблема ЗАПИСИ В СПИСКЕ, не скрипта: > `Плохие парни 1/2` (ДВА фильма одной строкой), `Солярис Тарковский` (уточнение > режиссёра), `Самолетом, поездом, машиной (1987)` (русский аналог). > Генератор такое угадать не может — **правится только список руками**. -> 3. **Секции CUB в UI** — инжект залит, нужен перезапуск Lampa и визуальная проверка: -> секции Watchlist должны появиться поверх родного фида CUB при активном источнике CUB. > > **Обновление 2026-09-22 (четвёртая сессия, ранее): ✅ ЧИСЛОВОЙ `tmdb_id` В КАРТОЧКАХ.** > 352 из 352 карточек отдают `tmdb_id` числом, `source`, `runtime`, `vote_average`, жанры. diff --git a/personal/tech/lampac-deployment.md b/personal/tech/lampac-deployment.md index d963f565..bfa4b13a 100644 --- a/personal/tech/lampac-deployment.md +++ b/personal/tech/lampac-deployment.md @@ -1786,10 +1786,13 @@ else{Lampa.Listener.follow('app',function(e){if(e.type=='ready')patchCubMain();} | `runtime`, `vote_average` | тем же способом через `format` | | `displayname` | «Мой список» — надпись в UI | | **✅ Alex подтвердил в UI** | **фильмы Watchlist открываются и ПРОИГРЫВАЮТСЯ** | -| Инжект секций в CUB-фид | залито, ожидает проверки в UI (перезапуск Lampa) | +| Инжект секций в CUB-фид | ⚠️ залито (35440 Б) — **ждёт перезапуска Lampa на ТВ** | +| Причина «секции не появились» | 🔴 `Manifest` не виден в обёртке → `ReferenceError` → фикс через `window.__wl_menu` | +| Сборщик плагина | `build_plugin.py` (детерминированный, с инвариантами); `patch_cub_inject.py` **отменён** | Скрипты: `/Users/admin/lampac-tmp/gen_watchlist_v2.py`, `deploy_lampac.py` -(`--skip-plugin` для быстрого прогона), `patch_cub_inject.py`. +(`--skip-plugin` для быстрого прогона), `build_plugin.py`, `deploy_cub.py`, +`restart_lampa.sh`, `probe_tv.py`, `probe_cub_main.py`. Проверка в шаге 7 валидирует именно ключ `watchlist` и предупреждает, если в `/catalog` остался русский ключ. @@ -1827,6 +1830,106 @@ else{Lampa.Listener.follow('app',function(e){if(e.type=='ready')patchCubMain();} Инжект залит (`plugin-cub.js`, 35566 Б в отдаваемой сборке). Нужен перезапуск Lampa на ТВ и проверка: секции Watchlist появляются **поверх родного фида CUB**. +### 🔴🔴 ШЕСТАЯ СЕССИЯ: ИСТИННАЯ ПРИЧИНА «СЕКЦИИ НЕ ПОЯВИЛИСЬ» — `Manifest` НЕДОСТУПЕН ВНУТРИ ОБЁРТКИ + +Первая версия `injectWatchlistParts` читала `Manifest.catalogs['watchlist']` **напрямую**. +Проба через CDP на живом ТВ показала: + +``` +out.cubMainSrc = "function (params, oncomplite, onerror) { original(params, function (cub_data) { + try { var wl = Manifest.catalogs['watchlist']; if (!..." +out.err = "ReferenceError: Manifest is not defined" +wlInjected: true ← обёртка СТОЯЛА +вызов main({}) → len: 4, titles: ["Сейчас смотрят","Рекомендуем посмотреть","Последнее добавление","Огонь!"] + ← только родные CUB, НИ ОДНОЙ нашей +``` + +**Корень:** `Manifest` объявлен **локально в замыкании плагина** (`/catalog.js`, IIFE). +Обёртка вызывается из другого контекста → `ReferenceError` → `catch` → молча +`oncomplite(cub_data)` с родными секциями. Ошибка **не видна в UI и не пишется в логи**. + +**Фикс:** не полагаться на замыкание — сохранять `menu` в глобальный `window.__wl_menu` +при `loadCatalogs()`, в обёртке читать оттуда, с фолбэком на прямой запрос `/catalog`: + +```js +// в loadCatalogs, ПОСЛЕ Manifest.catalogs=json; +if(json['watchlist']&&json['watchlist'].menu)window.__wl_menu=json['watchlist'].menu; + +function wlEnsureMenu(cb) { + if (window.__wl_menu && Object.keys(window.__wl_menu).length) return cb(window.__wl_menu); + network.silent(Utils.account(Manifest.api_host + '/catalog'), function (json) { + var m = (json && json['watchlist'] && json['watchlist'].menu) || {}; + window.__wl_menu = m; cb(m); + }, function () { cb(window.__wl_menu || {}); }); +} +``` +`wlEnsureMenu` вызывается внутри обёртки вместо прямого `Manifest.catalogs['watchlist']`. + +⚠️ **`Manifest.api_host` в `wlEnsureMenu` — тоже замыкание.** Фолбэк сработает только +если `__wl_menu` уже заполнен `loadCatalogs`; в норме он заполнен. Если `__wl_menu` +пуст И `Manifest` недоступен — вернётся `{}` и родной фид. + +### Сборка плагина: `build_plugin.py` вместо `patch_cub_inject.py` + +🔴 **`patch_cub_inject.py` отменён — он не идемпотентен.** Разрезание по первому +`function startPlugin` + поиск `end` вставляло `INJECT` **дважды** и оставляло файл +с нарушенным балансом скобок (`{`=123, `}`=122 → `node --check` → `SyntaxError`). + +**Новый сборщик — `build_plugin.py`, детерминированный:** +1. берёт базу `plugin-patched.js`; +2. вставляет `window.__wl_menu` в `loadCatalogs`; +3. вырезает ранее вставленный INJECT по маркеру `/* ==== WL-INJECT-START ==== */`; +4. разбивает файл на `[до startPlugin]` + `[startPlugin…]` + `[хвост })();]`; +5. собирает заново: `before` + `INJECT` + `NEW_START` + `tail`. + +**Инварианты в конце скрипта** (падает с `[x] ИНВАРИАНТ НАРУШЕН`, если нарушено): +- `WL-INJECT-START` = **1** +- `function patchCubMain()` = **1** +- `function startPlugin` = **1** + +⚠️ `patchCubMain();` встречается **2 раза** (в `window.appready` и в `app:ready`-листенере) — +это норма, в инвариант не входит (первая версия проверки ошибочно требовала 1). + +Проверка: `node --check plugin-cub.js` + баланс скобок `{`/`}` = 0. +Итог: **13054 Б**, сборка на сервере **35566 → 35440 Б** (зависит от длины `catalogs`-JSON). + +### Перезапуск Lampa на ТВ — правильный `luna-send` + +🔴 **`luna-send` через `ssh 'script -q -c "luna-send … -a \"{...}\""'` НЕ парсит аргументы** — +печатает help. Кавычки в кавычках рвутся. Рабочая форма — **одинарные кавычки внутри +`script -c`**, файлом (не inline): + +```bash +ssh $TV 'script -q -c "luna-send -n 1 -f luna://com.webos.applicationManager/close -a '"'"'{"id":"com.lampac.tv"}'"'"'" /dev/null' +sleep 4 +ssh $TV 'script -q -c "luna-send -n 1 -f luna://com.webos.applicationManager/launch -a '"'"'{"id":"com.lampac.tv"}'"'"'" /dev/null' +``` +Скрипт: `/Users/admin/lampac-tmp/restart_lampa.sh` (закрыть → пауза 4с → запустить → 20с → показать devtools). + +⚠️ **`docker restart lampac` НЕ перезагружает плагин на ТВ.** После заливки `plugin.js` +ТВ продолжает держать **старую версию в памяти** — `cubMainSrc` через CDP показывает +старый код. Обязателен **перезапуск приложения на ТВ**. + +### Диагностика рантайма Lampa через CDP (websocket-client) + +⚠️ Модуля `ws` в Node нет, `websockets` в Python нет → использовать **`websocket-client`** +(установлен). Скрипты `/Users/admin/lampac-tmp/probe_tv.py`, `probe_cub_main.py`. + +```python +WS=$(curl -s "http://192.168.1.70:9998/json/list" | jq -r '.[] | select(.title=="Lampac") | .webSocketDebuggerUrl' | head -1) +python3 probe_cub_main.py "$WS" +``` +`probe_cub_main.py` вызывает `Lampa.Api.sources.cub.main({}, cb)` и печатает +`titles` секций — **единственный надёжный способ увидеть, что реально отдаёт обёртка**. +Успех = 8 секций (4 родные CUB + 4 наши). + +Полезные поля пробы `probe_tv.py`: `Lampa.Storage.field('source')`, +`Object.keys(Lampa.Api.sources)`, `Lampa.Api.sources.cub.__wl_injected`, +`typeof Lampa.Api.sources.cub.main`. + +⚠️ `Manifest` внутри `Runtime.evaluate` **тоже не виден** (`ReferenceError: Manifest is not defined`) — +он в замыкании плагина. Не использовать в пробах. + ## Питфоллы проверки на ТВ (сводка) 1. **Lampa кэширует манифест и ответы.** После правок — **полностью выгрузить