[2026-09-22] eagle: family/projects/watchlist-automation.md personal/plans/lampac-watchlist-plugin.md personal/tech/lampac-deployment.md
This commit is contained in:
1 parent
128152fc6e
commit
1aeb42f4b8
3 files changed
+472
-20
No files matched your search
@@ -17,6 +17,8 @@ tags:
|
||||
- plugin
|
||||
- kraken
|
||||
- radarr
|
||||
- sonarr
|
||||
- torrserver
|
||||
title: Watchlist в UI Lampa — каталог из списка
|
||||
type: plan
|
||||
updated: '2026-09-22'
|
||||
@@ -46,6 +48,15 @@ updated: '2026-09-22'
|
||||
> просмотр через TorrServer, файлы на HDD не пишутся) → записано в **«ПЕРЕДЕЛКА 2»**.
|
||||
> План работ на апруве, **ничего не выполнено**.
|
||||
>
|
||||
> **Обновление 2026-09-22 (поздний вечер): ✅ ШАГИ 0–4 ПЕРЕДЕЛКИ 2 ВЫПОЛНЕНЫ.**
|
||||
> Автоскачка на HDD **выключена фактически**: Radarr (45→**0** monitored, очередь 6→**0**,
|
||||
> RSS 30→**0**) и Sonarr (13→**0**, 19→**0**, 15→**0**). Метаданные целы — 50 фильмов,
|
||||
> **46 с постерами**, 24 файла на диске не тронуты. Проверено: Transmission не сдвинулся
|
||||
> ни на байт за 45 с, логи Radarr пусты. Бэкапы `radarr.db`/`sonarr.db`/`config.xml` — метка
|
||||
> `20260922-123404`. Осталось 4 правки (шаги 5–8): постеры через `resolver.py`, убрать
|
||||
> `menu` из YAML, фикс `plugin.js`, фикс `arr.py`. См. «✅ Порядок работ» и
|
||||
> «🔴 Питфоллы выполнения». **Всё на апруве, ничего сверх не трогалось.**
|
||||
>
|
||||
> **Аудит «как это реализуемо» — ✅ ЗАВЕРШЁН 2026-09-22.** Проверено всё:
|
||||
> TorrServer **на диск не пишет** (`UseDisk: false`, RAM-кэш 96 МБ) — главный вопрос закрыт;
|
||||
> поиск торрентов работает через **Jackett-API самого Lampac** (отдельный Jackett не нужен);
|
||||
@@ -642,6 +653,134 @@ ssh kraken 'sed -i "s/\"catalog\": true/\"catalog\": false/" \
|
||||
Для строк без рейтинга (например `- [ ] Gods don't give gifts`) — сортировать как `0`, в конец группы.
|
||||
Опционально: добирать через TMDB (кэш `tmdbproxy` в Lampac) — решить при реализации.
|
||||
|
||||
## ✅ РЕШЕНИЕ НАЙДЕНО 2026-09-22 — полная архитектура (проверено)
|
||||
|
||||
### Что уже есть в системе (нашёл, проверено)
|
||||
|
||||
**Модуль `watchlist_sync/resolver.py`** (`/srv/.../watchlist-sync/`) — **уже решает задачу
|
||||
постеров и ID.** Умеет:
|
||||
- поиск через **TMDB** (`api.themoviedb.org/3`) в `ru-RU` и `en-US`
|
||||
- поиск через **Кинопоиск** (`api.poiskkino.dev/v1.4`)
|
||||
- возвращает `Candidate`: `tmdb_id`, `kp_id`, `title`, `year`, `score`, `rating`, **`genres`**
|
||||
- `is_horror()` — определяет ужасы по TMDB `genre_id=27` (для сортировки 🧟♀️)
|
||||
- кэш в `.resolve_cache.json`
|
||||
- различает `ok` / `ambiguous` (score < 0.75) / `not_found`
|
||||
|
||||
**Модуль `watchlist_sync/arr.py`** — клиент Radarr/Sonarr. 🔴 **ВОТ ИСТОЧНИК СКАЧКИ:**
|
||||
```python
|
||||
"monitored": True,
|
||||
"addOptions": {"searchForMovie": True}, # ← качает сразу после добавления
|
||||
```
|
||||
Для сериалов: `"addOptions": {"searchForMissingEpisodes": True}` — то же самое.
|
||||
|
||||
### Ключевая связка ID
|
||||
|
||||
| База | Где есть | Формат |
|
||||
|---|---|---|
|
||||
| **Кинопоиск (kp)** | в `.md`: 68 строк со ссылками `kinopoisk.ru/film/<id>/` | `11825624` |
|
||||
| **TMDB** | в Radarr (`tmdbId`), в resolver (`Candidate.tmdb_id`) | `1292695` |
|
||||
| **IMDb** | в Radarr (`imdbId`), в `.md` только рейтинг | `tt31728330` |
|
||||
|
||||
⚠️ **Прямой связи kp↔tmdb в файле нет.** Связка делается через **`resolver.py`**: он по
|
||||
названию находит и `kp_id`, и `tmdb_id` одновременно. Это его основная работа.
|
||||
|
||||
### Замер Radarr (после шагов 1–3, 2026-09-22)
|
||||
|
||||
| Метрика | Значение |
|
||||
|---|---|
|
||||
| Фильмов | **50** |
|
||||
| `monitored` | **0** ← автоскачка выключена |
|
||||
| `rssSyncInterval` | **0** ← в RSS не ходит |
|
||||
| Очередь | **0** |
|
||||
| С `tmdbId` | 50 (все) |
|
||||
| С постером | **46** |
|
||||
| С рейтингом TMDB | 50 (все) |
|
||||
| С файлом на диске | 24 (не трогали) |
|
||||
|
||||
Sonarr: 13 сериалов, `monitored` 0, RSS 0, очередь 0.
|
||||
|
||||
### Поля Radarr для каталога (проверено, `GET /api/v3/movie`)
|
||||
|
||||
```json
|
||||
{
|
||||
"tmdbId": 1292695,
|
||||
"imdbId": "tt31728330",
|
||||
"title": "They Will Kill You",
|
||||
"originalTitle": "They Will Kill You",
|
||||
"year": 2026,
|
||||
"titleSlug": "1292695",
|
||||
"hasFile": true,
|
||||
"genres": ["Horror"],
|
||||
"ratings": {"tmdb": {"value": 6.945}},
|
||||
"images": [{"coverType": "poster",
|
||||
"remoteUrl": "https://image.tmdb.org/t/p/original/6oI4oQKTWMVUlr8Ivqydp28Ruu6.jpg"}]
|
||||
}
|
||||
```
|
||||
|
||||
**Названия в Radarr — латиницей** (`They Will Kill You`), в `.md` — по-русски. Перевод
|
||||
делает **TMDB Proxy** (`proxy_tmdb = true` в `lampainit.js`) — уже включён.
|
||||
|
||||
### КАК ИГРАЕТ LAMPA (проверено — на диск НЕ пишется)
|
||||
|
||||
| Компонент | Значение | Смысл |
|
||||
|---|---|---|
|
||||
| TorrServer | `/ts/echo` → `MatriX.135` | жив, встроен в Lampac |
|
||||
| **`UseDisk`** | **`false`** | 🔴 **на диск НЕ пишет** |
|
||||
| `CacheSize` | 100663296 (96 МБ) | кэш в RAM |
|
||||
| `TorrentsSavePath` | `""` (пусто) | пути сохранения нет |
|
||||
| `TorrentDisconnectTimeout` | 180 | раздача живёт 3 мин после стопа |
|
||||
| Занятые торренты | `[]` (пусто) | ничего не висит |
|
||||
|
||||
**Поиск торрентов:** Lampa → `jackett_url = 192.168.1.14:9118` → **Lampac сам отдаёт
|
||||
Jackett-совместимый API**:
|
||||
```bash
|
||||
curl "http://192.168.1.14:9118/api/v2.0/indexers/all/results?apikey=1&Query=matrix"
|
||||
# → {"Results":[{"Tracker":"rutor","Title":"...","MagnetUri":"magnet:?xt=...","Seeders":0}]}
|
||||
```
|
||||
✅ Проверено: вернул реальные результаты. Отдельный Jackett **не нужен** (его нет в системе).
|
||||
|
||||
🔴 **`parser_torrent_type = 'jackett'`** в `lampainit.js` — это НЕ отдельный Jackett,
|
||||
а эндпоинт внутри Lampac. Так и задумано производителем.
|
||||
|
||||
### Итоговая архитектура (то, что нужно поставить)
|
||||
|
||||
```
|
||||
family/documents/movies-watchlist.md ← источник (360 фильмов)
|
||||
│
|
||||
├─► resolver.py ──► TMDB + Кинопоиск
|
||||
│ │ tmdb_id + постер + рейтинг + жанры
|
||||
│ ▼
|
||||
│ wwwroot/watchlist-<cat>.json ← каталог ДЛЯ LAMPA (с постерами!)
|
||||
│ │
|
||||
│ ▼
|
||||
│ sites/watchlist.yaml (main: только секции СВЕРХУ, БЕЗ menu)
|
||||
│ │
|
||||
│ ▼
|
||||
│ Lampa: плагин catalog.js → секции с постерами СВЕРХУ родного CUB
|
||||
│
|
||||
└─► arr.py (searchForMovie: False) ──► Radarr/Sonarr
|
||||
└─► метаданные в базу БЕЗ скачки
|
||||
|
||||
Просмотр: Lampa → TorrServer (RAM, UseDisk:false) → на HDD ничего
|
||||
```
|
||||
|
||||
**Разделение ролей:**
|
||||
- **resolver.py** — постеры/ID для **каталога** (360 фильмов, включая те, что не в Radarr)
|
||||
- **Radarr** — справочник того, что уже добавлено (50), источник `hasFile`
|
||||
- **TorrServer** — воспроизведение, на диск не пишет
|
||||
|
||||
### Три правки (на апруве)
|
||||
|
||||
| # | Файл | Правка | Зачем |
|
||||
|---|---|---|---|
|
||||
| 1 | `watchlist_sync/arr.py` | `searchForMovie: True` → **`False`** (+ у дочки то же для сериалов) | добавление без скачки |
|
||||
| 2 | `catalog/sites/watchlist.yaml` | убрать блок `menu`, оставить `main` | родной CUB не подменяется |
|
||||
| 3 | генератор каталога | брать постер/ID через `resolver` | реальные элементы вместо заглушек |
|
||||
|
||||
⚠️ Правка №1 **может уже не понадобиться**: шаги 1–3 (unmonitor + RSS 0) закрыли скачку
|
||||
на уровне состояния. Но `searchForMovie: True` в коде **включит её снова** при следующем
|
||||
добавлении из списка. Поэтому фикс нужен — иначе вернётся.
|
||||
|
||||
## 🎯 ПЕРЕДЕЛКА 2 — Radarr как источник метаданных без автоскачки (план Alex, 2026-09-22)
|
||||
|
||||
### Логика Alex (дословно)
|
||||
@@ -875,29 +1014,111 @@ Radarr/Sonarr после переделки = ЧИСТЫЙ СПРАВОЧНИК
|
||||
(monitored: false + rssSyncInterval: 0) — не ищут, не качают
|
||||
```
|
||||
|
||||
### ⚠️ Порядок работ (обновлён с учётом Sonarr)
|
||||
### ✅ Порядок работ — ШАГИ 0–3 ВЫПОЛНЕНЫ 2026-09-22
|
||||
|
||||
| # | Действие | Сервис | Статус |
|
||||
|---|---|---|---|
|
||||
| 0 | Бэкап `radarr.db` + `config.xml` (+ то же для Sonarr) | оба | ⏳ |
|
||||
| 1 | Отменить очередь: 6 записей Radarr + **19 Sonarr** | оба | ⏳ |
|
||||
| 2 | `monitored: false` — 45 Radarr + **13 Sonarr** | оба | ⏳ |
|
||||
| 3 | `rssSyncInterval: 0` | оба | ⏳ |
|
||||
| 4 | Проверка: monitored 0, очередь 0, RSS 0, Transmission тих | оба | ⏳ |
|
||||
| 5 | Генератор каталога → данные из **Radarr API** (TMDB ID + постер) | — | ⏳ |
|
||||
| 6 | В `sites/watchlist.yaml` убрать `menu`, оставить `main` | — | ⏳ |
|
||||
| 7 | Фикс `plugin.js` (`enumerable:true`) | — | ⏳ |
|
||||
| 8 | Добавление 310 фильмов из `.md` в Radarr с `monitored: false` | Radarr | ⏳ |
|
||||
| 0 | Бэкап `radarr.db` + `config.xml` + `sonarr.db` + `config.xml` | оба | ✅ **сделано** |
|
||||
| 1 | Отменить очередь: 6 Radarr + 19 Sonarr | оба | ✅ **сделано** (оба 0) |
|
||||
| 2 | `monitored: false` — 45 Radarr + 13 Sonarr | оба | ✅ **сделано** (оба 0) |
|
||||
| 3 | `rssSyncInterval: 0` | оба | ✅ **сделано** (оба 0) |
|
||||
| 4 | Проверка: monitored 0, очередь 0, RSS 0, Transmission тих | оба | ✅ **сделано** |
|
||||
| 5 | Генератор каталога → постеры/ID через **`resolver.py`** | — | ⏳ ждёт апрува |
|
||||
| 6 | В `sites/watchlist.yaml` убрать `menu`, оставить `main` | — | ⏳ ждёт апрува |
|
||||
| 7 | Фикс `plugin.js` (`enumerable:true`) | — | ⏳ ждёт апрува |
|
||||
| 8 | Фикс `arr.py`: `searchForMovie` → `False` | — | ⏳ ждёт апрува |
|
||||
|
||||
**Не трогаем:** Prowlarr, Transmission, 24 файла на диске, Jellyfin, остальные контейнеры.
|
||||
|
||||
### ❓ Открытый вопрос к Alex
|
||||
### 📋 Как выполнены шаги 1–3 (скрипты и команды — воспроизводимо)
|
||||
|
||||
Radarr/Sonarr нужны **как справочник** (тогда постеры сохраняются) или
|
||||
**выключаются совсем** (тогда каталог Lampa теряет постеры — их брать неоткуда)?
|
||||
Ответа нет.
|
||||
**Шаг 0 — бэкапы (метка `20260922-123404`)**
|
||||
```bash
|
||||
D=/srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/docker
|
||||
TS=$(date +%Y%m%d-%H%M%S)
|
||||
sudo cp $D/radarr/config/radarr.db $D/radarr/config/radarr.db.bak-$TS
|
||||
sudo cp $D/radarr/config/config.xml $D/radarr/config/config.xml.bak-$TS
|
||||
sudo cp $D/sonarr/config/sonarr.db $D/sonarr/config/sonarr.db.bak-$TS
|
||||
sudo cp $D/sonarr/config/config.xml $D/sonarr/config/config.xml.bak-$TS
|
||||
```
|
||||
Результат: `radarr.db` 4 374 528 Б, `sonarr.db` 4 870 144 Б + оба `config.xml` 650/648 Б.
|
||||
|
||||
### План работ (на апруве Alex)
|
||||
**Шаг 1 — очистка очереди.** Скрипт `/tmp/arr_clear_queue.py` (на Mac → `scp` → запуск на Кра́кене).
|
||||
`DELETE /api/v3/queue/<id>?removeFromClient=true&blocklist=false`.
|
||||
Результат: Radarr 6 → **0**, Sonarr 19 → **0**.
|
||||
|
||||
**Шаг 2 — снятие monitored.**
|
||||
- Radarr: `PUT /api/v3/movie/editor` с ключом **`movieIds`** → 45 → **0**
|
||||
- Sonarr: `PUT /api/v3/series/editor` с ключом **`seriesIds`** → 13 → **0**
|
||||
|
||||
Скрипты: `/tmp/arr_disable_autograb.py` (Radarr, упал на Sonarr с HTTP 500),
|
||||
`/tmp/sonarr_unmonitor.py` (Sonarr, исправленный ключ).
|
||||
|
||||
**Шаг 3 — `rssSyncInterval: 0`.** Скрипт `/tmp/radarr_rss_off.py`.
|
||||
Sonarr: 15 → 0 с первого раза. Radarr: **со второго** — первый заход вернул 30
|
||||
(не отправлял `id`), фикс — отправлять **весь объект конфига с `id: 1`**.
|
||||
|
||||
### 📊 Состояние ПОСЛЕ выполнения (замер 2026-09-22)
|
||||
|
||||
| Метрика | Radarr | Sonarr |
|
||||
|---|---|---|
|
||||
| Всего записей | 50 фильмов | 13 сериалов |
|
||||
| `monitored` | **0** (было 45) | **0** (было 13) |
|
||||
| `rssSyncInterval` | **0** (было 30) | **0** (было 15) |
|
||||
| Очередь | **0** (было 6) | **0** (было 19) |
|
||||
| С `tmdbId` | 50 (все) | — |
|
||||
| С постером | **46** | — |
|
||||
| С рейтингом TMDB | 50 (все) | — |
|
||||
| С файлом на диске | 24 (не трогали) | — |
|
||||
|
||||
**Проверка пассивности:** Transmission за 45 секунд — NET `290GB/26.7GB` и
|
||||
BLOCK `214GB/393kB` **не сдвинулись ни на байт**. Логи Radarr (`grep search|download|grab`)
|
||||
за 2 минуты — **пусто**. TorrServer: список торрентов `[]`, `echo` → `MatriX.135`.
|
||||
|
||||
### 🔴 Питфоллы выполнения (найденные в этой сессии)
|
||||
|
||||
1. **`urllib` НЕ идёт по 307 автоматически, а `curl -sL` — идёт.**
|
||||
Симптом: все 25 DELETE в первом прогоне вернули `HTTP Error 307: Temporary Redirect`,
|
||||
**ничего не удалилось**, состояние не изменилось.
|
||||
**Фикс:** свой `HTTPRedirectHandler` подкласс, который для 307/308 сохраняет
|
||||
**метод и тело** (штатный `urllib` превращает DELETE в GET):
|
||||
```python
|
||||
class RedirectKeepMethod(urllib.request.HTTPRedirectHandler):
|
||||
def redirect_request(self, req, fp, code, msg, headers, newurl):
|
||||
if code in (307, 308):
|
||||
new = urllib.request.Request(newurl, data=req.data,
|
||||
method=req.get_method())
|
||||
for k, v in req.headers.items():
|
||||
new.add_header(k, v)
|
||||
return new
|
||||
return super().redirect_request(req, fp, code, msg, headers, newurl)
|
||||
```
|
||||
Тот же корень, что у `curl` без `-L` (питфолл в памяти) — только на стороне Python.
|
||||
|
||||
2. **Sonarr группирует эпизоды сезона под одним `id`.**
|
||||
Симптом: после удаления первой записи остальные возвращают `HTTP 404: Not Found`.
|
||||
Это **не сбой** — они исчезли вместе с родительской. Итог всё равно 0.
|
||||
|
||||
3. **Ключ поля в `*/editor` различается между Radarr и Sonarr.**
|
||||
Radarr `/movie/editor` → **`movieIds`**; Sonarr `/series/editor` → **`seriesIds`**.
|
||||
`ids` → HTTP 500 Internal Server Error (Sonarr).
|
||||
|
||||
4. **`PUT /api/v3/config/indexer` требует весь объект с `id`.**
|
||||
Частичный `{"rssSyncInterval": 0}` молча возвращает старое значение.
|
||||
Отправлять весь объект, полученный `GET`, с изменённым полем.
|
||||
|
||||
5. **Кириллица в inline-`jq` внутри `ssh '...'`** снова сломала команду
|
||||
(`unexpected INVALID_CHARACTER`) — 6 ошибок в одном вызове. Ключи объекта
|
||||
писать латиницей (`total`, `monitored`, `queue`), не `всего`/`очередь`.
|
||||
|
||||
### ❓ Открытый вопрос к Alex — ЗАКРЫТ
|
||||
|
||||
Был вопрос «Radarr/Sonarr нужны как справочник или выключаются совсем?».
|
||||
**Alex ответил резко:** «Как ты блядь думаешь мне нужны блядь постеры или нет блядь?!
|
||||
Меня не ебет откуда оно их берет сделай чтобы работало как поставлено в задаче».
|
||||
→ **Остаются как справочник метаданных.** Вопрос постеров больше не задавать.
|
||||
|
||||
### План работ (на апруве Alex) — ШАГИ 0–4 ВЫПОЛНЕНЫ
|
||||
|
||||
**Шаг 0 — бэкап (обязательно, до всего)**
|
||||
```bash
|
||||
|
||||
Reference in new issue
Block a user