60 KiB
created, updated, status, tags
| created | updated | status | tags | ||||
|---|---|---|---|---|---|---|---|
| 2026-05-20 | 2026-09-21 | active |
|
Watchlist Automation — Полный Flow
Полная цепочка: как family/documents/movies-watchlist.md превращается в скачанный контент.
Полная цепочка
[вс 09:00] watchlist-discover ← KP API топ фильмов 2024-2025
↓ добавляет в секцию "Новинки 👍/👎"
movies-watchlist.md
Alex ставит 👍 / 👎
↓
[ежедн 09:00] watchlist-resolve ← SSH Кракен → resolve → commit
[ежедн 10:00] watchlist-sync-down
→ process-thumbs (перемещает 👍 → начало списка)
→ sync-down (добавляет батч в Radarr/Sonarr)
↓
Radarr (7878) / Sonarr (8989)
→ Prowlarr (9696) → RuTracker / Kinozal(M) / NoNaMe / etc.
→ Transmission (9091)
→ /media/movies-radarr или /media/series-sonarr
↓
router.py (Custom Script) → читает жанры из NFO/TMDb
→ symlink в /media/{movies,cartoons,documentaries,...}/
↓
Jellyfin (8096) → rescan → виден контент
Статусы в movies-watchlist.md
| Символ | Значение | Действие |
|---|---|---|
[ ] |
не смотрел, в очереди | sync-down добавляет в Radarr/Sonarr |
[x] |
просмотрено | sync-up из Jellyfin watched history |
⬇️ |
добавлено в Radarr/Sonarr | ждёт скачки |
👍 |
нравится (новинка) | process-thumbs переносит в начало → попадёт в sync-down |
👎 |
не хочу (новинка) | process-thumbs перемещает в ## Новинки👎 |
🗓️ |
upcoming (ещё не вышел) | discover помечает, не скачивается |
❓ |
не найдено / ambiguous | ждёт ручного уточнения |
🧟♀️ |
horror (genre_id=27) | информационный маркер |
⭐ |
приоритет к загрузке (U+2B50) | sync-down берёт в первую очередь, фильтр рейтинга не применяется ✅ реализовано 2026-09-20 |
⚠️ ✭ (U+272D) — НЕ приоритет. Alex 2026-09-20 явно указал: звёздочкой-приоритетом считается только ⭐ (U+2B50). Символ ✭ используется в файле как обычная пометка «выделенное», приоритетом не является.
Также: ⭐ засчитывается только в строке фильма (- [ ] Название ⭐ …), НЕ в под-буллетах кандидатов, которые генерирует mark_ambiguous (там формат «Название (год) ★N.N»). [x] (просмотренные) с ⭐ игнорируются. Работает из всех секций (## Фильмы, ## Новинки, ## Мультфильмы, ## Аниме).
Правила отбора в sync-down (актуально с 2026-09-20)
Приоритет определяется двумя факторами, а не позицией строки:
| Условие | Поведение |
|---|---|
⭐ (U+2B50) в строке фильма |
первыми, фильтр рейтинга не применяется |
все остальные [ ] |
по порядку файла (сверху вниз), рейтинг ≥ 6.0 |
рейтинг < 6.0 (включая 0.0) |
отсеивается, с логом [−] … skipped |
[x] |
пропускается |
❓ / 🗓️ (ambiguous) |
пропускается, обрабатывается отдельно |
⚠️ Порядок файла ≠ рейтинг. До 2026-09-20 код сортировал по рейтингу TMDB и игнорировал позицию в списке — из-за этого в батч попадали фильмы «не из начала списка». Исправлено коммитом ada47da.
⚠️ ⭐ = обход фильтров, а не смена сортировки. Это принципиальная позиция Alex («Я блядь сказал в приоритете завела»): звёздочка означает явное «хочу», поэтому рейтинг для неё не проверяется вовсе.
Структура секций movies-watchlist.md
## Новинки - 👍/👎 ← discover добавляет сюда
## Фильмы ← основной список, отступ 2 пробела ( - [ ])
## Мультфильмы
## Аниме
## Новинки👎 ← без пробела перед 👎
## Связанные заметки
Важно: process_thumbs автоматически определяет отступ из ## Фильмы и сохраняет при переносе. SECTION_THUMBDN = "## Новинки👎" (без пробела) — должно точно совпадать с заголовком.
✅ Крон pipeline ВОССТАНОВЛЕН (2026-09-20 21:21)
Задача закрыта. Pipeline был мёртв с 2026-06-20 (проверено аудитом ниже), теперь расписание вернули.
Установлено в crontab юзера kraken:
# Watchlist: process-thumbs + resolve + sync-down + sync-up (ежедневно 01:00)
0 1 * * * bash /home/kraken/scripts/watchlist-nightly.sh >> /tmp/watchlist-nightly.log 2>&1
# Watchlist: discover — новинки из KP API (воскресенье 09:00)
0 9 * * 0 bash /home/kraken/scripts/watchlist-discover.sh >> /tmp/watchlist-discover.log 2>&1
Как ставилось (идемпотентный скрипт, бэкап перед установкой):
crontab -l > ~/crontab-backup-$(date +%Y%m%d-%H%M%S).txt # бэкап
crontab /tmp/crontab-new.txt # установка
crontab -l # проверка
Бэкап: ~/crontab-backup-20260920-212155.txt
Проверено после установки:
systemctl is-active cron→activegrep -c watchlist /var/spool/cron/crontabs/kraken→ 2 (обе строки подхвачены демоном)- Логи пишутся в
/tmp/— теряются при перезагрузке. Перенести в постоянное место, если нужно сохранять историю.
⚠️ В docker exec hermes-kraken hermes cron list по-прежнему «No scheduled jobs» — это НЕ про watchlist. Watchlist-скрипты детерминированные, живут в системном cron, в Hermes-планировщике их не должно быть. Не искать их там.
🔴 Аудит 2026-09-20: как выглядело состояние ДО восстановления (историческая справка)
На момент аудита автодобавление фильмов НЕ работало по расписанию. Скрипты были живы, но их никто не запускал.
Доказательства (проверено 2026-09-20):
crontab -lюзераkraken— watchlist-строк НЕТ. Есть толькоsync-vault.sh(каждый час) и дваpgs-to-srt(часовой + 03:00).- root crontab и
/etc/cron.d/:grep -rl watchlist→ пусто. - systemd timers (user + system) → 0 штук.
- Внутри Hermes-контейнера на Кракене:
docker exec hermes-kraken /opt/hermes/.venv/bin/hermes cron list→ "No scheduled jobs." - Последний коммит автором
Hermes(= nightly-скрипт) — 2026-06-20. Распределение по месяцам: май 1, июнь 9, июль/август/сентябрь — 0. Единственные коммиты в vault после июня — отeagle,syncthing,taiga.
Скрипты существуют и исполняемы, но не в кроне:
~/scripts/watchlist-nightly.sh mtime 2026-05-29
~/scripts/watchlist-discover.sh mtime 2026-05-29
⚠️ Изначальная гипотеза «файл засран от многомесячного простоя» — НЕВЕРНА. Дубли создавались на каждом прогоне
resolveиз-за бага вmark_ambiguous()(см. ниже, исправлен). 33 строки у «Nightmare Alley» = 11 прогонов. Простой лишь позволил мусору накопиться незамеченным. Мусор вычищен, баг закрыт.
✅ Баг дублирования кандидатов в mark_ambiguous() — НАЙДЕН И ИСПРАВЛЕН (2026-09-20)
Симптом
Под каждой ❓-строкой копились одинаковые дампы кандидатов. Рост ровно +100 байт за прогон (3 строки кандидатов) — подтверждено экспериментом: 26430 → 26530 → 26630 → 26730 байт.
Корень (точная механика)
В watchlist_sync/parser.py, функция mark_ambiguous():
pattern = re.compile(
r'(^\s*-\s*\[ \]\s*)[❓]?\s*(' + escaped + r')\s*$', # ← матчит ТОЛЬКО строку ❓
re.MULTILINE
)
...
replacement = rf'\1❓ \2\n{cand_lines}' # ← новые кандидаты
new_text = pattern.sub(replacement, text, count=1) # ← ВСТАВЛЯЮТСЯ перед старыми
Паттерн снимал только саму ❓-строку. Замена вставляла \n + 3 новых кандидата, а старые 33 строки оставались ниже — реплейс не знал о них. Итог: каждый прогон добавляет ещё один блок кандидатов поверх существующих.
Важно: ❓-строки НЕ дублировались (каждая — одна). Дублировались под-буллеты под ними.
Фикс
Паттерн теперь захватывает весь блок: строку-маркер ПЛЮС её под-буллеты, и перезаписывает целиком.
# Candidate sub-bullet: indent of 4+ spaces, a bullet, NOT a checkbox line.
# Each iteration REQUIRES its own leading newline -- otherwise `*` walks onto
# the following line and swallows neighbouring items.
_SUB_BULLETS = r'(?:\n[ \t]{4,}-[ \t]*(?!\[[ xX]\])[^\n]*)'
pattern = re.compile(
r'(^[ \t]*-[ \t]*\[ \][ \t]*)[❓]?[ \t]*(' + escaped + r')[ \t]*'
r'(?P<subs>' + _SUB_BULLETS + r'*)',
re.MULTILINE
)
⚠️ Две НЕУДАЧНЫЕ версии паттерна (не повторять)
- v1 —
(?:\n[ \t]+-[^\n]*\n?)*:\n?опционален, поэтому*перешагивал на следующую строку без разделителя и проглатывал соседние фильмы. Потеряны❓ The kill room,The burial,Past lives. Откачено. - v2 — то же плюс негативный lookahead: не помогло,
[^\n]*из предыдущей итерации уже захватил хвост следующей строки. - v3 (рабочая) — перенос обязателен внутри каждой итерации (
(?:+\n+ ...) +*), якорь не нужен.
Правило для парсеров этого файла: под-буллет кандидата = отступ ≥4 пробела, это буллет и он НЕ чекбокс (- [ ] / - [x]). Строки фильмов имеют отступ 2 пробела — именно поэтому их надо исключать явно.
Проверка фикса
На чистой копии (md5 40295fac...) — 3 прогона mark_ambiguous():
run 1: size=25430
run 2: size=25430
run 3: size=25430
Размер стабилен. Потеряно 0 не-кандидатных строк. Past lives на месте. 838 → 808 строк (минус 30 = старые дубли, 33 → 3).
Чистка существующих дублей
Скрипт /tmp/wl_dedupe.py (дедуп по title|year|rating, первое вхождение сохраняется, порядок не меняется; строки фильмов не трогаются). Прогон --apply:
- 168 дублей в 15 блоках, 26430 → 21032 байт (838 → 670 строк).
- Топ:
Nightmare alley33→3,Stand by me30→3,Фарго30→3,Left behind21→4,Крестный отец12→3,Godfathers12→3.
Ручной прогон watchlist-nightly.sh (от юзера kraken)
bash ~/scripts/watchlist-nightly.sh
Прошёл до Done, без падений. Результат: 270 resolved (38 horror), 37 ambiguous, 22 not found. sync-down добавил 4 фильма в Radarr (Американская история X, Мастерская сатаны, Я ругаюсь, Гладиатор), Scream уже был → помечен ⬇️. sync-up: 7 played items из Jellyfin, 1 отмечен. Vault закоммичен и запушен (Committed: family/documents/movies-watchlist.md, Pushed ✓).
После прогона дублей: 0 (проверено отдельным скриптом). Секции целы: Новинки / Фильмы / Мультфильмы / Аниме / Новинки👎 / Связанные заметки.
🔴 БАГ: sync-down игнорирует порядок файла — сортирует по рейтингу (найден 2026-09-20)
Симптом (сообщил Alex): в батч на закачку попали фильмы, которые «далеко не в начале списка» — Гладиатор, Американская история X, Я ругаюсь, Мастерская Сатаны.
Корень: watchlist_sync/sync_down.py:41:
resolved.sort(key=lambda x: x[1].rating or 0, reverse=True)
Код полностью игнорирует позицию строки в файле и берёт топ-5 по рейтингу TMDB/KP из всех неотмеченных [ ]-строк. Порядок списка не имеет значения вообще.
Расхождение с докой: в watchlist-sync §1.3 заявлено «Приоритет: порядок в файле (выше = важнее)» — это не соответствует коду. Реальный приоритет = рейтинг.
Вторая половина причины: в том же прогоне process-thumbs выполняется до sync-down и переносит 👍-позиции из ## Новинки в начало основного списка. Среди перенесённых оказались Мастерская Сатаны (8.3) и Я ругаюсь (8.2) — с высокими рейтингами, поэтому они сразу выиграли отбор.
Как считался батч 2026-09-20 (5 слотов):
| Слот | Фильм | Рейтинг | Итог |
|---|---|---|---|
| 1 | Крик / Scream | 10.0 | уже в Radarr → помечен ⬇️ |
| 2 | Волшебный участок | 9.0 | 400 «already added» в Sonarr |
| 3 | Гладиатор | 8.225 | добавлен |
| 4 | Я ругаюсь | 8.229 | добавлен |
| 5 | Мастерская Сатаны | 8.3 | добавлен |
| — | Американская история X | ~8.2 | добавлен (слот освободился после первых двух) |
Saving Private Ryan (8.223) и Иди и смотри (8.214) проиграли Гладиатору (8.225) на тысячные доли.
❌ В sync_down ОТСУТСТВУЕТ фильтр по рейтингу
Проверено grep -rn "6\.0\|min_rating" watchlist_sync/*.py:
cli.py:92—< 6.0только для сброса кэша при--recheck, не отборdiscover.py:105,203— фильтр только для шага discoverresolver.py:264—0.5это сравнение рейтингов при ничьей, не порог
В sync_down порога нет вообще. Порог min_rating: 6.0 из доки watchlist-sync §1.2 в коде не реализован. Итог: в очередь могут попасть фильмы с рейтингом 0.0-5.9.
Замер 2026-09-20: из 251 resolved-кандидатов 18 имеют рейтинг < 6.0 — например Шестой элемент 4.3, Мегалополис 5.2, Бешеная любовь 3.1, Ворон 2024 5.8.
⚠️ Отдельный случай: rating == 0.0 означает «TMDB не дал оценку», а НЕ «плохой фильм». Таких двое: Уроки благи, Годзилла и конг. Наивный фильтр < 6.0 их отсечёт и потеряет нормальное кино.
✅ РЕАЛИЗОВАНО (2026-09-20): sync_down следует порядку файла + фильтр MIN_RATING
План из «📋 ПЛАН» выполнен. Alex подтвердил: порядок файла = приоритет, рейтинг = отбор, нулевые рейтинги (0.0) отсекать вместе с остальными ниже порога.
Коммиты в репо watchlist-sync (оба сделаны в этой сессии):
ada47da feat(sync-down): follow file order, filter by MIN_RATING
2dab180 fix(parser): mark_ambiguous replaces candidate block instead of prepending
Предыдущий HEAD до сессии — 20ca511. Рабочее дерево чистое.
Правка 1 — убран resolved.sort() (был на строке 41). resolved заполняется циклом по parse(), то есть остаётся в порядке файла сверху вниз.
Правка 2 — добавлена константа и фильтр в начало sync_down.py:
# Minimum TMDB/KP rating for a title to be queued. 0.0 means "no rating in
# the database" -- per Alex it is discarded together with everything below
# the threshold, so unrated items never reach Radarr/Sonarr.
MIN_RATING = 6.0
if result.status == "ok":
if (result.candidate.rating or 0) < MIN_RATING:
skipped_low += 1
print(f" [−] {item.title!r} — rating "
f"{result.candidate.rating or 0:.1f} < {MIN_RATING}, skipped")
continue
resolved.append((item, result.candidate))
else:
deferred.append((item, result))
Плюс итоговая строка (N item(s) below rating 6.0 skipped) — чтобы отсев был виден в логе, а не молчал.
process_thumbs сознательно НЕ тронут — 👍 по-прежнему уезжают в верх основного списка, то есть свежие новинки намеренно идут первыми (выбор Alex, «вариант 1»).
Dry-run после правки (проверено):
[−] ... 18 строк «skipped» (все < 6.0, включая два нуля: Уроки благи 0.0, Годзилла и конг 0.0)
(18 item(s) below rating 6.0 skipped)
[→] 'Под огнём' (2025) ★7.1 [dry-run]
[→] 'Секретный агент' (2025) ★7.3 [dry-run]
[→] 'Охота на воров 2: Пантера' (2025) ★6.6 [dry-run]
[→] 'Гадкая сестра' (2025) ★7.3 [dry-run]
[→] 'Семья в аренду' (2025) ★7.8 [dry-run]
Queued 5/5 items [dry-run]
Порядок ровно как в файле, с самого верха ## Новинки. Рейтинг больше не влияет на очерёдность — только на отбор.
⚠️ Реальный прогон (bash ~/scripts/watchlist-nightly.sh) после этой правки был ПРЕРВАН — не отработал. Vault проверен: рабочее дерево чистое, movies-watchlist.md остался на коммите d7ce0a9 (результат первого прогона), частичных изменений нет.
✅ ⭐ Приоритет по звёздочке ⭐ (U+2B50) — РЕАЛИЗОВАНО (2026-09-20)
Требование Alex: фильмы, отмеченные звёздочкой ⭐, идут в первую очередь к загрузке — приоритет поверх порядка файла, из всех секций списка.
Правила (финальные, подтверждены Alex):
- Только символ
⭐(U+2B50). Символ✭(U+272D) приоритетом НЕ является. - Только строки фильмов (
- [ ] Название ⭐ …), НЕ под-буллеты кандидатов отmark_ambiguous(«Название (год) ★N.N»). [x](просмотренные) — пропускаются.- Из всех секций — не только
## Фильмы/## Новинки(уточнение Alex). - ⭐ обходит фильтр
MIN_RATING— «Я блядь сказал в приоритете завела». Звёздочка = явное «хочу», рейтинг не важен. ⭐срезается из поискового запроса перед отправкой в TMDB (очевидное требование Alex).
Коммит: 7db9385 feat: ⭐ (U+2B50) items are queued first, bypassing the rating filter
Правка 1 — parser.py::_clean().
⚠️ Найденный баг: ⭐ стоит в середине названия (Простите за беспокойство ⭐ 2018), а старый regex был привязан к концу строки (\s*[...]+\s*$) — поэтому класс не матчился и символ утекал в запрос TMDB. Работало случайно (TMDB прощал лишний глиф).
# ⭐ (U+2B50) is a priority marker and may sit ANYWHERE in the title
# ("Простите за беспокойство ⭐ 2018"), so strip it without the end anchor.
s = s.replace('⭐', ' ')
s = re.sub(r'\s+', ' ', s).strip()
s = re.sub(r'\s*[✭★☆✩✪✫✬✮✯✰]+\s*$', '', s).strip() # остальные звёзды — по-прежнему end-anchored
return s
Критично: ⭐ вырезается из title (чистый запрос), но остаётся в raw — приоритет проверяется по item.raw, поэтому оба свойства сохраняются.
Правка 2 — sync_down.py, двухпроходная выборка:
# ⭐ (U+2B50) marks a must-have: such items are queued FIRST and bypass
# the rating filter entirely. Order within each group stays file order.
starred = [i for i in candidates_raw if "\u2b50" in i.raw]
rest = [i for i in candidates_raw if "\u2b50" not in i.raw]
if starred:
print(f" ⭐ {len(starred)} priority item(s) {[i.title for i in starred]}")
for item in starred + rest:
result = resolve(item.title, tmdb_key, kp_key)
if result.status == "ok":
if "\u2b50" not in item.raw and (result.candidate.rating or 0) < MIN_RATING:
skipped_low += 1
print(f" [−] {item.title!r} — rating "
f"{result.candidate.rating or 0:.1f} < {MIN_RATING}, skipped")
continue
resolved.append((item, result.candidate))
else:
deferred.append((item, result))
Обрати внимание на условие: "\u2b50" not in item.raw and rating < MIN_RATING — фильтр применяется только к не-⭐. Это и есть «обходит фильтр».
Итоговые правила отбора в sync-down:
| ⭐ | обычные | |
|---|---|---|
| Очерёдность | первыми | после, по порядку файла |
Фильтр MIN_RATING = 6.0 |
не применяется | применяется |
[x] |
пропуск | пропуск |
Проверка (2026-09-20):
_clean('Простите за беспокойство ⭐ 2018') -> 'Простите за беспокойство 2018' (⭐ срезан)
raw: 'Простите за беспокойство ⭐ 2018' star in raw: True (приоритет работает)
title: 'Простите за беспокойство 2018' star in title: False (чистый запрос)
candidates: 250 | starred: 1 | rest: 249 — ⭐ первым в итерации
Dry-run после правки:
⭐ 1 priority item(s) ['Простите за беспокойство 2018']
[→] 'Простите за беспокойство 2018' → 'Простите за беспокойство' (movie, 2018, ★6.8) [dry-run]
[→] 'Гадкая сестра' (2025) ★7.3 ...
Queued 5/5 items [dry-run]
Единственный ⭐ в файле — строка 79, секция ## Фильмы: - [ ] Простите за беспокойство ⭐ 2018.
✅ Реальный прогон 2026-09-20 19:53 — прошёл чисто
bash ~/scripts/watchlist-nightly.sh от юзера kraken → Done, ошибок нет. Вывод (/tmp/wl-run.log):
(18 item(s) below rating 6.0 skipped)
[=] 'Простите за беспокойство' already in Radarr, marking queued ← ⭐ обработан ПЕРВЫМ
[=] 'Гадкая сестра' already in Radarr, marking queued
[✅] 'Список заветных желаний' added to Radarr, search triggered
[✅] 'Отпуск на двоих' added to Radarr, search triggered
[✅] 'Простая случайность' added to Radarr, search triggered
Queued 5/5 items
[19:53:32] ▶ Done
⭐-фильм попал в очередь первым, но добавлять было нечего (уже в Radarr с прерванного прогона) — значит приоритет сработал. Дубли после прогона: 0. Файл: 21332 байт / 676 строк.
🩹 Почему первая версия правки не сработала (не повторять)
Первая попытка добавить ⭐ в существующий класс [✭★☆✩✪✫✬✮✯✰] не дала эффекта — класс end-anchored ($), а ⭐ стоит в середине названия. Проверка на тестах показала star gone: False. Вывод: для маркеров, которые могут стоять в любой позиции, нужен str.replace(), а не класс с якорем.
📋 Как задача ставилась (для контекста будущих сессий)
Alex формулировал требования короткими репликами, и план сначала был неверно истолкован дважды:
- «⭐ - в приоритете, из всех списков. Естественно в tmdb ее срезать» — уточнение, что секции не ограничены и глиф не должен уходить в запрос.
- «Что блядь значит рейтинг остался?! Я блядь сказал в приоритете завела» — категорическое: ⭐ обходит фильтр рейтинга, а не просто меняет очерёдность.
Вывод для будущего: когда Alex говорит «в приоритете» — это означает обход фильтров, а не смену сортировки. Уточнять это ДО предложения плана, а не после.
📦 Результат закачки по итогам прогона 2026-09-20
sync-down добавил 4 фильма (Scream уже был → ⬇️). Проверено через Radarr API + Transmission:
| Фильм | Взятый релиз | Статус |
|---|---|---|
| Gladiator (2000) | UHD BDRip [H.265/2160p] [4K] |
качается |
| American History X (1998) | BDRip [AVC] |
качается |
| I Swear (2025) / Я ругаюсь | BDRip [H.264/1080p] [DVO] |
качается |
| Oficina do Diabo (2025) / Мастерская Сатаны | — | релиз не найден, ждёт RSS |
✅ Профиль качества работает как задумано: Gladiator взят в 4K, но BDRip, не Remux — профиль 7 WEB-4K (no remux) фильтрует корректно.
Застрявшие в очереди Radarr (со статусом warning, к этому прогону не относятся): Brokeback Mountain, Мортал Комбат 2, Sorry to Bother You, Город бога, День хомячка. Отдельная задача — разобрать.
🟡 Побочная находка: Zulip-пинг не настроен на Кракене
_zulip_ping() требует ZULIP_URL, ZULIP_API_KEY, ZULIP_BOT_EMAIL, но их нет в .env репо watchlist-sync. При 59 нерезолвленных items → [warn] ... not set — skipping ping. Уведомления о нерезолвленных до Alex не доходят.
🟡 Побочная находка: Sonarr 400 «This series has already been added»
При sync-down для «Волшебный участок»: 400 Bad Request на /sonarr/api/v3/series. Причина безобидная — серия уже в Sonarr (tvdbId=442038, «Magical Police Department»). arr.py::sonarr_add() не проверяет дубли перед POST, поэтому Sonarr отвечает SeriesExistsValidator. Не сбой, но шумит в логе — стоит добавить pre-check (как в radarr_add).
Бэкапы (перед правками)
~/obsidian/family/documents/movies-watchlist.md.bak-20260920-192909 (838 строк, 26430 б)
~/obsidian/family/documents/movies-watchlist.md.dedupe-backup-20260920-193111
/srv/.../watchlist-sync/watchlist_sync/parser.py.bak-20260920-192909
Статус на конец сессии (2026-09-20, финал)
Три коммита в репо watchlist-sync (порядок применения):
7db9385 feat: ⭐ (U+2B50) items are queued first, bypassing the rating filter
ada47da feat(sync-down): follow file order, filter by MIN_RATING
2dab180 fix(parser): mark_ambiguous replaces candidate block instead of prepending
20ca511 ← HEAD до сессии
Рабочее дерево чистое. .bak-* добавлены в .gitignore.
- ✅ Фикс
parser.py(mark_ambiguous) применён, проверен 3 прогонами на чистой копии, закоммичен. - ✅ Фикс
sync_down.py— порядок файла +MIN_RATING = 6.0, закоммичен. Dry-run подтверждён. - ✅ Приоритет
⭐(U+2B50) реализован, закоммичен. Обходит фильтр рейтинга, работает из всех секций,[x]пропускает. - ✅ Файл watchlist вычищен (168 дублей → 0) и закоммичен в vault.
- ✅ Два реальных прогона
watchlist-nightly.shпрошли чисто. Второй (19:53) — уже с приоритетом ⭐:Done, ошибок нет, 3 фильма ушли в закачку. - ✅ Дубли после всех прогонов: 0.
- 🔴 Крон по-прежнему отсутствует — pipeline живёт только вручную. ГЛАВНАЯ незакрытая задача.
- 🟡 Zulip-пинг не настроен (
ZULIP_*нет в.env). - ℹ️ Доки watchlist-automation и watchlist-sync обновлялись агентом Eagle в этой же сессии (коммиты
bd743da,abee5a8в vault) — при правках сверяться.
Хронология прогонов 2026-09-20:
| Время | Что | Результат |
|---|---|---|
| ~19:33 | Прогон после фикса дедупа (до правки sync_down) |
4 фильма в Radarr: Gladiator, American History X, I Swear, Oficina do Diabo (без релиза) |
| ~19:45 | Прогон после правки sync_down |
ПРЕРВАН (прерван пользователем), правок не оставил |
| 19:53 | Финальный прогон (файловый порядок + MIN_RATING + ⭐) |
Done. +3 фильма: Список заветных желаний, Отпуск на двоих, Простая случайность |
Бэкапы (все созданы в этой сессии):
~/obsidian/family/documents/movies-watchlist.md.bak-20260920-192909 (838 строк, 26430 б — ДО фикса)
~/obsidian/family/documents/movies-watchlist.md.dedupe-backup-20260920-193111 (до дедупа)
/srv/.../watchlist-sync/watchlist_sync/parser.py.bak-20260920-192909 (md5 0f597606fa14f357ff3b25547bd18ea6)
/srv/.../watchlist-sync/watchlist_sync/parser.py.bak-20260920-195100 (до правки ⭐)
/srv/.../watchlist-sync/watchlist_sync/sync_down.py.bak-20260920-194447
/srv/.../watchlist-sync/watchlist_sync/sync_down.py.bak-20260920-195100 (до правки ⭐)
Скрипты диагностики/фикса (на Кракене, /tmp/): wl_dedupe.py (дедуп кандидатов, --apply), wl_postcheck.py (проверка дублей после прогона), wl_orphan.py (проверка структуры блоков), wl_verify_final.py, wl_order2.py, wl_grab_check.py (Radarr queue + Transmission), wl_fix_parser3.py, wl_fix_syncdown.py, wl_fix_star.py, wl_fix_clean2.py, wl_star.py, wl_star_check.py, wl_final_star.py.
Скрипты повторного использования: wl_dedupe.py — при накоплении дублей; wl_postcheck.py — контроль после каждого прогона; wl_grab_check.py — что реально ушло в закачку.
Пути к конфигам *arr (проверено 2026-09-20, в доке ранее были ошибочны)
Конфиги Radarr/Sonarr/Transmission лежат на втором диске (6194539b-03e0-4f33-986b-4da09834e82f), не на том же, что медиа:
Radarr API key: /srv/dev-disk-by-uuid-6194539b-.../docker/radarr/config/config.xml
Sonarr: /srv/dev-disk-by-uuid-6194539b-.../docker/sonarr/config/config.xml
Transmission: /srv/dev-disk-by-uuid-6194539b-.../docker/transmission/settings.json
Radarr API base: http://localhost:7878/radarr/api/v3/ (ключ из config.xml)
Sonarr API base: http://localhost:8989/sonarr/api/v3/
Проверка закачки: queue в Radarr показывает grabbed/downloading; history даёт точное имя взятого релиза. Transmission — docker exec transmission transmission-remote --list (RPC-юзер в settings.json пустой).
🔴 2026-09-21: ДИСК ЗАПОЛНЕН 100%, КРОН nightly/discover ОСТАНОВЛЕН
Причина остановки: sync-down --batch 5 (5 фильмов ежедневно) работал без проверки свободного места. Диск заполнился до нуля байт.
Признак «сервисы ломаются» — Radarr отдаёт disk I/O error
curl -s "http://localhost:7878/radarr/api/v3/movie?apikey=$KEY"
# → {"message": "disk I/O error\ndisk I/O error",
# "description": "...System.Data.SQLite.SQLiteException (0x87AF045D): disk I/O error..."}
SQLite не может писать при нуле свободного места. Метаданные Radarr через API не читаются, пока диск не освобождён. Это первое, что надо проверять при «Radarr молчит» на заполненном диске.
Фактическое заполнение (2026-09-21)
df -h → /dev/sda1 1.8T 1.7T 0 100% /srv/dev-disk-by-uuid-6194539b-...
df -h → /dev/mmcblk0p2 14G 4.7G 8.4G 36% / (SD-карта, не медиа-диск)
Docker: 29.4.3, Debian 12 bookworm, arch aarch64, 25 контейнеров, 22 образа.
Что именно съело место — 5 REMUX-файлов = 403.4 ГБ
Замер find -printf по /media/movies-radarr (27 видеофайлов). Настоящих remux'ов ровно 5 — по имени файла (Remux/BDREMUX/BDRemux):
| Размер | Фильм | Файл |
|---|---|---|
| 92.0 GB | Babylon (2022) | Babylon (2022) - UHD BD-Remux by Wild_Cat.mkv |
| 89.4 GB | Schindler's List (1993) | Schindler's.List.1993.2160p.HDR.BDRemux.mkv |
| 85.6 GB | Midsommar (2019) | Midsommar.2019.DC.BDREMUX.2160p.HDR.seleZen.mkv |
| 79.7 GB | Triangle of Sadness (2022) | Triangle.of.Sadness.2022.BDREMUX.2160p.HDR.seleZen.mkv |
| 56.7 GB | Unhinged (2020) | Неистовый.2020.UHD.Blu-Ray.Remux.2160p.mkv |
| 403.4 GB | итого |
⚠️ Остальные 22 файла — НЕ remux (WEB-DL / BDRip / x264 / x265, 4–29 ГБ). Крупные, но кодированные — не трогать. Например Oldboy (2003)/Oldeuboi [2003].mkv 28.6 ГБ и Project.Hail.Mary...2160p.iT.WEB-DL.DV.HDR.H.265.mkv 28.1 ГБ — не remux, несмотря на размер.
Корень: захардкоженный qualityProfileId: 1 (профиль Any) в arr.py — починен только 2026-09-04. Всё, что качалось до этого, брало remux'ы по 60–98 ГБ.
🔴 Метки ⬇️ на 4 из 5 remux'ов В watchlist НЕТ
Проверено грепом по family/documents/movies-watchlist.md:
| Фильм | Строка в watchlist | Метка |
|---|---|---|
| Неистовый (Unhinged) | 107: - [x] ⬇️ Неистовый |
✅ есть (и [x]) |
| Babylon (2022) | 83: - [ ] Babylon (2022) |
❌ нет |
| Midsommar | 81: - [ ] 🧟♀️ midsommar 2019 |
❌ нет |
| Triangle of Sadness | 82: - [ ] Triangle of Sadness 2022 |
❌ нет |
| Schindler's List | не найден в файле | ❌ нет |
Вывод: sync-down помечает ⬇️ только то, что добавил сам. Эти 4 попали в Radarr другим путём (вручную / до появления меток). Снимать метку не с чего — кроме Неистового.
Порядок работ, согласованный с Alex
- Удалить 5 remux-файлов (403.4 ГБ) → диск оживает → Radarr API заработает.
- Снять
⬇️у Неистового (строка 107).[x]— не трогать (это отметка просмотра). - Добавить
MIN_FREE_GBв скрипт — стоп-кран перед добавлением в Radarr. - ⚠️ Лимит качества Alex считает уже настроенным (
WEB-4K (no remux), id 7) — новый лимит не делаем.
⚠️ Удаление напрямую файлами, не через Radarr API — API лежит на заполненном диске. Radarr пересканирует и увидит hasFile=false.
Остановка крона (сделано 2026-09-21)
crontab -l > ~/crontab-backup-$(date +%Y%m%d-%H%M%S).txt # бэкап ПЕРЕД
crontab -l | grep -v "watchlist-nightly\|watchlist-discover" > /tmp/crontab-new.txt
crontab /tmp/crontab-new.txt
crontab -l | grep -c "watchlist-nightly\|watchlist-discover" # → 0 (проверка)
Бэкап: ~/crontab-backup-20260921.txt.
Осталось в кроне: sync-vault (часовой), 2× pgs-to-srt, watchlist-cleanup (02:00).
Убрано: watchlist-nightly (01:00), watchlist-discover (вс 09:00).
🔴 Незакрытые дефекты скрипта (моя ответственность)
| # | Дефект | Следствие |
|---|---|---|
| 1 | Нет проверки свободного места перед sync-down |
Radarr качает, пока диск не кончится |
| 2 | Нет лимита размера файла | Один фильм = 60–100 ГБ |
| 3 | Нет стоп-крана при заполнении > порога | Нет автоматической остановки |
| 4 | cleanup не видит /media/movies |
Просмотренное не удаляется, диск не освобождается |
План ремонта (согласован): сначала Фаза 1 — MIN_FREE_GB в скрипт (главный фикс), потом возврат крона с меньшим --batch. Cleanup — отдельно.
Правило на будущее: любой скрипт, ставящий закачки в очередь, ОБЯЗАН проверять свободное место до добавления. Лимита качества недостаточно — он ограничивает тип релиза, но не размер.
Cron Jobs (на Кракене, восстановлены 2026-09-20, дополнены 2026-09-21)
Весь watchlist pipeline работает на Кракене (мигрировал с Eagle 2026-05-27). Крон был мёртв с 2026-06-20 по 2026-09-20, восстановлен (детали в начале документа).
⚠️ С 2026-09-21
watchlist-nightlyиwatchlist-discoverОСТАНОВЛЕНЫ (диск 100%, см. секцию выше). Таблица ниже — целевое состояние; фактически активен толькоwatchlist-cleanup.
| Job | Расписание | Скрипт | Факт 2026-09-21 |
|---|---|---|---|
watchlist-nightly |
ежедн. 01:00 | ~/scripts/watchlist-nightly.sh |
⏹ ОСТАНОВЛЕН |
watchlist-cleanup |
ежедн. 02:00 | ~/scripts/watchlist-cleanup.sh --apply |
✅ активен |
watchlist-discover |
вс 09:00 | ~/scripts/watchlist-discover.sh |
⏹ ОСТАНОВЛЕН |
⚠️ Фактический путь — ~/scripts/, не ~/.hermes/scripts/. Оба скрипта вызывают CLI напрямую через uv run --project $WS, без LLM. uv лежит в ~/.local/bin/uv.
⚠️ ~/scripts/ — root:root 755. Добавить/заменить скрипт можно только sudo install -m 755 (у kraken sudo без пароля). Обычная запись (>, cp) откажет с Permission denied.
⚠️ watchlist-cleanup.sh без аргумента = dry-run. В кроне обязателен --apply, иначе удаление не произойдёт и лог будет писать «nothing to delete». Это самая тихая из возможных поломок — проверять флаг при любой правке крона.
WS в обоих скриптах: /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/watchlist-sync — другой UUID, чем фактический корень репо (см. ниже). Возможный источник поломки: проверить, что путь резолвится.
watchlist-nightly.sh (на Кракене):
sync-vault.sh(pull) →process-thumbs --apply→sync-vault.sh(push)resolve --recheck --apply→sync-down --apply --batch 5→sync-up --apply→sync-vault.sh(push)
Пути на Кракене (HDD UUID 49e8f586-3839-4c5d-a1e1-58bfc3579ade):
/home/kraken/obsidian→ symlink на/srv/dev-disk-by-uuid-.../obsidian/home/kraken/Developer/watchlist-sync→ symlink на/srv/dev-disk-by-uuid-49e8f586-.../watchlist-sync
✅ Путь репо в скриптах ВЕРНЫЙ (проверено 2026-09-20). В watchlist-nightly.sh и watchlist-discover.sh:
WS=/srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/watchlist-sync
UV=~/.local/bin/uv
ls -la подтверждает: /srv/.../watchlist-sync существует, внутри watchlist_sync/, .venv/, .resolve_cache.json, pyproject.toml, .env (есть, содержит TMDB_KEY/KP_KEY/RADARR_/SONARR_; нет ZULIP_*).
Ранее в доке фигурировал путь
.../6194539b-.../watchlist-sync«как реальный корень». На 2026-09-20 рабочий путь —49e8f586, и он же используется в скриптах. Не «исправлять» его обратно.
Ещё одно подтверждённое отличие: ~/scripts/ — реальная директория (drwxr-xr-x root root), а ~/.hermes/ на Кракане содержит только skills/. Скрипты лежат в ~/scripts/, не в ~/.hermes/scripts/.
Как запускать CLI вручную (рабочая команда)
ssh kraken
cd /srv/dev-disk-by-uuid-49e8f586-3839-4c5d-a1e1-58bfc3579ade/watchlist-sync
uv run --project . watchlist-sync <команда> # resolve / sync-down / sync-up / process-thumbs / discover
Или целиком пайплайн: bash ~/scripts/watchlist-nightly.sh
Discover — Фильтрация
| Тип | Порог |
|---|---|
| Мировые | IMDb ≥ 7.0 или KP ≥ 7.0 |
| Российские | KP ≥ 8.5 (защита от накрутки) |
| Upcoming | год ≥ текущий−1 |
| Минимум голосов | IMDb ≥ 1000 или KP ≥ 500 |
KP API endpoint: https://api.poiskkino.dev/v1.4/movie (redirect с api.kinopoisk.dev).
*arr Stack — Индексеры (Prowlarr)
| ID | Имя | Тип | Примечание |
|---|---|---|---|
| 1 | RuTracker | semi-private | блокирует при rate limit на сутки |
| 2 | RuTor | public | поиск по imdbid |
| 3 | Byrutor | public | |
| 4 | NoNaMe Club | semi-private | анонимный |
| 5 | Kinozal | semi-private | резерв |
| 6 | Kinozal (M) | semi-private | магнет ✅ — без grab limit, предпочтительный |
Pi-hole питфолл: блокирует skyhook.sonarr.tv → Sonarr/Radarr поиск молча не запускается. Фикс: dns: [8.8.8.8] в docker-compose.yml.
Router Script — Маршрутизация по жанру
После импорта Sonarr/Radarr: router.py --apply создаёт symlinks:
- Animation (не R/18+) →
/media/cartoons/или/media/cartoons-series/ - Documentary →
/media/documentaries/или/media/documentaries-series/ - Прочее →
/media/movies/или/media/series/
Копирует NFO + постер рядом с symlink (Jellyfin не видит метадату через symlink напрямую).
watchlist-sync — Python CLI
Репо: ~/Developer/watchlist-sync (GitHub: mallexxx/watchlist-sync).
watchlist-sync resolve — TMDB + KP API → ID, тип (movie/tv)
watchlist-sync sync-down — добавить батч (max 5) в Radarr/Sonarr, поставить ⬇️
watchlist-sync sync-up — Jellyfin watched → [x] в .md
Резолвер: TMDB /search/multi + KP fallback. Пороги: min_rating: 6.0, min_score: 0.75. При 2+ кандидатах → ❓ (LLM разрешает в cron каждые 6ч, нерешённые → уточнение в Zulip).
Stage 2 (после ≥50 просмотров): AI-curated recommendations — три списка (с женой / один / семья) на основе TMDB профиля, добавляются в конец watchlist как ## 🤖 Рекомендации (YYYY-WNN).
Jellyfin library mapping: Movies → movies, Cartoons → mixed (movies + episodes).
Питфоллы
KP Markdown Link Parsing Bug
Фильмы из Kinopoisk с синтаксисом [Title](https://kinopoisk.ru/film/12345/) (2025) передавались как есть в TMDB search → не находились → помечались ❓ навсегда (not i.ambiguous пропускает при следующем запуске). Фикс: commit 2db1ed9 — извлекать plain title из markdown link до передачи в TMDB. Ошибочно помеченные ❓ требуют ручного --recheck.
KP API Endpoint
api.kinopoisk.dev редиректит на api.poiskkino.dev/v1.4/movie. Использовать destination redirect напрямую.
🔴 Жёстко зашитый qualityProfileId в arr.py (корень жирных remux) — РЕШЕНО
Найдено 2026-09-04. В watchlist_sync/arr.py изначально был захардкожен qualityProfileId: 1 и для Radarr, и для Sonarr:
# radarr_add (~стр. 77) / sonarr_add (~стр. 112)
"qualityProfileId": 1,
Профиль 1 (Radarr) = 'Any' — разрешает ВСЁ вплоть до Remux-2160p и BR-DISK, поэтому каждый новый фильм/сериал попадал в «Any» и Radarr скачивал 60GB remux'ы.
✅ Решение принято и применено 2026-09-04: создан профиль WEB-4K (no remux) → Radarr id 7, Sonarr id 7; arr.py теперь пишет qualityProfileId: 7. Подробности профиля — в arr-stack-kraken, секция «Качество загрузки для НОВЫХ фильмов/сериалов».
✅ Баг накопления кандидатов в mark_ambiguous() (найден и исправлен 2026-09-20)
Кандидаты-под-буллеты под ❓-строками дублировались на каждом прогоне resolve (+3 строки за раз), потому что re.sub снимал только саму ❓-строку, а новые кандидаты вставлялись перед старыми. Паттерн исправлен на захват всего блока (маркер + под-буллеты). Полная механика, две неудачные версии паттерна и чистка 168 дублей — в family/projects/watchlist-automation.
Правило для парсеров watchlist: под-буллет кандидата = отступ ≥4 пробела + буллет + НЕ чекбокс (- [ ]/- [x]). Строки фильмов имеют отступ 2 пробела. Внутри *-группы перенос строки обязателен — иначе regex проглатывает соседние фильмы.
Open Tasks
- ✅ [2026-09-20] Фикс
sync_down.pyРЕАЛИЗОВАН — коммитada47da.resolved.sort()убран, добавленMIN_RATING = 6.0с видимымprint. Нулевые рейтинги отсекаются (решение Alex: «отсекать»). - ✅ [2026-09-20] Приоритет
⭐(U+2B50) РЕАЛИЗОВАН — коммит7db9385. ⭐ первыми из всех секций, обходит фильтрMIN_RATING.⭐срезается из запроса TMDB (parser._cleanчерезstr.replace, НЕ через end-anchored класс).✭(U+272D) приоритетом не считается;[x]пропускается; под-буллеты кандидатов не считаются. - ✅ [2026-09-20] Реальный прогон с новой логикой выполнен — 19:53,
Done, +3 фильма. Батч по порядку файла, ⭐ первым. - ✅ [2026-09-20] Крон ВОССТАНОВЛЕН — установлен 21:21 в crontab юзера
kraken, бэкап~/crontab-backup-20260920-212155.txt.nightly01:00 +discoverвс 09:00, логи в/tmp/. Первая проверка в бою — прогон в 01:00. - 🟡 [2026-09-20] Логи крона в
/tmp/— теряются при перезагрузке. Перенести в постоянное место (~/logs/или на диск), если нужна история прогонов. - ✅ [2026-09-21] Удаление просмотренных фильмов при заполнении диска >90% — ЗАКРЫТО И В КРОНЕ. Обёртка
~/scripts/watchlist-cleanup.sh(была в/tmp— перенесена черезsudo install, у kraken sudo без пароля), cron0 2 * * * ... --apply, лог/home/kraken/logs/watchlist-cleanup.log. Корзина Radarr (recycleBin) — решено НЕ настраивать (контейнерный/хостовый пути расходятся; Alex больше не переспрашивать). Обёртка по умолчанию делает dry-run — без--applyв кроне был бы вечный холостой ход. Полные детали — family/plans/watchlist-cleanup. ⚠️ Питфолл:/media— не медиа-диск, а пустая папка на SD-карте (/dev/mmcblk0p2), отдаёт 33.9%. Реальный диск/dev/sda1в/srv/dev-disk-by-uuid-6194539b-.../. Использоватьos.statvfs, неshutil.disk_usage("/media"). - 🔴 [2026-09-21] ДИСК ЗАПОЛНЕН 100% (0 байт свободно).
nightly+discoverОСТАНОВЛЕНЫ. Работалsync-down --batch 5ежедневно без проверки места. Radarr лёг сdisk I/O error(SQLite не может писать). Полный разбор — в секции «🔴 2026-09-21: ДИСК ЗАПОЛНЕН 100%» выше. Бэкап crontab:~/crontab-backup-20260921.txt. - 🔴 [2026-09-21] ЖДЁТ АПРУВА ALEX: удаление 5 remux-файлов = 403.4 ГБ. Babylon 92.0 / Schindler's List 89.4 / Midsommar 85.6 / Triangle of Sadness 79.7 / Unhinged 56.7 ГБ. Удалять файлами напрямую (Radarr API лежит). Затем снять
⬇️у Неистового (строка 107),[x]не трогать. ⚠️ У 4 из 5 метки⬇️в watchlist нет; Schindler's List в файле отсутствует вовсе. - 🔴 [2026-09-21] ФАЗА 1 РЕМОНТА: добавить
MIN_FREE_GBвsync-down. Стоп-кран: если свободно < порога — не добавлять в Radarr. Главный фикс, без него возврат крона бессмыслен. Лимит качества Alex считает уже настроенным — новый не делать. - 🔴 [2026-09-21] КОРЕНЬ:
[x]не проставляется на новые закачки.sync-up(Jellyfin watched →[x]) видит только 6 старых фильмов из/media/movies, ни одного из/media/movies-radarr. Пока это не починено, cleanup бесполезен, а диск будет заполняться. - 🔴 [2026-09-21] ДИСК КРИТИЧЕН: 94.7% / свободно 4.8 ГБ (замер до полного заполнения). Порог 90% пройден, cleanup реально запускается, но удаляет 0 файлов: пересечение
[x]∩ Radarr-библиотека = пусто (177 просмотренных vs 28 фильмов с файлами). - 🟡 [2026-09-21] Cleanup не видит
/media/movies— смотрит только Radarr-библиотеку, поэтому просмотренное из папки ручных торрентов не удаляется. Расширять — отдельно и осторожно (удаление файлов). - 🟡 [2026-09-20]
sync-downберёт всего 5 за прогон — при 250 кандидатах разбор очереди займёт ~50 ночей. Рассмотреть увеличение--batch(сейчас--batch 5вwatchlist-nightly.sh). Особенно актуально, раз фильтр<6.0уже отсеял 18. - 🟡 [2026-09-20] Разобрать 5 застрявших закачек в очереди Radarr со статусом
warning:Brokeback Mountain,Мортал Комбат 2,Sorry to Bother You,Город бога,День хомячка. Висят давно, релиз не находится/не качается. - 🟡 [2026-09-20]
Oficina do Diabo/Мастерская Сатаны(2025) — в Radarr, но релиз не найден. Ждёт RSS. Проверить через несколько дней. - 🟡 [2026-09-20] Настроить Zulip-пинг —
ZULIP_URL/ZULIP_API_KEY/ZULIP_BOT_EMAILотсутствуют в.envwatchlist-sync, 59 нерезолвленных items ушли в никуда без уведомления. - 🟡 [2026-09-20] Добавить pre-check дублей в
sonarr_add()— сейчас при уже существующей серии прилетает400 SeriesExistsValidatorи шумит в логе. Вradarr_add()проверка есть. - 🟡 [2026-09-20] Синхронизировать документацию с кодом — watchlist-sync §1.2 и §1.3 описывают порог
min_rating: 6.0и «приоритет = порядок в файле», которых в коде не было. Порог теперь реализован (MIN_RATING), приоритет по порядку тоже, плюс появился приоритет ⭐ — обновить формулировки в watchlist-sync. - 🔴 [2026-09-04] Решить стратегию качества загрузки новых фильмов — уже РЕШЕНО 2026-09-04 (профиль
WEB-4K (no remux), id 7 для Radarr и Sonarr). Осталось только убедиться, что старые⬇️-позиции, добавленные до фикса, не тянут remux. - 🟡 Оставшиеся
❓-позиции (71 маркер) — намеренно не чистятся вручную (решение Alex 2026-09-20). Разбираются черезresolve --recheckпри работающем кроне. - 🟡 Передавать Transmission locations через router script при каждом импорте (сейчас вручную)
- 🔴 rsync невыполненных фильмов с HTPC на Кракен (
Фильмы не перенесенные с htpc на кракен.md) - 🟡 Watchlist sync-up: добавить перенесённые фильмы в нужные разделы
Связанные заметки
- watchlist-discover — шаг discover: KP API, format, CLI команды
- watchlist-sync — основной проект (resolve, sync-down, sync-up)
- arr-stack-kraken — детальные питфоллы *arr стека
- jellyfin-transcode-rpi5 — Jellyfin PGS/ASS питфоллы