[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 мин не подхватится |
|
| Кэш манифеста | `loader.js`: `cache_version = floor(Date.now()/9e5)` — смена сервера в течение ~15 мин не подхватится |
|
||||||
| Служба devtools | `com.webos.service.devtools` **НЕ существует** на webOS 5.4.2 Lite |
|
| Служба 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, БЕЗ ручного переключения
|
### 🔴 ТРЕБОВАНИЕ Alex: секции ВНУТРИ CUB, БЕЗ ручного переключения
|
||||||
|
|
||||||
**Дословно:** «надо блядь добавить в CUB список новые секции а не ручное блядь переключение!»
|
**Дословно:** «надо блядь добавить в CUB список новые секции а не ручное блядь переключение!»
|
||||||
@@ -1959,8 +2120,9 @@ else{Lampa.Listener.follow('app',function(e){if(e.type=='ready')patchCubMain();}
|
|||||||
| `runtime`, `vote_average` | тем же способом через `format` |
|
| `runtime`, `vote_average` | тем же способом через `format` |
|
||||||
| `displayname` | «Мой список» — надпись в UI |
|
| `displayname` | «Мой список» — надпись в UI |
|
||||||
| **✅ Alex подтвердил в UI** | **фильмы Watchlist открываются и ПРОИГРЫВАЮТСЯ** |
|
| **✅ Alex подтвердил в UI** | **фильмы Watchlist открываются и ПРОИГРЫВАЮТСЯ** |
|
||||||
| Инжект секций в CUB-фид | ⚠️ залито (35440 Б) — **ждёт перезапуска Lampa на ТВ** |
|
| Инжект секций в CUB-фид | ✅ **механизм найден и проверен** (`partNext`), залито (36956 Б в сборке) |
|
||||||
| Причина «секции не появились» | 🔴 `Manifest` не виден в обёртке → `ReferenceError` → фикс через `window.__wl_menu` |
|
| Причина «секции не появились» | 🔴 обёртка `cub.main` невызываема (`permit` в замыкании) → перешли на `partNext` |
|
||||||
|
| Осталось | перезапуск Lampa на ТВ (`luna-send` не работает — нужен пульт или CDP `Page.reload`) |
|
||||||
| Сборщик плагина | `build_plugin.py` (детерминированный, с инвариантами); `patch_cub_inject.py` **отменён** |
|
| Сборщик плагина | `build_plugin.py` (детерминированный, с инвариантами); `patch_cub_inject.py` **отменён** |
|
||||||
|
|
||||||
Скрипты: `/Users/admin/lampac-tmp/gen_watchlist_v2.py`, `deploy_lampac.py`
|
Скрипты: `/Users/admin/lampac-tmp/gen_watchlist_v2.py`, `deploy_lampac.py`
|
||||||
|
|||||||
Reference in new issue
Block a user