22 KiB
Executable File
created, namespace, related, tags, title, type, updated
| created | namespace | related | tags | title | type | updated | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-09-22 | family |
|
|
tv-lampac-plugin — подключение плагина Lampa на LG TV по SSH | how-to | 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 при работающем приложении опасна:
приложение перезапишет значение из памяти при выходе.
Правильный порядок:
- Закрыть приложение Lampa (иначе перезапишет)
- Записать значение в localStorage
- Запустить приложение
🔴 Пункта «Настройки → Источник» НЕ СУЩЕСТВУЕТ (проверено 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):
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!»
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(), два вхождения):
// БЫЛО (баг)
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.
# 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 регистрирует источник (механика)
Важно для диагностики — плагин не добавляет новый пункт в главное меню, он подменяет существующие:
// при старте / 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 содержит:
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)
-
localStorage у webOS-приложений изолирован. Файл в
.localstorage/у сторонних (Homebrew) приложений может отсутствовать — Chromium держит стор в памяти и сбрасывает на диск не сразу. Если каталога нет, сначала запустить приложение один раз. -
luna-sendчерез SSH молчит — вывод в tty. Оборачивать вscript -q -c "..." /tmp/o.txtи читать файл. См. family/how-to/tv-luna-send. -
LevelDB нельзя править на живом приложении. Сначала
closeByAppId, потом запись. -
init.confлежит НЕ в корне каталога Lampac, а вconfig-module/init.conf(монтируется в/lampac/init.conf:ro). Искать там, а не поlampac/init.conf— иначе получишь ложный «файл пропал». -
После добавления плагина обязательно полный перезапуск Lampa — каталоги регистрируются только на старте. ⚠️ Но не делай из «нуля соединений» вывод о поломке: сразу после старта соединений действительно 0, через ~30 с появляются. Смотреть с ТВ (
netstat -tn | grep 9118). -
plugin.jsлежит в ОБРАЗЕ, а не на HDD. Монтируются толькоcatalog/sitesиcatalog/override. Правки/lampac/module/Catalog/plugin.jsчерезdocker execтеряются при обновлении образа — нужен bind-mount через compose. -
Не верить
Object.keys()на слово — проверятьgetOwnPropertyDescriptor. Свойство может существовать (доступно напрямую) и при этом не быть enumerable.Object.keysвернёт список без него, и это выглядит как «источника нет», хотя он есть. -
Проще всего — через 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).
Что установлено точно:
- ТВ достаёт Кра́кен (
/catalog200 за 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 ночь):
- ❌
Убрать блок— ОТМЕНЕНО, невозможно.menuизwatchlist.yaml, оставитьmainmainв YAML ломает парсинг (сайт исчезает из/catalog),menuобязателен для регистрации канала. Подмену делаетplugin.js. См. раздел выше. - ⏳ Переключить источник данных с парсинга
.mdнаresolver.py(TMDB + Кинопоиск) → постеры + TMDB ID для всех 360. (Radarr API даёт только 50 — в нём нет остальных 310.) - ⏳ Смонтировать поправленный
plugin.js(enumerable: true) - ✅ Выключена автоскачка на 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.