[2026-09-21] eagle: family/plans/watchlist-disk-overflow-fix.md personal/tech/inter-site-throughput-taiga-to-mac.md personal/tech/multistream-single-flow-limit.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-21 15:08:42 +06:00
1 parent 313df3409d
commit ae1caede69
3 files changed
+367 -43

No files matched your search

+158 -43
View File
@@ -11,6 +11,8 @@ tags:
- disk
- radarr
- incident
- mark-queued
- horror-filter
related:
- '[[family/projects/watchlist-automation]]'
- '[[family/plans/watchlist-cleanup]]'
@@ -23,6 +25,11 @@ related:
> Radarr лежит с `disk I/O error`. `watchlist-nightly` и `watchlist-discover` остановлены.
> Причина: `sync-down --batch 5` качал 5 фильмов ежедневно **без проверки свободного места**.
> **Три независимых дефекта (все найдены 2026-09-21 по коду):**
> 1. **Нет проверки места** → диск забит под ноль (`sync_down.py`)
> 2. **`mark_queued` молча проваливается** → 3 метки `⬇️` потеряны (`parser.py:77`)
> 3. **Правила «ужасы не качаются» НЕТ в коде вообще** → `🧟‍♀️` только рисуется, фильтр отсутствует; `⭐` приоритетнее `🧟` тоже не реализовано
---
## Статус: Фаза 0 ожидает апрува Alex
@@ -30,11 +37,14 @@ related:
| Фаза | Что | Статус |
|---|---|---|
| 0 | Освободить место (удалить 5 remux = 403.4 ГБ) | 🔴 **ЖДЁТ АПРУВА** |
| 0b | Снять `⬇️` у Неистового в watchlist | ⏸ после Фазы 0 |
| 1 | `MIN_FREE_GB` в скрипт (стоп-кран) | ⏸ |
| 2 | Лимит размера файла | ❌ **НЕ ДЕЛАЕМ** — Alex: «лимит качества и так настроен» |
| 3 | Починить `cleanup` (видит только Radarr) | ⏸ отдельно |
| 4 | Вернуть крон с меньшим `--batch` | ⏸ после Фазы 1 |
| 0b | Снять `⬇️` у Шиндлера (396) + Неистового (107) | ⏸ после Фазы 0 |
| 1 | **Фикс `mark_queued`** — эмодзи-префиксы + возврат `bool` + лог провала | ⏸ **НОВОЕ** |
| 2 | `MIN_FREE_GB` в скрипт (стоп-кран) | ⏸ |
| 2b | Лимит размера файла | ❌ **НЕ ДЕЛАЕМ** — Alex: «лимит качества и так настроен» |
| 3 | **Фильтр ужасов + приоритет `⭐ > 🧟`** (правило новое, в коде его нет) | ⏸ **НОВОЕ** |
| 3b | Починить `cleanup` (видит только Radarr) | ⏸ отдельно |
| 4 | Восстановить 3 потерянные `⬇️` (Babylon, Midsommar, Triangle) | ⏸ после Фазы 1 |
| 5 | Вернуть крон с `--batch 2` | ⏸ после Фаз 1–2 |
**Сделано 2026-09-21:** крон `watchlist-nightly` + `watchlist-discover` остановлен.
Бэкап crontab: `~/crontab-backup-20260921.txt`.
@@ -68,21 +78,32 @@ related:
**Признак remux — имя файла:** `Remux` / `BDREMUX` / `BDRemux` / `BD-Remux`.
### 🔴 Метки `⬇️` в watchlist — есть только у одного из пяти
### 🔴 Метки `⬇️` — факт: у 3 из 5 метки ПОТЕРЯНЫ (баг `mark_queued`)
`family/documents/movies-watchlist.md`:
`family/documents/movies-watchlist.md` — **все 5 фильмов есть в списке** (проверено `grep` по ru+en):
| Фильм | Строка | Метка |
| Фильм | Строка | Метка `⬇️` |
|---|---|---|
| Неистовый (Unhinged) | 107: `- [x] ⬇️ Неистовый` | ✅ |
| Babylon (2022) | 83: `- [ ] Babylon (2022)` | ❌ |
| Midsommar | 81: `- [ ] 🧟‍♀️ midsommar 2019` | ❌ |
| Triangle of Sadness | 82: `- [ ] Triangle of Sadness 2022` | ❌ |
| Schindler's List | — | **отсутствует в файле** |
| Неистовый (Unhinged) | 107: `- [x] ⬇️ Неистовый` | ✅ есть |
| Список Шиндлера | 396: `- [ ] ⬇️ Список Шиндлера` | ✅ есть |
| Babylon (2022) | 83: `- [ ] Babylon (2022)` | ❌ **потеряна** |
| Midsommar | 81: `- [ ] 🧟‍♀️ midsommar 2019` | ❌ **потеряна** |
| Triangle of Sadness | 82: `- [ ] Triangle of Sadness 2022` | ❌ **потеряна** |
`sync-down` ставит `⬇️` только на то, что добавил сам. Эти четыре попали в Radarr иначе.
⚠️ **Питфолл поиска:** Шиндлер записан **по-русски** («Список Шиндлера»). `grep -i schindler` его **не находит** → ошибочный вывод «фильма нет в списке». Искать и ru, и en.
**Решение Alex:** снять `⬇️` (там, где есть). `[x]` у Неистового **не трогать** — это отметка просмотра.
**Корень потери меток — баг `mark_queued` (`parser.py:77`):**
```python
pattern = re.compile(r'(^\s*-\s*\[ \]\s*)(' + re.escape(title) + r')', re.MULTILINE)
new_text = pattern.sub(r'\1⬇️ \2', text, count=1)
if new_text != text:
path.write_text(new_text) # ← молча ничего, если не совпало
```
1. Между `]` и названием бывает **эмодзи-маркер** (`🧟‍♀️`, `✭`) → regex не матчит. Строка `- [ ] 🧟‍♀️ midsommar 2019` не подпадает.
2. `title` может не совпадать буквально (год/скобки) → не матчит.
3. **Тихий провал:** нет ошибки, нет лога. `sync_down.py` вызывает `mark_queued` (строки 98, 104, 113, 122) и **не проверяет результат** → считает, что всё ок.
**Решение Alex:** снять `⬇️` там, где есть (Шиндлер, Неистовый). `[x]` у Неистового **не трогать** — это отметка просмотра.
### Почему удаляем файлами, а не через Radarr API
@@ -95,7 +116,128 @@ Radarr **не отвечает** — диск в нуле, SQLite не може
---
## Фаза 1 — Стоп-кран `MIN_FREE_GB` (главный фикс)
## Фаза 1 — Фикс `mark_queued` (корень потери меток) 🆕
**Файл:** `watchlist_sync/parser.py:77`
**Дефект:** regex ожидает название **сразу** после `- [ ]`, но в файле бывает эмодзи-маркер. Плюс тихий провал:
```python
pattern = re.compile(r'(^\s*-\s*\[ \]\s*)(' + re.escape(title) + r')', re.MULTILINE)
new_text = pattern.sub(r'\1⬇️ \2', text, count=1)
if new_text != text:
path.write_text(new_text) # ← молча ничего, если не совпало
```
**Что чинить:**
```python
# 1. Разрешить опциональные маркеры перед названием (в т.ч. ⭐ — он может стоять где угодно)
pattern = re.compile(
r'(^\s*-\s*\[ \]\s*)'
r'([🧟‍♀️✭🗓️❓⭐]\s*)?'
r'(' + escaped + r')',
re.MULTILINE
)
# 2. Возвращать bool — вставилась ли метка
# 3. При провале — log warning / raise, а не тишина
```
**Плюс:** в `sync_down.py` (строки **98, 104, 113, 122** — четыре места) **проверять результат**:
```python
if not mark_queued(watchlist, item.title):
print(f" [!] failed to mark ⬇️ for {item.title!r}")
```
**Проверка:** прогнать на копии файла → убедиться, что 3 проблемные строки (81, 82, 83) получают метку.
⚠️ Наличие `⭐` в коде уже известно (`parser.py:_clean`): *«U+2B50 may sit ANYWHERE in the title ("Простите за беспокойство ⭐ 2018")»* → проверять **всю строку**, не только конец.
---
## Фаза 3 — Фильтр ужасов + приоритет `⭐ > 🧟` (ПРАВИЛО НОВОЕ) 🆕
**🔴 Установлено фактами: правила «ужасы не качаются» в коде НЕТ вообще.**
| Компонент | Есть? | Где |
|---|---|---|
| `is_horror()` — определяет жанр | ✅ | `resolver.py:43` (по жанрам TMDB, `27` = Horror) |
| `mark_horror()` — ставит `🧟‍♀️` | ✅ | `parser.py:156`, вызов `cli.py:127` |
| **Фильтр в `sync_down`** | ❌ **ОТСУТСТВУЕТ** | `sync_down.py` не вызывает `is_horror()` — проверено по всему файлу |
`🧟‍♀️` — **только визуальная метка**. Единственный фильтр в `sync_down` — `MIN_RATING` (строка 63).
Поэтому **Midsommar скачался**, будучи помеченным `🧟‍♀️`.
**Правило, которое надо реализовать (сформулировано Alex 2026-09-21):**
| Случай | Действие |
|---|---|
| Ужас + `⭐` | **качаем** — `⭐` приоритетнее `🧟` |
| Ужас без `⭐` | **пропускаем** |
| Не ужас | качаем как обычно |
```python
def should_skip_horror(candidate, raw_line: str) -> bool:
if not candidate.is_horror():
return False
if '\u2b50' in raw_line: # ⭐ — явный приоритет пользователя
return False
return True # ужасы без ⭐ — пропускаем
```
**Что нужно:**
1. `parser.py` — читать наличие `⭐` **в любой позиции** строки → новое поле `priority: bool` в `WatchItem`
2. `sync_down.py` — перед добавлением в Radarr: `if should_skip_horror(c, item.raw): continue`
3. `cli.py` — при маркировке: ужас + `⭐` → `🧟‍♀️` **не навешивать**
---
## Фаза 4 — Восстановить потерянные `⬇️`
Три фильма без метки (после фикса `mark_queued` — правильным инструментом, не руками):
- строка **83**: `Babylon (2022)`
- строка **81**: `🧟‍♀️ midsommar 2019`
- строка **82**: `Triangle of Sadness 2022`
**Проверка:** `grep` по каждой строке → метка на месте.
---
## Фаза 5 — Вернуть крон
После того как Фазы 1–2 проверены и стоп-кран работает:
- вернуть строки `watchlist-nightly` (01:00) и `watchlist-discover` (вс 09:00) в crontab;
- **снизить `--batch` с 5 до 2**.
---
## Фаза 3b — Починить `cleanup` (отдельно, осторожно)
**Дефект:** cleanup сопоставляет `[x]` из watchlist с **Radarr-библиотекой**, а просмотренное лежит в `/media/movies` (ручные торренты). Пересечение = 0 → удаляет 0 файлов.
**Замер 2026-09-21:** `watchlist [x] items: 177` / `radarr movies with file: 28` / `nothing to delete`.
**Это не причина инцидента** — cleanup не мог занять место, он только удаляет. Расширять его — отдельная задача, идёт после Фаз 0–2.
---
## Порог `MIN_FREE_GB` — ⏸ ожидает решения Alex
Предложение: **100 ГБ**. Alex ещё не подтвердил число.
---
## Уроки
1. **Любой скрипт, ставящий закачки в очередь, ОБЯЗАН проверять свободное место до добавления.** Лимита качества недостаточно — он про тип релиза, не про размер.
2. **«Radarr молчит / I/O error» на заполненном диске — сначала проверить место**, потом конфиг и сеть.
3. **Крон в 01:00 без присмотра = диск заполняется незаметно.** Тревога при >порога не настроена: cleanup писал «nothing to delete» и молчал.
4. **Не выдавать догадки за факт.** Первая версия разбора указывала на `cleanup` как виновника — Alex поправил: cleanup удаляет, а не занимает. Виновник — `sync-down`.
5. **Функция, которая «тихо ничего не делает» при провале — источник невидимых дефектов.** `mark_queued` молчал → 3 метки потеряны, никто не заметил. Возвращать `bool` и логировать.
6. **Метка ≠ правило.** `🧟‍♀️` рисовалась, но фильтра не было — Midsommar скачался. Если метка должна что-то запрещать — запрет надо писать отдельно.
7. **Искать и по-русски, и по-латинице.** `grep -i schindler` не нашёл «Список Шиндлера» → ложный вывод «фильма нет». Проверять оба написания перед любым утверждением.
---
## Фаза 2 — Стоп-кран `MIN_FREE_GB` (главный фикс заполнения)
**Цель:** перед добавлением фильма в Radarr проверить свободное место. Если мало — не добавлять.
@@ -131,33 +273,6 @@ Alex 2026-09-21: **«лимит качества и так настроен»**.
---
## Фаза 3 — Починить `cleanup` (отдельно, осторожно)
**Дефект:** cleanup сопоставляет `[x]` из watchlist с **Radarr-библиотекой**, а просмотренное лежит в `/media/movies` (ручные торренты). Пересечение = 0 → удаляет 0 файлов.
**Замер 2026-09-21:** `watchlist [x] items: 177` / `radarr movies with file: 28` / `nothing to delete`.
**Это не причина инцидента** — cleanup не мог занять место, он только удаляет. Расширять его — отдельная задача, идёт после Фаз 0–1.
---
## Фаза 4 — Вернуть крон
После того как Фаза 1 проверена и стоп-кран работает:
- вернуть строки `watchlist-nightly` (01:00) и `watchlist-discover` (вс 09:00) в crontab;
- **снизить `--batch`** (сейчас 5) — 5 фильмов/сутки без учёта размера и есть корень инцидента.
---
## Уроки
1. **Любой скрипт, ставящий закачки в очередь, ОБЯЗАН проверять свободное место до добавления.** Лимита качества недостаточно — он про тип релиза, не про размер.
2. **«Radarr молчит / I/O error» на заполненном диске — сначала проверить место**, потом конфиг и сеть.
3. **Крон в 01:00 без присмотра = диск заполняется незаметно.** Тревога при >порога не настроена: cleanup писал «nothing to delete» и молчал.
4. **Не выдавать догадки за факт.** Первая версия разбора указывала на `cleanup` как виновника — Alex поправил: cleanup удаляет, а не занимает. Виновник — `sync-down`.
---
## Связанные заметки
- [[family/projects/watchlist-automation]] — полный pipeline, статус крона