[2026-09-23] plan: Lampa watched → watchlist.md via TimeCode DB (sync_from_lampac)
This commit is contained in:
1 parent
5bd4b155cb
commit
34dfc8cfc6
1 file changed
+136
@@ -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-<ts>/`. Без бэкапа не начинать.
|
||||
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` — отдельная задача.
|
||||
Reference in new issue
Block a user