diff --git a/personal/tech/lampac-deployment.md b/personal/tech/lampac-deployment.md index fc61ddaf..67d7865b 100644 --- a/personal/tech/lampac-deployment.md +++ b/personal/tech/lampac-deployment.md @@ -1709,6 +1709,167 @@ status.append('movie', json); | Кэш манифеста | `loader.js`: `cache_version = floor(Date.now()/9e5)` — смена сервера в течение ~15 мин не подхватится | | Служба devtools | `com.webos.service.devtools` **НЕ существует** на webOS 5.4.2 Lite | +### ✅ РЕШЕНО: `partNext` — рабочий механизм (проверено 2026-09-22, сессия 8) + +**Требование Alex:** секции Watchlist ВНУТРИ источника CUB, без ручного переключения. +Переключение источника — **не решение** (отвергнуто дважды). + +#### Почему провалилась обёртка `cub.main` (3 итерации) + +Родной `main$1()` в `app.min.js` объявлен **внутри замыкания Lampa** и зависит от +локальных `permit`, `get$7`, `Lang`, `permit.child_small`, `Helper$b`: + +```js +function main$1() { + var parts_limit = 6; + var parts_data = [ + function (call) { get$7('?sort=now_playing', params, function (json) { + json.title = Lang.translate('title_now_watch'); call(json); }, call, {life: day*2}); }, + function (call) { if (permit.child_small) return call(); ... } + ]; + ... +} +``` + +| Симптом | Замер CDP на ТВ | Корень | +|---|---|---| +| `cub.main({})` → вечный `pending`, 0 fetch | `{"pending":true}` через 15 с | `permit` = **undefined** вне замыкания → падение на первой проверке → callback не зовётся | +| секции не добавлялись, ошибок нет | `cubMainSrc` = `...var wl = Manifest.catalogs['watchlist']...` | `Manifest`/`Utils`/`network` = **undefined** вне замыкания → `ReferenceError` → `catch` → родной фид | +| «Нет подключения к сети» в логе ТВ | `{localhost}/catalog?uid=...&token={token}` | `Utils.account()` без `Manifest.api_host` подставляет `{localhost}` | + +🔴 **Вывод: `cub.main` НЕВЫЗЫВАЕМ извне by design.** Обёртка — тупик, не «недоработка». + +#### ✅ Правильный механизм: перехват `Lampa.Api.partNext` + +Родной `main$1()` собирает `parts_data` — массив функций-секций — и отдаёт его в +**глобальную** `Lampa.Api.partNext(parts, parts_limit, partLoaded, partEmpty)`: + +```js +function partNext(parts, parts_limit, partLoaded, partEmpty) { + var pieces = parts.filter(function (p) { return typeof p == 'function'; }) + .slice(0, 0 + parts_limit); + if (pieces.length) { + new Progress().append(pieces).start(function (result) { + var data = result.filter(function (r) { return r && r.results && r.results.length; }); + ... + }); + } else partEmpty(); +} +``` + +Патч добавляет наши функции-секции в `parts` **до** вызова оригинала: + +```js +Lampa.Api.partNext = function (parts, parts_limit, partLoaded, partEmpty) { + if (Lampa.Arrays.isArray(parts) && !parts.__wl_done) { + var menu = window.__wl_menu; + if (menu && Object.keys(menu).length) { + parts.__wl_done = true; + Object.keys(menu).forEach(function (name) { + parts.push(wlSection(name, menu[name])); + }); + } + } + return orig.apply(this, arguments); +}; +``` + +Секция — функция `call(json)`, те же контракты, что у родных CUB: + +```js +function wlSection(name, url) { + return function (call) { + wlGet(url, function (json) { + json.title = name; + json.source = 'watchlist'; // ← обязательно, иначе карточка уйдёт в CUB/tmdb + if (Lampa.Arrays.isArray(json.results)) + json.results.forEach(function (it) { it.source = 'watchlist'; }); + call(json); + }, function () { call(); }); // ошибка → пустой вызов, пул не ломается + }; +} +``` + +**Проверено на живом ТВ (CDP):** `pnCalls: 1`, `lastPartsCount: 28` — CUB собрал главную +из 28 функций (24 родные + наши 4). Activity `main`, `patched: true`, меню +`["Новинки","Фильмы","Мультфильмы","Аниме"]`. В DOM рендерились: +«Рассекая волны», «Хамнет», «Эхопраксия», «WeWork создание и крах компании». + +#### 🔴 В замыкании доступны ТОЛЬКО глобальные объекты + +| Нужно | ❌ Не работает в этом контексте | ✅ Работает | +|---|---|---| +| api_host | `Manifest.api_host` | `Lampa.Manifest.api_host` (фолбэк — хардкод `http://192.168.1.14:9118`) | +| URL-склейка | `Utils.account(url)` → `{localhost}` | **ручная:** `wlAbs(url)` = host + path | +| HTTP | `network.silent(...)` | `new Lampa.Reguest().silent(absURL, ok, fail)`, фолбэк `fetch` | +| список секций | `Manifest.catalogs['watchlist'].menu` | `window.__wl_menu` (заполняется в `loadCatalogs` из `/catalog`) | + +```js +function wlAbs(url) { + if (!url) return ''; + if (/^https?:\/\//i.test(url)) return url; + return wlHost() + (url.charAt(0) === '/' ? url : '/' + url); +} +``` + +🔴 **`Lampa.Reguest.silent(абсолютныйURL)` работает идеально** (замер: 33 фильма, +XHR уходит корректный). Проблема была только в относительных URL через `Utils.account`. + +#### Сборщик `build_plugin.py` (заменил `patch_cub_inject.py`) + +```bash +cd /Users/admin/lampac-tmp +python3 build_plugin.py # plugin-patched.js + INJECT → plugin-cub.js +node --check plugin-cub.js # обязательно +node -e "const s=require('fs').readFileSync('plugin-cub.js','utf8');let b=0;for(const c of s){if(c=='{')b++;if(c=='}')b--;}console.log('баланс:',b)" # → 0 +``` + +Детерминирован: `[до startPlugin] + INJECT + [новый startPlugin] + '})();'`. +Инварианты: `WL-INJECT-START`=1, `function wlPatchPartNext`=1, `function startPlugin`=1, +`network.silent` в INJECT=0. Итог: **15476 Б** (в отдаваемой сборке **36956 Б**). + +🔴 **Питфолл прошлого сборщика:** проверки `"X" not in s` шли **по уже модифицированной +строке** → повторный запуск вставлял INJECT дважды → лишняя `}` → `SyntaxError`, +баланс скобок `{`=123, `}`=122. Всегда `node --check` + баланс ПЕРЕД заливкой. + +#### Деплой (полный порядок) + +```bash +scp plugin-cub.js kraken:/srv/.../lampac/catalog/plugin.js +ssh kraken 'P=/srv/.../lampac/catalog; chmod 644 $P/plugin.js; chown 1000:1000 $P/plugin.js; rm -f $P/._*; docker restart lampac' +# проверка отдаваемой сборки (Staticache!): +curl -s http://192.168.1.14:9118/catalog.js -o /tmp/cj.js +grep -c 'WL-INJECT-START' /tmp/cj.js # → 1 +grep -c 'wlPatchPartNext' /tmp/cj.js # → 3 +``` + +⚠️ **ТВ держит CMY старый плагин в памяти.** После заливки обязателен перезапуск приложения +на ТВ. Признак незакрытого перезапуска: `String(Lampa.Api.sources.cub.main)` содержит +**старую** обёртку `wlEnsureMenu`, а `Lampa.Api.__wl_partnext` = true — **две версии +одновременно**, старая ломает главную (`uid`/`token`, вечный pending). + +#### ⚠️ Перезапуск Lampa на ТВ — `luna-send` НЕ РАБОТАЕТ на этой прошивке + +Проверено 2026-09-22: `luna-send` по ssh возвращает **пустоту** (не help, не ошибку), +и через файл (`sh /tmp/tv_restart.sh`), и с `reload:true`, и через `close`+`launch`. +Страница devtools не меняется (`reset=` в URL тот же) → приложение **не перезапускается**. + +Рабочие альтернативы (не проверены до конца, следующая сессия): +- `Page.reload` + `Network.clearBrowserCache` через CDP (порт 9998) +- пульт: выйти из приложения и открыть заново + +#### Питфолл: `eval(pluginCode)` внутри IIFE не создаёт глобальных функций + +После `eval(code)` функции `wlHost()`/`wlAbs()` **снаружи не видны** (`ReferenceError`) — +они в замыкании IIFE. Это норма: `cub.main`/`partNext` их видят (одно замыкание), +внешние CDP-пробы — нет. Проверять только через `Lampa.Api.main()` либо чтение DOM. + +#### Питфолл: `cub.list` без host → 404 + +`Lampa.Api.sources.cub.list({url:'/catalog/list?...'})` → **HTTP 404** (относительный URL). +Прямой `fetch` с абсолютным URL → **200**, 9496 байт. Ещё одно подтверждение того, +что в этом контексте нужны только абсолютные URL. + ### 🔴 ТРЕБОВАНИЕ Alex: секции ВНУТРИ CUB, БЕЗ ручного переключения **Дословно:** «надо блядь добавить в CUB список новые секции а не ручное блядь переключение!» @@ -1959,8 +2120,9 @@ else{Lampa.Listener.follow('app',function(e){if(e.type=='ready')patchCubMain();} | `runtime`, `vote_average` | тем же способом через `format` | | `displayname` | «Мой список» — надпись в UI | | **✅ Alex подтвердил в UI** | **фильмы Watchlist открываются и ПРОИГРЫВАЮТСЯ** | -| Инжект секций в CUB-фид | ⚠️ залито (35440 Б) — **ждёт перезапуска Lampa на ТВ** | -| Причина «секции не появились» | 🔴 `Manifest` не виден в обёртке → `ReferenceError` → фикс через `window.__wl_menu` | +| Инжект секций в CUB-фид | ✅ **механизм найден и проверен** (`partNext`), залито (36956 Б в сборке) | +| Причина «секции не появились» | 🔴 обёртка `cub.main` невызываема (`permit` в замыкании) → перешли на `partNext` | +| Осталось | перезапуск Lampa на ТВ (`luna-send` не работает — нужен пульт или CDP `Page.reload`) | | Сборщик плагина | `build_plugin.py` (детерминированный, с инвариантами); `patch_cub_inject.py` **отменён** | Скрипты: `/Users/admin/lampac-tmp/gen_watchlist_v2.py`, `deploy_lampac.py`