353 lines
22 KiB
Markdown
353 lines
22 KiB
Markdown
---
|
||
created: '2026-09-22'
|
||
namespace: family
|
||
related:
|
||
- '[[family/how-to/tv-luna-send]]'
|
||
- '[[family/how-to/htpc-webos-luna]]'
|
||
- '[[personal/tech/lampac-deployment]]'
|
||
tags:
|
||
- tv
|
||
- webos
|
||
- lampa
|
||
- lampac
|
||
- plugin
|
||
- how-to
|
||
title: tv-lampac-plugin — подключение плагина Lampa на LG TV по SSH
|
||
type: how-to
|
||
updated: '2026-09-22'
|
||
---
|
||
# tv-lampac-plugin.sh — подключение плагина Lampa к Lampac на LG TV
|
||
|
||
> Создан 2026-09-22. Проблема, которую решает: добавить плагин/источник в Lampa на ТВ
|
||
> **без пульта**, автоматически по SSH.
|
||
> Связано: [[family/how-to/tv-luna-send]], [[family/how-to/htpc-webos-luna]], [[personal/tech/lampac-deployment]].
|
||
|
||
## Зачем
|
||
|
||
Настройки Lampa хранятся в localStorage webOS-приложения. Пульта под рукой может не быть,
|
||
а добавлять вручную (`Настройки → Плагины → ввести URL`) долго и неудобно.
|
||
Данный скрипт прописывает плагин/источник прямо в localStorage приложения Lampa.
|
||
|
||
## Ключевые пути на ТВ
|
||
|
||
| Что | Путь |
|
||
|---|---|
|
||
| Приложение Lampa | `/media/developer/apps/usr/palm/applications/com.lampac.tv/` |
|
||
| localStorage (LevelDB) | `/media/developer/apps/usr/palm/applications/com.lampac.tv/.localstorage/` |
|
||
| Настройки Lampa | ключ `lampac_settings` (JSON) в LevelDB |
|
||
|
||
## Как Lampa хранит настройки
|
||
|
||
Lampa в webOS использует `localStorage`, который Chromium хранит в **LevelDB**
|
||
(`.localstorage/leveldb/`). Прямая запись в LevelDB при работающем приложении **опасна**:
|
||
приложение перезапишет значение из памяти при выходе.
|
||
|
||
**Правильный порядок:**
|
||
1. Закрыть приложение Lampa (иначе перезапишет)
|
||
2. Записать значение в localStorage
|
||
3. Запустить приложение
|
||
|
||
## 🔴 Пункта «Настройки → Источник» НЕ СУЩЕСТВУЕТ (проверено 2026-09-22)
|
||
|
||
**Не повторять эту ошибку — Alex дважды сказал, что пункта нет.**
|
||
Я его выдумал, отвечая «как увидеть списки».
|
||
|
||
**Правильный путь (Alex нашёл сам 2026-09-22):**
|
||
**Настройки → «остальное» → основной источник → «Мой список».**
|
||
|
||
⚠️ Мой предыдущий вариант («влево на ряду → панель источников») **не подтверждён**.
|
||
|
||
⚠️ **При выборе «Мой список» исчезает родной каталог CUB** — это **не баг Lampa**,
|
||
а следствие перехвата кликов в `plugin.js` (см. раздел «🔴 Что на самом деле подменяет CUB»).
|
||
|
||
## 🔴 Что на самом деле подменяет CUB — `plugin.js`, а не YAML (проверено 2026-09-22)
|
||
|
||
**Что хотел Alex:**
|
||
|
||
> «Я предполагал что будет отображаться то что и раньше (список cub) но В НЕГО будет
|
||
> сверху добавлено несколько секций в которых будут РЕАЛЬНЫЕ ЭЛЕМЕНТЫ — а не сгенерируют
|
||
> пустые заглушки!»
|
||
|
||
⚠️ **Гипотеза «`menu` подменяет / `main` добавляет» — ОПРОВЕРГНУТА на живом сервере.**
|
||
Её здесь не повторять. Факты:
|
||
|
||
| Гипотеза | Факт |
|
||
|---|---|
|
||
| `menu` подменяет родные разделы | ❌ `menu` **регистрирует канал**. Без него сайт отбрасывается: `ApiController.cs:70` → `if (init == null \|\| !init.enable \|\| init.menu == null \|\| init.hide) continue;` |
|
||
| `main` добавляет секции сверху | ❌ блока `main` **в YAML не существует** — YamlDotNet давится неизвестным полем, `goInit` → null, сайт молча пропадает |
|
||
| «Убрать `menu` из watchlist.yaml» | ❌ **сломало канал**: «Мой список» исчез из `/catalog`, список пустой. Три раунда правок, три рестарта |
|
||
|
||
**Настоящий виновник — `plugin.js`** (он же `/catalog.js`):
|
||
|
||
```js
|
||
Lampa.Listener.follow('menu', function(e){
|
||
if (e.type=='action' && (e.action=='tv'||'cartoon'||'anime'||'movie'||'relise')) {
|
||
var catalog = Api.getCatalog();
|
||
if (!catalog) return;
|
||
...
|
||
Lampa.Router.call('category', {...});
|
||
e.abort(); // ← перехват клика по родному разделу
|
||
}
|
||
});
|
||
```
|
||
|
||
**Перехват работает ТОЛЬКО когда выбран источник «Мой список».** Родной CUB/tmdb не
|
||
трогается, пока источник не переключён на наш.
|
||
|
||
**Вывод про «CUB + мой список одновременно»:** родной CUB и «Мой список» — **два источника
|
||
Lampa** (переключаются в «остальное → основной источник»). Показать одновременно нельзя
|
||
без своего плагина. Варианты — [[personal/tech/lampac-deployment]], раздел
|
||
«🎯 Как добиться „CUB + мой список сверху“».
|
||
|
||
## 🟡 «Здесь пусто» и нет постеров — потому что данные не из Radarr
|
||
|
||
Второй симптом: элементы без превью, при открытии «здесь пусто».
|
||
Замер выдачи `/catalog/list?plugin=watchlist&cat=films`:
|
||
|
||
| Метрика | Значение |
|
||
|---|---|
|
||
| Всего позиций | 360 |
|
||
| С постером (`img != null`) | **0** |
|
||
| С реальным ID (`film/...`) | **18** |
|
||
|
||
Причина: генератор парсил `movies-watchlist.md` — **текст названий**, без TMDB ID и постеров.
|
||
Остальным 342 подставлялся `href` на **поиск** Кинопоиска → Lampa открывала страницу поиска.
|
||
|
||
**Правильный источник — Radarr API** (туда фильмы и добавлялись, там уже есть `tmdbId`
|
||
и `images[].remoteUrl`). Alex: «Они уже резолвятся же блядь!! Оно же добавлялось в arr!»
|
||
|
||
```bash
|
||
curl -sL "http://localhost:7878/api/v3/movie?apikey=$KEY" | jq length # → 50
|
||
# ⚠️ -L обязателен, без него 307 и пустое тело
|
||
```
|
||
|
||
Покрытие: Radarr **50** фильмов vs `.md` **360**. Что делать с остальными 310 — открытый
|
||
вопрос к Alex.
|
||
|
||
## 🔴 БАГ: источник не виден в панели (`enumerable: false`)
|
||
|
||
**Найдено 2026-09-22** диагностикой через Chrome DevTools ТВ (см. раздел ниже).
|
||
|
||
Факты с живого ТВ:
|
||
|
||
| Замер | Значение | Смысл |
|
||
|---|---|---|
|
||
| `Lampa.Storage.field('source')` | `'Мой список'` | источник **уже выбран** |
|
||
| `Object.keys(Lampa.Api.sources)` | `'tmdb|cub'` | ❌ источника нет в перечислении |
|
||
| `Lampa.Api.sources['Мой список'].getCatalog()` | `search, movie, cartoons, anime, menu, main` | ✅ каталог доступен напрямую |
|
||
| `Object.getOwnPropertyDescriptor(Lampa.Api.sources,'Мой список')` | `{"enumerable":false,"configurable":false}` | ← **корень** |
|
||
|
||
Причина в `/lampac/module/Catalog/plugin.js`, строка 59 (`loadCatalogs()`, **два вхождения**):
|
||
|
||
```js
|
||
// БЫЛО (баг)
|
||
Object.defineProperty(Lampa.Api.sources, key, { get: function(){ return Api; } });
|
||
|
||
// НАДО
|
||
Object.defineProperty(Lampa.Api.sources, key,
|
||
{ get: function(){ return Api; }, enumerable: true, configurable: true });
|
||
```
|
||
|
||
**`plugin.js` живёт в ОБРАЗЕ, не на HDD** (`docker inspect` показывает монтирования только
|
||
на `catalog/sites` и `catalog/override`). Правка через `docker exec` исчезнет при обновлении.
|
||
|
||
Фикс — смонтировать поправленный файл через compose:
|
||
`./catalog/plugin.js:/lampac/module/Catalog/plugin.js:ro`.
|
||
Полные команды и откат — [[personal/plans/lampac-watchlist-plugin]], раздел «ГЛАВНЫЙ ПИТФОЛЛ».
|
||
|
||
**Статус: фикс НЕ применён, ждёт апрува Alex (2026-09-22).**
|
||
|
||
## 🛠 Диагностика ТВ через Chrome DevTools (главный инструмент, найден 2026-09-22)
|
||
|
||
**Ключевое открытие: webOS отдаёт Chrome DevTools Protocol на порту 9998.**
|
||
У процессов `WebAppMgr` в аргументах есть `--remote-debugging-port=9998`.
|
||
Это даёт **чтение состояния живой Lampa** — то, чего не дают ни логи, ни tcpdump.
|
||
|
||
```bash
|
||
# 1. Список отлаживаемых страниц + URL приложения
|
||
curl -s --max-time 8 "http://192.168.1.70:9998/json" | /usr/bin/jq -r '.[] | "\(.type): \(.url)"'
|
||
|
||
# 2. Проверка сети до Lampac (на ТВ!)
|
||
ssh root@192.168.1.70 'curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" \
|
||
--max-time 8 http://192.168.1.14:9118/catalog'
|
||
|
||
# 3. Живые соединения с Lampac (смотреть на ТВ, НЕ на сервере)
|
||
ssh root@192.168.1.70 'netstat -tn 2>/dev/null | grep 9118'
|
||
|
||
# 4. Что запущено сейчас
|
||
ssh root@192.168.1.70 'script -q -c "luna-send -n 1 -f \
|
||
luna://com.webos.applicationManager/getForegroundAppInfo {}" /dev/null'
|
||
|
||
# 5. Перезапустить приложение (JSON экранирован И обёрнут в двойные кавычки!)
|
||
ssh root@192.168.1.70 'script -q -c "luna-send -n 1 -f \
|
||
luna://com.webos.applicationManager/launch \"{\\\"id\\\":\\\"com.lampac.tv\\\"}\"" /dev/null'
|
||
```
|
||
|
||
Чтение переменных Lampa — через `websocket-client` + `Runtime.evaluate`:
|
||
готовые скрипты `/tmp/lampa_probe.py` и `/tmp/lampa_probe3.py` (см. план).
|
||
|
||
### Ловушки диагностики (проверено на живом ТВ)
|
||
|
||
⚠️ **Момент замера.** `sudo ss -tn | grep :9118` на Кра́кене сразу после старта дал **0 соединений** —
|
||
я сделал ложный вывод «ТВ не ходит на сервер». Через 30 с на ТВ:
|
||
**1 ESTABLISHED + 6 TIME_WAIT** — всё работает. Смотреть соединения **на ТВ**, не на сервере.
|
||
|
||
⚠️ **`launch` через luna требует экранированного JSON в кавычках.** Без кавычек —
|
||
`errorCode: 2, invalid parameters` (молча падает). `getForegroundAppInfo {}` работает без кавычек.
|
||
|
||
⚠️ **`tcpdump` на Кра́кене НЕТ.** Не ставили — DevTools-подход дал больше (состояние JS, а не пакеты).
|
||
|
||
⚠️ **`luna://com.webos.service.capture/takeScreenShot` не существует** на этом ТВ
|
||
(`Unknown method "takeScreenShot"`). Скриншот так не снять.
|
||
|
||
⚠️ **Логи HTTP Lampac не ведёт** — `docker logs` не покажет запросы ТВ. Не искать там.
|
||
|
||
## Как плагин `catalog.js` регистрирует источник (механика)
|
||
|
||
Важно для диагностики — плагин **не добавляет новый пункт в главное меню**, он **подменяет
|
||
существующие**:
|
||
|
||
```js
|
||
// при старте / app ready:
|
||
Lampa.Utils.account(Manifest.api_host + '/catalog', function(json){
|
||
Manifest.catalogs = json; // все каталоги с сервера
|
||
keys.forEach(function(key){
|
||
Lampa.Params.values.source[key] = key; // регистрирует источник
|
||
Object.defineProperty(Lampa.Api.sources, key, { // ← ЗДЕСЬ БАГ
|
||
get: function(){ return Api; } // нет enumerable:true
|
||
});
|
||
if (Manifest.catalogs[key].search)
|
||
Lampa.Search.addSource(Api.discovery(key)); // добавляет в поиск
|
||
});
|
||
});
|
||
// хук на меню: клик по movie/tv/cartoon/anime/relise подменяется на URL из catalogs[key].menu
|
||
Lampa.Listener.follow('menu', ...)
|
||
```
|
||
|
||
⚠️ Свойство ставится через `defineProperty` **без `enumerable: true`** → `Object.keys()` его
|
||
не видит → источник не появляется в панели выбора (разбор бага — выше).
|
||
|
||
Отсюда следует:
|
||
- Отдельного переключателя в настройках нет **by design** — источник выбирается панелью слева.
|
||
- Плагин **подтягивает каталоги только при старте приложения**. Если добавить плагин и не
|
||
перезапустить Lampa — каталоги не зарегистрируются. Нужен полный перезапуск (не сворачивание).
|
||
- Заголовок каталога после переключения содержит имя источника в верхнем регистре:
|
||
«Фильмы — МОЙ СПИСОК».
|
||
|
||
## Что должен отдавать сервер (проверено 2026-09-22)
|
||
|
||
| Endpoint | Ответ | Значение |
|
||
|---|---|---|
|
||
| `/catalog.js` | 200, ~32 КБ | сам плагин, манифест с `api_host` |
|
||
| `/catalog` | JSON, 7 ключей | список каталогов: Rezka, Kinobase, FilmixApp, VoKino, Eneyida, KinoUkr, **Мой список** |
|
||
| `/catalog/list?plugin=watchlist&cat=films` | `{page, results, total_pages}` | 360 позиций, `total_pages: 1` |
|
||
|
||
`api_host` подставляется по IP запроса → `http://192.168.1.14:9118` (не `localhost`),
|
||
поэтому ТВ получает рабочие ссылки.
|
||
|
||
**7 источников в `/catalog`** — нормальный минимум: модуль `Catalog` собирает их из bundled-плагинов
|
||
плюс `watchlist`. «Мой список» идёт **первым** ключом.
|
||
|
||
## ⚠️ Ловушка диагностики: `plugins_add` в `lampainit.js` — НЕ то, что кажется
|
||
|
||
`http://192.168.1.14:9118/lampainit.js` содержит:
|
||
```js
|
||
var plugins_add = [
|
||
{"url":"http://192.168.1.14:9118/catalog.js","status":1,"name":"Альтернативные источники каталога", ...},
|
||
...
|
||
];
|
||
```
|
||
|
||
Это **серверный список плагинов, которые Lampac сам подсовывает** в UI.
|
||
Клиент на ТВ (webOS-приложение `com.lampac.tv`) — **не отдельная Lampa**: он грузит `app.min.js`
|
||
и `lampainit.js` **с сервера** (`loader.js` → `lampac_url` из localStorage, дефолт `http://192.168.1.14:9118`).
|
||
|
||
Следствие: каталог watchlist работает через **серверный модуль `Catalog`**, а не через строку
|
||
`plugins_add`. Не искать причину поломки в этом массиве.
|
||
|
||
## Питфоллы (проверено 2026-09-22)
|
||
|
||
1. **localStorage у webOS-приложений изолирован.** Файл в `.localstorage/` у сторонних
|
||
(Homebrew) приложений **может отсутствовать** — Chromium держит стор в памяти и
|
||
сбрасывает на диск не сразу. Если каталога нет, сначала запустить приложение один раз.
|
||
|
||
2. **`luna-send` через SSH молчит** — вывод в tty. Оборачивать в `script -q -c "..." /tmp/o.txt`
|
||
и читать файл. См. [[family/how-to/tv-luna-send]].
|
||
|
||
3. **LevelDB нельзя править на живом приложении.** Сначала `closeByAppId`, потом запись.
|
||
|
||
4. **`init.conf` лежит НЕ в корне каталога Lampac, а в `config-module/init.conf`**
|
||
(монтируется в `/lampac/init.conf:ro`). Искать там, а не по `lampac/init.conf`
|
||
— иначе получишь ложный «файл пропал».
|
||
|
||
5. **После добавления плагина обязательно полный перезапуск Lampa** — каталоги регистрируются
|
||
только на старте. ⚠️ Но **не делай из «нуля соединений» вывод о поломке**: сразу после старта
|
||
соединений действительно 0, через ~30 с появляются. Смотреть **с ТВ** (`netstat -tn | grep 9118`).
|
||
|
||
6. **`plugin.js` лежит в ОБРАЗЕ, а не на HDD.** Монтируются только `catalog/sites` и
|
||
`catalog/override`. Правки `/lampac/module/Catalog/plugin.js` через `docker exec` **теряются
|
||
при обновлении образа** — нужен bind-mount через compose.
|
||
|
||
7. **Не верить `Object.keys()` на слово — проверять `getOwnPropertyDescriptor`.** Свойство может
|
||
существовать (доступно напрямую) и при этом не быть enumerable. `Object.keys` вернёт список
|
||
без него, и это выглядит как «источника нет», хотя он есть.
|
||
|
||
8. **Проще всего — через UI самого пульта**, если он доступен:
|
||
Lampa → Настройки → Плагины → добавить URL. Скрипт нужен, когда пульта нет.
|
||
|
||
## Что должно быть прописано для Lampac
|
||
|
||
| Настройка | Значение |
|
||
|---|---|
|
||
| Плагин (онлайн-источники) | `http://192.168.1.14:9118/online.js` |
|
||
| Каталог (свой список) | `http://192.168.1.14:9118/catalog.js` |
|
||
| TorrServer | `http://192.168.1.14:9118` (Настройки → TorrServer → «Использовать основную ссылку») |
|
||
| Буфер плеера | 50–100 МБ |
|
||
|
||
## Скрипт
|
||
|
||
Лежит на Mac: `~/Automation/tv-lampac-plugin.sh`
|
||
(дописывается при первом реальном применении; пока не создан — см. «Статус»).
|
||
|
||
## Статус
|
||
|
||
**Проверено на живом ТВ 2026-09-22** (диагностика через DevTools, порт 9998).
|
||
|
||
**Что установлено точно:**
|
||
- ТВ достаёт Кра́кен (`/catalog` 200 за 0.26 с), Lampa ходит на сервер (ESTABLISHED).
|
||
- Плагин `catalog.js` **добавлен**, `window.plugin_catalog = true`, `appready = true`.
|
||
- `Storage.field('source')` = `'Мой список'` — источник **выбран**.
|
||
- `Lampa.Api.sources['Мой список']` **существует** и отдаёт каталог
|
||
(`search, movie, cartoons, anime, menu, main`) — **технически доступен**.
|
||
- ❌ В панели выбора источника его **нет** — `plugin.js` регистрирует свойство
|
||
без `enumerable: true`. **Баг в Lampac, не в нашей настройке.**
|
||
|
||
**Что переделывается (обновлено 2026-09-22 ночь):**
|
||
|
||
1. ❌ ~~Убрать блок `menu` из `watchlist.yaml`, оставить `main`~~ — **ОТМЕНЕНО, невозможно.**
|
||
`main` в YAML ломает парсинг (сайт исчезает из `/catalog`), `menu` обязателен для
|
||
регистрации канала. Подмену делает `plugin.js`. См. раздел выше.
|
||
2. ⏳ Переключить источник данных с парсинга `.md` на **`resolver.py`** (TMDB + Кинопоиск)
|
||
→ постеры + TMDB ID для всех 360. *(Radarr API даёт только 50 — в нём нет остальных 310.)*
|
||
3. ⏳ Смонтировать поправленный `plugin.js` (`enumerable: true`)
|
||
4. ✅ **Выключена автоскачка на HDD** — Radarr (45→0 monitored, очередь 6→0, RSS 30→0),
|
||
Sonarr (13→0, 19→0, 15→0). Бэкапы `20260922-123404`. Метаданные целы: 50 фильмов,
|
||
46 с постерами, 24 файла на диске не тронуты.
|
||
|
||
**Текущее состояние каталога: РАБОЧИЙ.** «Мой список» на месте в `/catalog`, 4 категории
|
||
(360/33/3/7). `watchlist.yaml` откачен к проверенной форме.
|
||
|
||
**Открытое решение Alex:** родной CUB и «Мой список» одновременно показать нельзя —
|
||
нужен свой плагин. Варианты (оставить как есть / патч `plugin.js` / свой плагин) —
|
||
[[personal/tech/lampac-deployment]], раздел «🎯 Как добиться „CUB + мой список сверху“».
|
||
|
||
Полный разбор — [[personal/plans/lampac-watchlist-plugin]].
|
||
|
||
**Скрипт-автоматизация по-прежнему не создана** — и, вероятно, не нужна: источник
|
||
переключается через **Настройки → «остальное» → основной источник** (Alex сделал сам).
|
||
|
||
**Скрипт-автоматизация по-прежнему не создана.** Прямая запись в localStorage **не нужна**:
|
||
проблема оказалась не в настройках Lampa, а в коде плагина. Если автоматизация понадобится —
|
||
подход: `closeByAppId com.lampac.tv` → запись ключа в localStorage → `launch com.lampac.tv`
|
||
(учесть питфоллы 1–3). Но сначала — фикс `plugin.js`.
|