[2026-09-22] eagle: personal/tech/lampac-deployment.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-22 16:53:03 +06:00
1 parent f8b9114105
commit d1f17eca39
1 file changed
+164 -2
+164 -2
View File
@@ -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`