diff --git a/personal/plans/lampac-watchlist-plugin.md b/personal/plans/lampac-watchlist-plugin.md index 741a80c6..800e1b58 100644 --- a/personal/plans/lampac-watchlist-plugin.md +++ b/personal/plans/lampac-watchlist-plugin.md @@ -16,116 +16,204 @@ tags: - webos - plugin - kraken -title: Watchlist в UI Lampa — плагин отображения +title: Watchlist в UI Lampa — каталог из списка type: plan updated: '2026-09-22' --- -# Watchlist в UI Lampa — плагин отображения (план) +# Watchlist в UI Lampa — каталог из списка (план) -> Составлен 2026-09-22. Ждёт подтверждения Alex. -> Предыдущий шаг (Lampac на Кра́кене) — [[personal/plans/lampac-kraken]], шаги 1–6 закрыты. +> Составлен 2026-09-22, переписан после разведки кода Catalog. Ждёт подтверждения Alex. +> Базовое развёртывание — [[personal/plans/lampac-kraken]] (шаги 1–6 закрыты). ## Задача -Показывать **список фильмов Alex** (`family/documents/movies-watchlist.md`) прямо в UI Lampa на ТВ — -как каталог для просмотра. **Не локальный плейбэк**, а отображение списка. +Показывать список фильмов Alex (`family/documents/movies-watchlist.md`) **в UI Lampa на ТВ** — каталогом. +Не локальный плейбэк. Формулировка Alex: «отображение фильмов из списка». -Уточнение Alex: «это не локальный плейбэк а отображение фильмов из списка». +## ✅ Затык снят: чем это делается -## Что НЕ так понято (зафиксировать, чтобы не переделывать) +В образе Lampac уже есть модуль **`Catalog`** — YAML-каталоги → плагин Lampa `/catalog.js`. +Сейчас **выключен**. Писать плагин с нуля **не нужно**. -| Толкование | Верно? | +## Как работает Catalog (разобрано по коду 2026-09-22) + +**Файлы в контейнере:** `/lampac/module/Catalog/` — `Controllers/`, `plugin.js`, `README.md`, +`sites/*.yaml` (10 готовых примеров: `vokino`, `rezka`, `kinopub`, `anime`, …). + +### Механика + +| Что | Как | |---|---| -| Показать **свой список** (`movies-watchlist.md`) в UI | ✅ **да, это задача** | -| Показать **файлы библиотеки** с диска Кра́кена (Jellyfin-подобное) | ❌ нет — это шаг 7 старого плана, **другое** | -| Локальный плейбэк (раздача торрента с диска Кра́кена) | ❌ нет | +| Данные | `sites/.yaml` — описание сайта: `host`, `menu`, `search`, `list`, `content` | +| Подстановки | `override/.yaml` и `override/_.yaml` — переопределения поверх базового | +| Роуты | `/catalog.js` (плагин), `/catalog` (JSON каналов), `/catalog/list`, `/catalog/card` | +| WAF | `^/catalog/` → **10 запросов/сек** | +| Имя файла | только `[a-z0-9-]`; есть fallback-поиск по `displayname` | -## Что нашлось в Lampac (разведка 2026-09-22) +### Ключевое: обязателен HTTP -В образе `ghcr.io/lampac-nextgen/lampac` 33 модуля (`/lampac/module/`). Релевантные три: - -| Модуль | Что делает | Статус | Подходит? | -|---|---|---|---| -| **Catalog** | **YAML-каталоги → плагин `/catalog.js`** | ⛔ выключен | ✅ **главный кандидат** | -| DLNA | DLNA/UPnP, локальные файлы, торрент-менеджмент | ✅ включён | ⚠️ это про файлы, не про список | -| Online | 70+ онлайн-источников → `/online.js` | ✅ включён | уже используется | - -### Модуль Catalog — детали - -- **Роут:** `/catalog.js` (плагин Lampa), внутренние — `/catalog/` -- **Данные:** YAML-файлы в `/sites/.yaml` -- **Имя файла** — только `[a-z0-9-]`, иначе `Regex.Replace` срежет -- **Есть lookup по `displayname`** внутри `*.yaml`, если файла по имени нет -- **WAF-лимит:** `^/catalog/` → 10 запросов/сек -- **`ModuleBaseConf`** с `limit_map`, класс `CatalogSettings`, есть `IEnumerable`-итерация - -**Почему выключен:** -```jsonc -// current.conf -"SkipModules": [ "Catalog", "Tracks", "Transcoding", ... ] -"catalog": false // в блоке плагинов LampaWeb +```csharp +if (!url.StartsWith("http")) + url = $"{init.host}/{url}"; // ListController.cs:87 ``` -Оба надо включить. +`host` из YAML сканируется **по HTTP** (`Http.Get` / Playwright / RCH). +**Локальные файлы напрямую Catalog читать не умеет** — только HTTP-ответ. -⚠️ **Питфолл:** `init.conf` монтируется **не был** — у нас в compose нет volume на `/lampac/init.conf`. -Файл живёт внутри образа. Правки через `docker exec` **потеряются при пересоздании контейнера**. -Значит: либо добавить volume, либо править через AdminPanel, либо `docker cp` + mount. +### Два режима парсинга -## Развилка архитектуры — нужно решение Alex +```csharp +bool? jsonPath = contentParse.jsonPath ?? init.jsonPath; -Отображение списка и воспроизведение — **разные вещи**. Список отдаём, но по клику что играть? +if (jsonPath == true) json = JToken.Parse(html); // JSON-режим +else doc.LoadHtml(html); // HTML-режим +``` -| # | Вариант | Как работает | Плюсы | Минусы | -|---|---|---|---|---| -| **A** | **Каталог → TMDB → торренты** | `/catalog.js` отдаёт названия, Lampa ищет их в TMDB, по клику — TorrServer/онлайн | Просто. Список = то, что уже есть. Работает сегодня | Каталог отдельно от «Избранного» Lampa | -| **B** | **Генератор Lampa-«Избранного»** | Отдаём `movies-watchlist.md` как JSON — Lampa кладёт его в свою папку «Буду смотреть» | Из коробки в UI, без плагина | Лимит **50** у `kinopoisk.js`; формат Lampa-специфичный | -| **C** | **Catalog + свои ссылки** | YAML с ссылками на торренты с диска Кра́кена — это уже **локальный плейбэк** | Прямой запуск | ❌ **Alex сказал — не это** | +- `jsonPath: true` → ответ парсится как **JSON**, элементы берутся по `nodes` (`$.channels[*].details`) +- иначе → HTML через HtmlAgilityPack -**Рекомендация: A.** Список показываем, воспроизведение оставляем штатным (торренты/онлайн). Это ровно -«отображение фильмов из списка», без изобретения плейбэка. +🔴 **Это и есть рычаг:** любой **свой HTTP-эндпоинт, отдающий JSON нужной формы**, подойдёт как `host`. +Тогда задача сводится к генерации JSON + YAML-обёртки, без правки кода Lampac. -## Что нужно выяснить до кодирования +### Форма элемента (`content` в YAML) -1. **Формат YAML** — читать `Catalog/Controllers` в образе, узнать схему `CatalogSettings` - (поля: `displayname`, иконка, источник элементов, `tmdb`-режим?). -2. **Есть ли готовый Konopoisk/TMDB-режим** — если Catalog умеет принимать TMDB-коллекцию, - задача сводится к генерации YAML из watchlist. -3. **Как обновлять каталог** — watchlist меняется (Radarr, ⬇️, `[x]`), нужен генератор + hook. -4. **Фильтры** — показывать только `[ ]` (не просмотренные)? Прятать `👎`? Секции (`Фильмы`/`Аниме`/`Мультфильмы`)? -5. **`init.conf`** — как правки не потерять: volume vs AdminPanel. +```yaml +content: + nodes: "$.channels[*].details" # jsonPath-выражение (JSON) или CSS/XPath (HTML) + name: { attribute: name } + original_name:{ attribute: originalname } + href: { attribute: ident } + image: { attribute: poster } + year: { attribute: released } + serial_key: { attribute: type, format: | return value is "serial" ? value : null; } + args: + - { name_arg: vote_average, attribute: rating_kp } +``` -## Черновик шагов (уточнится после разведки формата) +Карточка — отдельная секция `card_parse` + `card_args` (описание, рейтинги, жанры, страна). +Полный живой пример — `sites/vokino.yaml` (копия в [[personal/tech/lampac-deployment]], раздел Catalog). -1. Включить модуль: убрать `Catalog` из `SkipModules`, поставить `"catalog": true`. -2. Разобрать схему YAML по кодe `Catalog/Controllers/*.cs` (в контейнере). -3. Написать генератор: `movies-watchlist.md` → `sites/.yaml`. - - Источник данных — **vault** (`family/documents/movies-watchlist.md`), git-синхронизирован - - Уже есть готовый парсер: `watchlist-sync/parser.py` (см. [[family/projects/watchlist-sync]]) -4. Смонтировать `sites/` в контейнер. -5. Плагин на ТВ: Lampa → Настройки → Плагины → `http://192.168.1.14:9118/catalog.js`. -6. **Приёмка:** список виден в UI Lampa на ТВ, названия совпадают с `movies-watchlist.md`. +## Включение модуля — 2 правки -## Как обновлять +```jsonc +// current.conf (внутри контейнера /lampac/current.conf) +"SkipModules": [ "Tracks", "Transcoding", ... ] // ← убрать "Catalog" (строка ~277) +"plugins": { ..., "catalog": true } // ← было false (строка ~1653) +``` -Варианты (выбрать после шага 2): -- hook в `watchlist-nightly.sh` (уже кроном 01:00 на Кра́кене) — догенерировать YAML после прогона -- отдельный cron-скрипт -- ручной запуск генератора +🔴 **ПИТФОЛЛ — `init.conf` НЕ смонтирован.** В нашем `docker-compose.yml` нет volume на `/lampac/init.conf`, +файл живёт в образе. Правки через `docker exec` **исчезнут при пересоздании контейнера** +(`docker compose up`, watchtower-обновление образа). Варианты: +- (а) добавить volume `./config/init.conf:/lampac/init.conf:ro` — надёжно, но нужен первичный `docker cp` +- (б) править через **AdminPanel** `/adminpanel` (модуль, правит `init.conf` + `current.conf`) +- (в) `docker cp` + commit — плохо -⚠️ `watchlist-nightly.sh` живёт в `~/scripts/` — **root:root**, правка только `sudo install -m 755`. +**Рекомендация: (а)** — конфиг на HDD, переживает пересоздание. -## Открытые вопросы к Alex +## Архитектура решения -1. **Развилка A/B/C** — согласен на A (каталог → TMDB → штатное воспроизведение)? -2. **Что показывать:** только непросмотренные `[ ]`? Или всё? -3. **Секции:** как в файле (`Фильмы`, `Мультфильмы`, `Аниме`) или одним списком? -4. **`👎` и `🗓️`** — прятать? +``` +family/documents/movies-watchlist.md ← источник (vault, git-синхрон) + │ существующий парсер: watchlist-sync/parser.py + ▼ +генератор (Python, на Кра́кене) + │ пишет JSON нужной формы + ▼ +/lampac/... JSON-эндпоинт, доступный по HTTP с Lampac + │ + ▼ +sites/watchlist.yaml ← Catalog-описание, host=<наш JSON URL> + menu: Фильмы / Мультфильмы / Аниме (по секциям .md) + │ + ▼ +Lampa на ТВ: плагин http://192.168.1.14:9118/catalog.js +``` + +**Откуда отдавать JSON — варианты (выбрать на этапе реализации):** + +| # | Где | Плюс | Минус | +|---|---|---|---| +| 1 | **статика в `/lampac/wwwroot/`** | ничего не поднимать, Lampac сам отдаёт | только чтение, обновление = перезапись файла | +| 2 | **отдельный лёгкий HTTP-сервер** на Кра́кене | есть API/логика | ещё один контейнер | +| 3 | `file://` | — | ❌ не поддерживается (только http) | + +**Склоняюсь к (1)** — генерировать `wwwroot/watchlist.json`, Lampac отдаёт его сам, без новых сущностей. + +## Что показывать в каталоге + +Секции берём из самого файла: `## Фильмы`, `## Мультфильмы`, `## Аниме` → три категории меню. +Поля: `name` (название), `year`, `href` (ссылка на Кинопоиск — уже есть в файле как `[название](https://www.kinopoisk.ru/film/NNN/)`), +`image` — постер (можно взять через TMDB-кэш Lampac, `tmdbproxy`). + +⚠️ **`href` в файле — ссылка Кинопоиска**, а Lampa ждёт карточку. Отрисовку карточки решает `card_parse` +(в vokino он ходит по `{host}/view/{uri}`). Для нашего случая возможен режим **только список, без карточки** — +проверить на этапе реализации. + +## Обновление каталога + +- Генератор дёргать **после** `watchlist-nightly.sh` (уже кроном 01:00 на Кра́кене) — догенерировать JSON +- ⚠️ `watchlist-nightly.sh` в `~/scripts/` — **root:root**, правка только `sudo install -m 755` +- Партия данных меняется (`⬇️`, `[x]`, 👍→перенос) — JSON пересобирать после каждого прогона + +## Шаги (черновик, уточняется на этапе реализации) + +1. Включить модуль Catalog: `SkipModules` + `catalog: true`, закрепить `init.conf` volume. +2. Смонтировать `module/Catalog/` (или только `sites/` + `override/`) на HDD — чтобы каталоги не терялись. +3. Написать генератор `movies-watchlist.md` → JSON (переиспользовать `parser.py` из watchlist-sync). +4. Положить JSON туда, откуда Lampac отдаёт статику. +5. Написать `sites/watchlist.yaml` по образцу `vokino.yaml`. +6. Подключить на ТВ: Lampa → Настройки → Плагины → `http://192.168.1.14:9118/catalog.js`. +7. **Приёмка:** категории видны в UI Lampa на ТВ, названия совпадают со списком. + +## Откат + +`catalog: false` + вернуть `Catalog` в `SkipModules`. Ничего в Lampac не патчится. + +## Правила отбора и сортировки (утверждено Alex 2026-09-22) + +### Фильтрация + +| Правило | Действие | +|---|---| +| `[ ]` непросмотренные | **показывать** | +| `[x]` просмотренные | ❌ скрыть | +| `👎` | ❌ скрыть | +| `🗓️` upcoming | показывать (решить при реализации — есть в файле) | +| `❓` ambiguous | показывать (название как есть) | + +### Сортировка внутри списка — трёхключевая + +1. **`⭐` (U+2B50) — первыми** +2. **Рейтинг — по убыванию** (IMDb/KP из строки файла; строки `[название](kp) (год) IMDb N.N KP N.N`) +3. **Ужасы (`🧟♀️`, TMDB genre_id=27) — последними** + +⚠️ **Только `⭐` (U+2B50)** — как в `sync-down` (см. [[family/projects/watchlist-automation]]). +`✭` (U+272D) приоритетом **не является**. + +### Порядок секций + +1. **Главный список — первым.** Это `## Фильмы` +2. Дальше — **остальные по порядку в файле**: `## Новинки - 👍/👎`, `## Мультфильмы`, `## Аниме`, … + +⚠️ `## Новинки👎` — **не показывать** (это скрытая секция отказов). +⚠️ Секция `## Новинки` содержит `👍`/`👎`; `👎`-строки прячем, `👍` показываем. + +### Источник рейтинга + +В строках со ссылками Кинопоиска рейтинг **уже в тексте**: `IMDb 7.6 KP 8.2`. +Для строк без рейтинга (например `- [ ] Gods don't give gifts`) — сортировать как `0`, в конец группы. +Опционально: добирать через TMDB (кэш `tmdbproxy` в Lampac) — решить при реализации. + +## Открытые вопросы + +1. **Нужна ли карточка** (описание/рейтинг внутри Lampa), или достаточно списка названий с постерами? +2. **Постеры** — тянуть через TMDB-кэш Lampac или не тянуть вовсе? +3. **`🗓️` upcoming** — показывать или прятать? (сейчас по умолчанию показываем) ## Связанные -- [[personal/plans/lampac-kraken]] — базовое развёртывание (шаги 1–6 сделаны) -- [[personal/tech/lampac-deployment]] — эксплуатация Lampac -- [[family/projects/watchlist-sync]] — парсер списка, CLI, cron -- [[family/projects/watchlist-automation]] — полный flow, форматы маркеров +- [[personal/plans/lampac-kraken]] — базовое развёртывание +- [[personal/tech/lampac-deployment]] — эксплуатация, порты, питфоллы +- [[family/projects/watchlist-sync]] — парсер списка, CLI +- [[family/projects/watchlist-automation]] — форматы маркеров, cron - [[family/documents/movies-watchlist]] — источник данных diff --git a/personal/tech/lampac-deployment.md b/personal/tech/lampac-deployment.md index c28e5ff8..a224d8ed 100644 --- a/personal/tech/lampac-deployment.md +++ b/personal/tech/lampac-deployment.md @@ -147,8 +147,42 @@ Configure complete ← HTTP начинает отвечать Один сегмент `192.168.1.x` — туннели и проброс портов не нужны. Подробнее: [[family/how-to/kraken-network]]. -## Занятые порты на Кра́кене (2026-09-22) +## Модуль Catalog — каталоги из YAML +Модуль **`Catalog`** (в образе, по умолчанию **выключен**) отдаёт свои каталоги как плагин Lampa. +Разобрано по коду 2026-09-22: `/lampac/module/Catalog/`. + +| Что | Как | +|---|---| +| Данные | `sites/.yaml` — `host`, `menu`, `search`, `list`, `content` | +| Переопределения | `override/.yaml`, `override/_.yaml` | +| Роуты | `/catalog.js`, `/catalog`, `/catalog/list`, `/catalog/card` | +| WAF | `^/catalog/` → 10 req/sec | +| Примеры | 10 файлов: `vokino`, `rezka`, `kinopub`, `aniliberty`, `eneyida`, `filmix`, `filmixapp`, `getstv`, `kinobase`, `kinoukr` | + +**Обязателен HTTP:** `if (!url.StartsWith("http")) url = $"{init.host}/{url}"` — локальные файлы не читаются. + +**Два режима:** `jsonPath: true` → `JToken.Parse` (JSON), иначе HtmlAgilityPack (HTML). +Любой свой JSON-эндпоинт годится как `host` — это рычаг для watchlist-каталога. + +**Выключен в двух местах** `current.conf`: +```jsonc +"SkipModules": [ "Catalog", "Tracks", ... ] // ~строка 277 +"plugins": { "catalog": false } // ~строка 1653 +``` + +🔴 **`init.conf` НЕ смонтирован** в нашем compose — файл из образа. Правки через `docker exec` +**теряются при пересоздании контейнера**. Нужен volume `./config/init.conf:/lampac/init.conf:ro` +(или правка через AdminPanel `/adminpanel`). + +Синапс модулей (всего 33): `AdminPanel, Adult, Catalog, Community, DLNA, DatabaseEditor, ExternalBind, +ForkPlayerXML, GStreamer, JacRed, Kit, LampaWeb, LampacApk, LogUserRequest-Lite, MsxNative, Music, +NextHUB, Online, OnlineAnime, OnlineENG, OnlineGEO, OnlinePaid, OnlineRUS, OnlineUKR, PidTor, Potok, +Proxy, SISI, Sync, Telemetry, Tracks, Transcoding, WebLog`. + +Полный пример YAML (`vokino.yaml`): `docker exec lampac cat /lampac/module/Catalog/sites/vokino.yaml`. + +## Занятые порты на Кра́кене (2026-09-22) `7878` Radarr · `8096` Jellyfin · `8191` FlareSolverr · `8989` Sonarr · `9000` Portainer · `9091` Transmission · `9696` Prowlarr · `51413` Transmission (UDP) · **`9118` Lampac**