Files
obsidian-vault/family/how-to/tv-lampac-plugin.md
T

22 KiB
Raw Blame History

created, namespace, related, tags, title, type, updated
created namespace related tags title type updated
2026-09-22 family
family/how-to/tv-luna-send
family/how-to/htpc-webos-luna
personal/tech/lampac-deployment
tv
webos
lampa
lampac
plugin
how-to
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 при работающем приложении опасна: приложение перезапишет значение из памяти при выходе.

Правильный порядок:

  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):

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)

  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.