diff --git a/personal/plans/lampac-watched-to-watchlist.md b/personal/plans/lampac-watched-to-watchlist.md new file mode 100644 index 00000000..77aeb68f --- /dev/null +++ b/personal/plans/lampac-watched-to-watchlist.md @@ -0,0 +1,136 @@ +--- +title: Отметка «просмотрено» из Lampa → watchlist.md +type: plan +status: awaiting-approval +namespace: personal +created: 2026-09-23 +updated: 2026-09-23 +tags: [lampac, lampa, watchlist, timecode, torrserver, kraken, sync-up] +related: + - "[[family/projects/watchlist-automation]]" + - "[[personal/plans/lampac-watchlist-plugin]]" + - "[[family/documents/movies-watchlist]]" +--- + +# Отметка «просмотрено» из Lampa → `movies-watchlist.md` + +> **Проблема (Alex, 2026-09-23):** «А у нас из лампы уходят отметки просмотрено в список галочками как было в jellyfin?» +> Ответ: **нет**. Задача — сделать, чтобы уходили. + +--- + +## 1. Диагноз (проверено фактами 2026-09-23) + +### 1.1 Канал Jellyfin мёртв — и не он нужен + +- `sync_up.py` умеет **только** Jellyfin (`GET /Users/{id}/Items?IsPlayed=true`) → `[x]`. +- Jellyfin на Кра́кене хранит `BaseItems`: **53** записи, `movie` — **0**, `series` — **1**. + `UserData.IsPlayed=true` — **0**. `PlaybackActivity` — **0**. +- Причина: смотреть стали через **Lampa + TorrServer**, а не Jellyfin. Плюс с 2026-09-22 + автозакачки отключены → в Jellyfin ничего не прибавляется. +- **Вывод:** Jellyfin как источник — тупик. Фактический источник просмотров — **Lampa**. + +### 1.2 Lampa уже пишет просмотр на сервер — канал ЕСТЬ + +Модуль Lampac **`TimeCode`** (`sync`): + +| Элемент | Значение | +|---|---| +| Модуль | `/lampac/module/Sync/TimeCode/` (`Controller.cs`, `plugin.js`, `SqlContext.cs`) | +| БД | `/lampac/database/TimeCode.sql` (SQLite; на хосте `$H/lampac/database/TimeCode.sql`) | +| Таблица | `timecodes` | +| Колонки | `Id, user, identity, card, item, position, duration, percent, profile, deleted, watched_at, updated_at, extra` | +| Запись ставит | `Lampa` → `POST /timecode/add` (легаси) или `/timecode/set` (нативный), пачками ≤10 req/s | +| Читает | `GET /timecode/all?card_id=...` | +| Ключ личности | `identity` = `{tmdb_id}_movie` — **ровно то, что нужно для матча со списком** | + +**Живая запись на 2026-09-23:** +``` +identity = 1758655_movie card = movie-1758655 +position = 1222.0 duration = 6898.0 percent = 18.0 +watched_at = 0 deleted = 0 +``` +`percent` уже считается Lampa/TorrServer. Отметка «просмотрено» в UI Lampa +кладёт `percent ≈ 100` (либо `watched_at > 0` — обе колонки проверять). + +⚠️ **`sqlite3` в контейнере НЕТ** (обычный случай у Alex) — БД читать через +`docker cp lampac:/lampac/database/TimeCode.sql /tmp/` + `python3 -c "import sqlite3 ..."`. +На хосте Кра́кена `python3` есть. + +### 1.3 Что уже есть в `watchlist.json` — `tmdb_id` готов к матчу + +`$H/lampac/wwwroot/watchlist.json` → `channels.*.items[]`, у **346/346** films есть `tmdb_id`. +Матч делается по TMDB-ID, **без** хрупкого сравнения названий. + +--- + +## 2. Решение + +**Новый модуль в `watchlist-sync`: `sync_from_lampac.py`.** +Читает `timecodes` → сопоставляет по `tmdb_id` → ставит `[x]` в `.md` (тем же +`sync_up._mark_watched`, что уже работает для Jellyfin). Вызывается в конце +`watchlist-nightly.sh` — после `sync-up`, перед `sync-vault (push)`. + +Почему так, а не «писать в Jellyfin»: Jellyfin не источник просмотров и не имеет +файлов для большинства позиций. Единственный честный источник — Lampa. + +--- + +## 3. Шаги + +1. **Бэкап.** `TimeCode.sql` + `movies-watchlist.md` + `watchlist-sync/` в + `~/backup-watchlist-before-lampac-sync-/`. Без бэкапа не начинать. +2. **Новый файл** `watchlist_sync/sync_from_lampac.py`: + - читает БД по пути из env `LAMPAC_TIMECODE_DB` (default + `/lampac/database/TimeCode.sql`; хост-путь подставить в `.env`); + - отбирает `deleted = 0` и (`percent >= 90` **или** `watched_at > 0`); + - `identity` → `tmdb_id` (срезать `_movie` / `_tv`); `_tv` пропускать на первом этапе; + - строит `{tmdb_id: title}` из `watchlist.json` (`channels.*.items[]`); + - для каждого найденного `[ ]`-строки в `.md` — `[x]` через `_mark_watched`; + - `--dry-run` по умолчанию, `--apply` для записи; печатает каждое действие. +3. **Копия для теста.** Dry-run на **копии** боевого `.md`, сверить: сколько строк + перешло, какие именно. Только после сверки — `--apply` на боевом. +4. **`.env`** на Кра́кене: `LAMPAC_TIMECODE_DB=/srv/dev-disk-by-uuid-6194539b-03e0-4f33-986b-4da09834e82f/lampac/database/TimeCode.sql` + (БД лежит на хосте, не в контейнере — путь проверен). +5. **Крон.** В `~/scripts/watchlist-nightly.sh` — новый вызов **после** `sync-up`, + **до** `sync-vault (push)`. Правка через `sudo cp` (`~/scripts/` — `root:root 755`). + Бэкап скрипта до правки. Сумма новой версии зафиксировать в доке. +6. **Порог `percent`.** Начать с `>= 90`. Проверить на живой записи (сейчас 18% — + не должна проходить). При ложных срабатываниях — поднять до 95. +7. **Документировать** в `family/projects/watchlist-automation.md` (раздел про синк) + + ссылка из `personal/plans/lampac-watchlist-plugin.md`. + +--- + +## 4. Грабли (известные заранее) + +| # | Граблю | Обход | +|---|---|---| +| 1 | `sqlite3` в контейнерах НЕТ | `docker cp` + `python3 -c "import sqlite3"` на хосте | +| 2 | `~/scripts/` на Кра́кене `root:root 755` — `scp` даёт `Permission denied` | только `sudo cp` | +| 3 | Кириллица в inline-ssh | **BLOCKED** tirith — писать скрипт файлом (`write_file`), не heredoc | +| 4 | `identity` для сериалов = `{tmdb}_tv` + серия неизвестна | этап 1 — только фильмы; сериалы отдельно | +| 5 | `percent` сбрасывается в `0` при `deleted` | фильтровать `deleted = 0` | +| 6 | Матч по названию ломается на год/рейтингах | матч **только** по `tmdb_id`, строгий | +| 7 | `timecodes` пишу сам `TimeCode`, при рестарте лампака не теряется (SQLite на хосте) | ок | +| 8 | Крон-файлы возвращать только `crontab /tmp/файл`; бэкап `crontab -l > f` обязателен | — | + +--- + +## 5. Проверка результата + +- [ ] `sync_from_lampac.py --dry-run` находит запись `1758655_movie` (18% — **не** проходит) +- [ ] После ручной отметки фильма в Lampa до 100% → `--dry-run` показывает его, `--apply` ставит `[x]` +- [ ] `[x]`-строка переехала вверх (поведение `_mark_watched` как у Jellyfin-канала) +- [ ] Лог ночного прогона содержит строку от `sync_from_lampac` +- [ ] Alex видит: фильм, отмеченный в Lampa, пропал из «Мой список» в каталоге после ночного прогона +- [ ] `git log` в vault — коммит с изменённым `.md` от `Hermes` + +--- + +## 6. Что НЕ делается + +- **Не** трогаем `arr.py` (`searchForMovie: True`) — отдельная задача на апруве. +- **Не** возвращаем `sync-down` в крон — закачек быть не должно. +- **Не** пишем в Jellyfin — он не источник просмотров. +- **Не** трогаем `cleanup` — отдельная задача.