[2026-09-22] eagle: personal/tech/lampac-deployment.md
This commit is contained in:
1 parent
f8b9114105
commit
d1f17eca39
1 file changed
+164
-2
@@ -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`
|
||||
|
||||
Reference in new issue
Block a user