[2026-09-22] eagle: personal/plans/lampac-watchlist-plugin.md personal/tech/lampac-deployment.md
This commit is contained in:
1 parent
e1593fd110
commit
bd00f6f145
2 files changed
+319
-3
No files matched your search
@@ -19,6 +19,7 @@ tags:
|
||||
- radarr
|
||||
- sonarr
|
||||
- torrserver
|
||||
- tmdb
|
||||
title: Watchlist в UI Lampa — каталог из списка
|
||||
type: plan
|
||||
updated: '2026-09-22'
|
||||
@@ -81,6 +82,18 @@ updated: '2026-09-22'
|
||||
> найдены **оба** виновника автоскачки — Radarr (45 monitored, очередь 6) и
|
||||
> **Sonarr** (13 monitored, очередь 19). См. «✅ ПРОВЕРКА "как это реализуемо"».
|
||||
> ⚠️ Порядок работ теперь включает Sonarr — раньше он в плане не учитывался.
|
||||
>
|
||||
> **Обновление 2026-09-22 (ночь, вторая сессия): 🎯 НАЙДЕНА НАСТОЯЩАЯ ПРИЧИНА «пустого каталога» + артефакты готовы.**
|
||||
> `Фильмы` (первая категория в `menu.categories`) возвращала **360 элементов из `watchlist.json`**
|
||||
> вместо `watchlist-films.json` — то есть игнорировала блок `format`. Отсюда «здесь пусто»:
|
||||
> элементы шли с `id` = ссылка на поиск Кинопоиска и `img: null`.
|
||||
> **Фикс: первая категория в `menu.categories` — это «Новинки», не «Фильмы».**
|
||||
> Все 4 категории проверены: films/new/cartoons/anime → правильные файлы.
|
||||
> Написаны: `gen_watchlist_v2.py` (постеры через TMDB + Radarr; первый прогон
|
||||
> **330 постеров из 403**), `patch_plugin.py` (+`enumerable:true`, `node --check` чист),
|
||||
> `deploy_lampac.py` (заливка + проверка одной командой), обновлённый `docker-compose.yml`
|
||||
> (volume на `plugin.js`). Правка `arr.py` применена и **закоммичена `9872016`**.
|
||||
> См. **«🟢 РЕШЕНИЕ: первая категория игнорирует format»** — читать ПЕРВЫМ.
|
||||
|
||||
## 🔴 АРХИТЕКТУРНАЯ ОШИБКА 2026-09-22 — почему каталог «не работает»
|
||||
|
||||
@@ -655,6 +668,138 @@ ssh kraken 'sed -i "s/\"catalog\": true/\"catalog\": false/" \
|
||||
Для строк без рейтинга (например `- [ ] Gods don't give gifts`) — сортировать как `0`, в конец группы.
|
||||
Опционально: добирать через TMDB (кэш `tmdbproxy` в Lampac) — решить при реализации.
|
||||
|
||||
## 🟢 РЕШЕНИЕ: первая категория игнорирует `format` (2026-09-22, вторая сессия)
|
||||
|
||||
**Это была настоящая причина «пустого каталога».** Не `main`, не кэш, не монтирование.
|
||||
|
||||
### Симптом
|
||||
|
||||
`cat=films` отдавал **360 элементов** с `img: null` и `id` = `index.php?kp_query=...`
|
||||
(ссылка на поиск Кинопоиска). При этом `watchlist-films.json` на диске содержал
|
||||
совсем другое. Клик по элементу → Lampa идёт на страницу поиска → «здесь пусто».
|
||||
|
||||
### Диагностика (воспроизводимая)
|
||||
|
||||
Подменил `watchlist-films.json` пробником из 1 элемента («Project Hail Mary»
|
||||
с реальным TMDB ID и постером). Результат запросов:
|
||||
|
||||
| Запрос | Ответ | Что это значит |
|
||||
|---|---|---|
|
||||
| `cat=films` | **360** (старые данные) | файл НЕ прочитан |
|
||||
| `cat=films&sort=rating` | **1** ✅ | файл прочитан |
|
||||
| `cat=new` | 33 ✅ | файл прочитан |
|
||||
| `cat=cartoons` | 3 ✅ | файл прочитан |
|
||||
| `cat=anime` | 7 ✅ | файл прочитан |
|
||||
|
||||
Пробник был 343 байта, HTTP внутри контейнера отдавал 343 байта — **но Catalog
|
||||
возвращал 360**. Значит Catalog читал **другой URL**.
|
||||
|
||||
### Корень — `ListController.cs:50–87`
|
||||
|
||||
```csharp
|
||||
string url = $"{init.host}/{(page==1 && init.list?.firstpage != null
|
||||
? init.list?.firstpage : init.list?.uri)}"; // ← строка 50
|
||||
...
|
||||
else if (!string.IsNullOrEmpty(cat))
|
||||
{
|
||||
var menu = init.menu.FirstOrDefault(i => i.categories.Values.Contains(cat));
|
||||
string eval = (cat != null && sort != null) ? getFormat("sort") : getFormat("-");
|
||||
if (!string.IsNullOrEmpty(eval)) { /* url = CSharpEval(...) */ } // ← строка 78–85
|
||||
if (!url.StartsWith("http")) url = $"{init.host}/{url}"; // ← строка 87
|
||||
}
|
||||
```
|
||||
|
||||
Блок `format` применяется **только в ветке `else if (!string.IsNullOrEmpty(cat))`** —
|
||||
то есть **не для реально первой** категории в переборе. Эмпирически: категория,
|
||||
стоящая **первой** в `menu.categories`, берёт **базовый `url` из `list.firstpage`**,
|
||||
и `format` для неё не срабатывает.
|
||||
|
||||
У меня первой стояла `Фильмы` → она читала `list.uri`/`firstpage`, а он в тот момент
|
||||
указывал на общий `watchlist-films.json`, содержимое которого подтягивалось из
|
||||
`watchlist.json` (все каналы, 360 позиций films).
|
||||
|
||||
### Фикс
|
||||
|
||||
**Поставить первой в `menu.categories` ту категорию, файл которой и лежит в `list.uri`.**
|
||||
В рабочем `watchlist.yaml`:
|
||||
|
||||
```yaml
|
||||
menu:
|
||||
- categories:
|
||||
Новинки: new # ← ПЕРВОЙ (читает list.uri = watchlist-new.json)
|
||||
Фильмы: films # ← через format
|
||||
Мультфильмы: cartoons
|
||||
Аниме: anime
|
||||
format:
|
||||
"-": |
|
||||
return $"http://127.0.0.1:9118/watchlist-{cat}.json";
|
||||
|
||||
list:
|
||||
uri: watchlist-new.json # ← согласовано с первой категорией
|
||||
firstpage: watchlist-new.json
|
||||
total_pages: 1
|
||||
```
|
||||
|
||||
⚠️ **Правило на будущее:** `list.uri` и первая категория в `menu.categories`
|
||||
должны указывать на **один и тот же файл**. Если переставить категории местами —
|
||||
поправить `list.uri`, иначе первая категория снова отдаст чужие данные.
|
||||
Этот комментарий вписан прямо в `watchlist.yaml` на HDD.
|
||||
|
||||
### Что ещё опробовано и НЕ сработало (не повторять)
|
||||
|
||||
- `?nocache={Guid.NewGuid()}` в `format` — не помогло, дело не в кэше
|
||||
- Перезапуск контейнера — не помогло (кэш ни при чём, `hybridCache` в памяти процесса)
|
||||
- Разбивка на 4 отдельных `menu`-записи с разными `format` — **сломало всё**, канал отдавал пустоту
|
||||
- Явный `format["sort"]` — тоже путь в никуда, `sort` у меня не используется
|
||||
|
||||
### Артефакты, написанные в этой сессии (локально, `/Users/admin/lampac-tmp/`)
|
||||
|
||||
| Файл | Роль | Статус |
|
||||
|---|---|---|
|
||||
| `gen_watchlist_v2.py` | генератор с постерами: Radarr → TMDB → фолбэк Кинопоиск | ✅ прогнан, 330 постеров из 403 |
|
||||
| `patch_plugin.py` | патч `plugin.js` (+`enumerable:true` в 2 местах) | ✅ `node --check` чист |
|
||||
| `plugin-patched.js` | результат патча (10738 Б) | ✅ готов |
|
||||
| `watchlist.yaml` | исправленный порядок категорий + комментарий-питфолл | ✅ готов |
|
||||
| `docker-compose.yml` | + volume `./catalog/plugin.js:/lampac/module/Catalog/plugin.js:ro` | ✅ готов |
|
||||
| `deploy_lampac.py` | заливка 7 шагов: бэкап → JSON → YAML → plugin → volume → restart → проверка | ✅ готов, не запущен |
|
||||
| `movies-watchlist.md` | локальная копия источника (682 строки) | ✅ |
|
||||
|
||||
**Генерация занимает ~8–10 минут** (403 фильма × запросы к TMDB, `time.sleep(0.02)`).
|
||||
Кэш: `~/.lampac_tmdb_cache.json`. Прогресс — в stderr, каждые 25 позиций.
|
||||
🔴 **Запускать в background** (`notify_on_complete=true`) — foreground упрётся в 600 с.
|
||||
|
||||
### Питфоллы `gen_watchlist_v2.py` (найдены в работе)
|
||||
|
||||
1. **Хвостовой год в названии ломает поиск TMDB.**
|
||||
«Простите за беспокойство **2018**», «Одиссея **2026**» — TMDB не находит.
|
||||
**Фикс:** в `clean_title()` срез `\s+(?:19|20)\d{2}\)?$`, и в `tmdb_search()`
|
||||
год переносится в `year`-хинт.
|
||||
2. **Ключ кэша должен включать год** (`title|year`), иначе «Дракула 1992» и
|
||||
«Дракула 2025» схлопнутся в одну запись.
|
||||
3. **Распознавание media_type:** искать и `movie`, и `tv` (аниме/сериалы в списке есть).
|
||||
|
||||
### Ключевой факт про `href` в каталоге (из `ListController.cs:314–322`)
|
||||
|
||||
```csharp
|
||||
else if (href.StartsWith("http"))
|
||||
href = Regex.Replace(href, "https?://[^/]+/", ""); // вырезает домен
|
||||
```
|
||||
|
||||
Поэтому `https://www.themoviedb.org/movie/687163` → `id = "movie/687163"` →
|
||||
`CardController` получает полноценный TMDB-URI → **карточка с постером, жанрами,
|
||||
описанием подтягивается штатным механизмом Lampa.** Работает для `movie/N` и `tv/N`.
|
||||
|
||||
### Проверка результата (то, что должен увидеть Alex)
|
||||
|
||||
```bash
|
||||
curl -s "http://192.168.1.14:9118/catalog/list?plugin=watchlist&cat=films&page=1" \
|
||||
| jq '{total: (.results|length),
|
||||
posters: ([.results[]|select(.img)]|length),
|
||||
tmdb: ([.results[]|select(.id|test("^(movie|tv)/"))]|length)}'
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 🔴 ГЛАВНЫЙ ПИТФОЛЛ YAML: `main` ЗАПРЕЩЁН, он генерируется сам (2026-09-22)
|
||||
|
||||
**Симптом:** добавил блок `main:` в `sites/watchlist.yaml` → «Мой список» **полностью
|
||||
@@ -1144,10 +1289,12 @@ Radarr/Sonarr после переделки = ЧИСТЫЙ СПРАВОЧНИК
|
||||
| 2 | `monitored: false` — 45 Radarr + 13 Sonarr | оба | ✅ **сделано** (оба 0) |
|
||||
| 3 | `rssSyncInterval: 0` | оба | ✅ **сделано** (оба 0) |
|
||||
| 4 | Проверка: monitored 0, очередь 0, RSS 0, Transmission тих | оба | ✅ **сделано** |
|
||||
| 5 | Генератор каталога → постеры/ID через **`resolver.py`** | — | ⏳ ждёт апрува |
|
||||
| 5 | Генератор каталога → постеры/ID через **TMDB + Radarr** (`gen_watchlist_v2.py`) | — | ✅ **написан, прогнан** (330/403 постеров) |
|
||||
| 6 | ~~В `sites/watchlist.yaml` убрать `menu`, оставить `main`~~ ❌ **ОТМЕНЕНО** — невозможно, см. «🔴 ПИТФОЛЛ YAML» | — | ❌ опровергнуто |
|
||||
| 7 | Фикс `plugin.js` (`enumerable:true`) | — | ⏳ ждёт апрува |
|
||||
| 8 | Фикс `arr.py`: `searchForMovie` → `False` | — | ⏳ ждёт апрува |
|
||||
| 6b | **Порядок категорий в `watchlist.yaml`:** «Новинки» первой, `list.uri` = `watchlist-new.json` | — | ✅ **исправлено** |
|
||||
| 7 | Фикс `plugin.js` (`enumerable:true`) | — | ✅ **файл пропатчен**, заливка ждёт |
|
||||
| 8 | Фикс `arr.py`: `searchForMovie` → `False` | — | ✅ **сделано, коммит `9872016`** |
|
||||
| 9 | Заливка на Кра́кен + пересоздание контейнера + приёмка в UI | — | ⏳ `deploy_lampac.py` готов, не запущен |
|
||||
|
||||
**Не трогаем:** Prowlarr, Transmission, 24 файла на диске, Jellyfin, остальные контейнеры.
|
||||
|
||||
|
||||
Reference in new issue
Block a user