[2026-09-22] eagle: personal/plans/lampac-watchlist-plugin.md personal/tech/lampac-deployment.md
This commit is contained in:
1 parent
6f63bc8810
commit
c4932a84f4
2 files changed
+178
-3
No files matched your search
@@ -7,7 +7,7 @@ related:
|
|||||||
- '[[family/projects/watchlist-sync]]'
|
- '[[family/projects/watchlist-sync]]'
|
||||||
- '[[family/projects/watchlist-automation]]'
|
- '[[family/projects/watchlist-automation]]'
|
||||||
- '[[family/documents/movies-watchlist]]'
|
- '[[family/documents/movies-watchlist]]'
|
||||||
status: card-done-tv-check-pending
|
status: card-fixed-tv-check-pending
|
||||||
tags:
|
tags:
|
||||||
- lampac
|
- lampac
|
||||||
- lampa
|
- lampa
|
||||||
@@ -40,10 +40,16 @@ updated: '2026-09-22'
|
|||||||
> См. «🔴 АРХИТЕКТУРНАЯ ОШИБКА» — читать ПЕРВЫМ.
|
> См. «🔴 АРХИТЕКТУРНАЯ ОШИБКА» — читать ПЕРВЫМ.
|
||||||
>
|
>
|
||||||
> **Итог одной строкой:** серверная часть каталога работает полностью — «Мой список»
|
> **Итог одной строкой:** серверная часть каталога работает полностью — «Мой список»
|
||||||
> первым в `/catalog`, 4 категории (403 позиции, 348 постеров, 352 рабочих карточки),
|
> первым в `/catalog`, 4 категории (403 позиции, 348 постеров), **карточка по клику
|
||||||
> карточка по клику отдаёт **HTTP 200** (339/339). Родной CUB не тронут.
|
> отдаёт все поля: 352/352 с числовым `tmdb_id`**. Родной CUB не тронут.
|
||||||
> Осталась приёмка глазами на ТВ.
|
> Осталась приёмка глазами на ТВ.
|
||||||
>
|
>
|
||||||
|
> **Обновление 2026-09-22 (третья сессия): ✅ КАРТОЧКА ПОЧИНЕНА ОКОНЧАТЕЛЬНО.**
|
||||||
|
> «Здесь пусто» давало отсутствие **числового** `tmdb_id`: `plugin.js` делает
|
||||||
|
> `if(json.tmdb_id)`, а `ModInit.cs:285` возвращает любое `JValue` СТРОКОЙ.
|
||||||
|
> Фикс — `format: "long.TryParse(...)"` в `card_args`. Плюс кэш `catalog:card:*`
|
||||||
|
> в ПАМЯТИ переживал `docker restart` и отдавал старое. См. «🔴 ФИНАЛЬНЫЙ ФИКС».
|
||||||
|
>
|
||||||
> **Обновление 2026-09-22 (вечер):** Alex лично нашёл источник в UI
|
> **Обновление 2026-09-22 (вечер):** Alex лично нашёл источник в UI
|
||||||
> («остальное → основной источник → Мой список»), увидел результат и подтвердил
|
> («остальное → основной источник → Мой список»), увидел результат и подтвердил
|
||||||
> диагноз: секции подменяют CUB, нет превью, элементы — сырые строки файла.
|
> диагноз: секции подменяют CUB, нет превью, элементы — сырые строки файла.
|
||||||
@@ -1807,4 +1813,99 @@ Cron: генератор в **02:30**, после `watchlist-nightly` (01:00).
|
|||||||
310 фильмов из списка, которых нет в Radarr — пока показываются через фолбэк
|
310 фильмов из списка, которых нет в Radarr — пока показываются через фолбэк
|
||||||
Кинопоиска (51 без постера). Решить судьбу отдельно.
|
Кинопоиска (51 без постера). Решить судьбу отдельно.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔴 ФИНАЛЬНЫЙ ФИКС: карточка = «здесь пусто» без ЧИСЛОВОГО `tmdb_id`
|
||||||
|
|
||||||
|
**2026-09-22, третья сессия. Карточка заработала: 352/352 отдают `tmdb_id`.**
|
||||||
|
|
||||||
|
Alex после первого «готово»: «при открытии все так же "здесь пусто" и никакого инфо
|
||||||
|
или воспроизведения». Сервер отдавал `HTTP 200` с title/img/overview — значит
|
||||||
|
дело было **не в запросе, а в полноте ответа**.
|
||||||
|
|
||||||
|
### Причина — одна, но скрытая за двумя масками
|
||||||
|
|
||||||
|
`plugin.js` при клике (`full()`):
|
||||||
|
|
||||||
|
```js
|
||||||
|
if(json.tmdb_id){ status.need++;
|
||||||
|
Lampa.Api.sources.cub.reactionsGet(
|
||||||
|
{id: json.tmdb_id, method: json.original_name ? 'tv' : 'movie'}, ...); }
|
||||||
|
```
|
||||||
|
|
||||||
|
**Без `tmdb_id` Lampa считает карточку неполной → пустой экран.** Причём нужен
|
||||||
|
**числовой** `tmdb_id`, не строка.
|
||||||
|
|
||||||
|
Два бага в цепочке `card_args`:
|
||||||
|
|
||||||
|
1. **`ModInit.cs:285` — `nodeValue` возвращает ЛЮБОЕ `JValue` как строку.**
|
||||||
|
```csharp
|
||||||
|
string value = valueToken switch {
|
||||||
|
JValue jValue => jValue.Value?.ToString(), // ← число 424781 → "424781"
|
||||||
|
... };
|
||||||
|
```
|
||||||
|
Поэтому `tmdb_id` из JSON-файла приходил строкой, и `if(json.tmdb_id)` не
|
||||||
|
давала числа. **Никакой конфиг это не обходит — только `format`.**
|
||||||
|
|
||||||
|
2. **Кэш `catalog:card:{plugin}:{uri}` живёт в ПАМЯТИ процесса и переживает
|
||||||
|
`docker restart`.** После правки данных старые ответы продолжали отдаваться.
|
||||||
|
Именно поэтому `movie/424781` (**первый элемент «Фильмов»**, по нему Alex и
|
||||||
|
кликал) упорно оставался `null`, хотя исправленный файл уже лежал на диске.
|
||||||
|
**Проверять фикс только на НЕзакэшированном `uri`.**
|
||||||
|
|
||||||
|
### Фикс — `format` в `card_args` (исполняется как C#, возвращает настоящий тип)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
card_args:
|
||||||
|
- name_arg: tmdb_id
|
||||||
|
attribute: tmdb_id
|
||||||
|
format: "long.TryParse(value, out long v) ? v : 0"
|
||||||
|
- name_arg: source
|
||||||
|
attribute: media_type
|
||||||
|
- name_arg: overview
|
||||||
|
attribute: overview
|
||||||
|
- name_arg: genres
|
||||||
|
attribute: genres
|
||||||
|
- name_arg: runtime
|
||||||
|
attribute: runtime
|
||||||
|
format: "long.TryParse(value, out long v) ? v : 0"
|
||||||
|
- name_arg: vote_average
|
||||||
|
attribute: vote_average
|
||||||
|
format: "double.TryParse(value, out double v) ? v : 0"
|
||||||
|
- name_arg: rating
|
||||||
|
attribute: rating # остаётся строкой — Lampa показывает в бейдже
|
||||||
|
```
|
||||||
|
|
||||||
|
`format` вызывается как `CSharpEval.Execute<object>(nd.format,
|
||||||
|
new CatalogNodeValue(value, host), options)` (`ModInit.cs:255` и `:317`) —
|
||||||
|
`value` это уже строка, поэтому нужен `TryParse`.
|
||||||
|
|
||||||
|
### Эталонный рабочий ответ
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "id": "movie/424781", "title": "Простите за беспокойство",
|
||||||
|
"original_title": "Простите за беспокойство", "tmdb_id": 424781,
|
||||||
|
"source": "movie", "runtime": 111, "rating": "6.8", "vote_average": 68,
|
||||||
|
"genres": [{"name":"фэнтези"},{"name":"фантастика"},{"name":"комедия"}],
|
||||||
|
"overview": "...", "img": "http://192.168.1.14:9118/proxyimg:210:0/..." }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Итог проверки
|
||||||
|
|
||||||
|
**352 из 352** карточек (все, у кого есть TMDB ID) отдают числовой `tmdb_id`,
|
||||||
|
`source`, `runtime`, рейтинг и жанры. Ошибок — 0.
|
||||||
|
|
||||||
|
### 🔴 CUB: «вижу только фильмы из списка»
|
||||||
|
|
||||||
|
CUB **не пропал** — это **два независимых источника Lampa**, одновременно
|
||||||
|
показать нельзя. Переключение: **Настройки → Остальное → Основной источник**.
|
||||||
|
Пункта «Источник» в настройках НЕ существует.
|
||||||
|
|
||||||
|
### Питфолл приёмки на ТВ
|
||||||
|
|
||||||
|
Lampa на ТВ **кэширует манифест и ответы**. После правок надо **полностью
|
||||||
|
выгрузить приложение** (не свернуть), иначе клиент держит старый кэш и
|
||||||
|
показывает дореформенный результат.
|
||||||
|
|
||||||
|
|
||||||
## Связанные
|
## Связанные
|
||||||
@@ -1371,3 +1371,77 @@ python3 deploy_lampac.py /tmp/wl-out --skip-plugin
|
|||||||
вызовом (`&&`-цепочка рвёт tty).
|
вызовом (`&&`-цепочка рвёт tty).
|
||||||
|
|
||||||
### Связанные
|
### Связанные
|
||||||
|
|
||||||
|
## 🔴 ПОЧЕМУ КАРТОЧКА = «ЗДЕСЬ ПУСТО» (найдено 2026-09-22, вечер)
|
||||||
|
|
||||||
|
**Симптом:** данные в карточку приходят (title, img, overview), но в UI «здесь пусто»,
|
||||||
|
нет кнопки воспроизведения.
|
||||||
|
|
||||||
|
**Причина:** `plugin.js` при клике:
|
||||||
|
|
||||||
|
```js
|
||||||
|
if(json.tmdb_id){ status.need++; Lampa.Api.sources.cub.reactionsGet(
|
||||||
|
{id: json.tmdb_id, method: json.original_name ? 'tv' : 'movie'}, ...); }
|
||||||
|
```
|
||||||
|
|
||||||
|
Без `tmdb_id` (**числа**, не строки!) Lampa считает карточку неполной → пустой экран.
|
||||||
|
|
||||||
|
### Два бага в цепочке, оба надо было починить
|
||||||
|
|
||||||
|
1. **`ModInit.cs:285` — `nodeValue` возвращает ЛЮБОЕ значение как строку.**
|
||||||
|
```csharp
|
||||||
|
string value = valueToken switch {
|
||||||
|
JValue jValue => jValue.Value?.ToString(), // ← число → "424781"
|
||||||
|
... };
|
||||||
|
```
|
||||||
|
Поэтому `tmdb_id` из JSON приходил строкой, и `if(json.tmdb_id)` давала не число.
|
||||||
|
|
||||||
|
2. **Кэш в памяти процесса переживает `docker restart`.**
|
||||||
|
`hybridCache` ключ `catalog:card:{plugin}:{uri}` живёт в памяти. При правке
|
||||||
|
данных старые ответы продолжают отдаваться. **Обязательно `docker restart lampac`
|
||||||
|
и проверять на НЕзакэшированном uri.**
|
||||||
|
|
||||||
|
### Фикс — `format` в `card_args`
|
||||||
|
|
||||||
|
`format` исполняется как C# (`CSharpEval`, объект `CatalogNodeValue(value, host)`)
|
||||||
|
и может вернуть настоящий тип, а не строку:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
card_args:
|
||||||
|
- name_arg: tmdb_id
|
||||||
|
attribute: tmdb_id
|
||||||
|
format: "long.TryParse(value, out long v) ? v : 0"
|
||||||
|
- name_arg: source
|
||||||
|
attribute: media_type
|
||||||
|
- name_arg: runtime
|
||||||
|
attribute: runtime
|
||||||
|
format: "long.TryParse(value, out long v) ? v : 0"
|
||||||
|
- name_arg: vote_average
|
||||||
|
attribute: vote_average
|
||||||
|
format: "double.TryParse(value, out double v) ? v : 0"
|
||||||
|
- name_arg: rating
|
||||||
|
attribute: rating # строкой — Lampa показывает в бейдже
|
||||||
|
```
|
||||||
|
|
||||||
|
### Рабочий ответ карточки (эталон)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "id": "movie/424781", "title": "Простите за беспокойство",
|
||||||
|
"original_title": "Простите за беспокойство", "tmdb_id": 424781,
|
||||||
|
"source": "movie", "runtime": 111, "rating": "6.8", "vote_average": 68,
|
||||||
|
"genres": [{"name":"фэнтези"},{"name":"фантастика"},{"name":"комедия"}],
|
||||||
|
"overview": "...", "img": "http://192.168.1.14:9118/proxyimg:210:0/..." }
|
||||||
|
```
|
||||||
|
|
||||||
|
**Результат: 352 из 352 карточек отдают числовой `tmdb_id`.**
|
||||||
|
|
||||||
|
### Про `CUB` — почему «только фильмы из списка»
|
||||||
|
|
||||||
|
CUB и «Мой список» — **два независимых источника Lampa**, одновременно показать
|
||||||
|
нельзя. Переключение: **Настройки → Остальное → Основной источник**.
|
||||||
|
Пункта «Источник» в настройках НЕ существует.
|
||||||
|
|
||||||
|
### Питфолл проверки на ТВ
|
||||||
|
|
||||||
|
Lampa на ТВ кэширует манифест и ответы. После правок **надо полностью
|
||||||
|
выгрузить приложение** (не свернуть), иначе клиент держит старый кэш.
|
||||||
Reference in new issue
Block a user