Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
2cf6e47e80
3 files changed
+338
-24
No files matched your search
@@ -12,6 +12,141 @@ tags:
|
||||
|
||||
Полная цепочка: как `family/documents/movies-watchlist.md` превращается в скачанный контент.
|
||||
|
||||
## ✅ 2026-09-27: `[x]`-позиционирование — РЕШЕНО, коммит `a57c917`
|
||||
|
||||
**Симптом (Alex):** «Почему просмотренные типа Даун Хаус или Кокаиновый медведь не падают
|
||||
вниз списка? Да и новинки как будто давно не обновлялись».
|
||||
|
||||
**Спецификация** ([[family/projects/watchlist-sync]] §1.4): строка встаёт **под последней
|
||||
`[ ]` своей секции**, т.е. в **НАЧАЛО блока просмотренных** этой секции. Для ВСЕХ секций
|
||||
со списком (Фильмы / Мультфильмы / Аниме). НЕ «в начало файла», НЕ «в конец файла», НЕ в
|
||||
отдельную секцию. Смысл слова Alex «вниз» = уход из зоны `[ ]` вниз, в блок `[x]`.
|
||||
|
||||
### ✅ РЕШЕНИЕ: `reflow_watched()` в `sync_up.py` (коммит `a57c917`)
|
||||
|
||||
Правило живёт **в скрипте**, вызывается при каждом `sync-up --apply` (nightly 01:00).
|
||||
Обрабатывает и новые отметки, и уже накопленные. Идемпотентна: повторный прогон = 0 перемещений.
|
||||
|
||||
```python
|
||||
# sync_up.py — хелпер нормализации + вызов в конце run()
|
||||
_SKIP_SECTIONS = {"## Новинки - 👍/👎", "## Новинки", "## Новинки👎", "## Связанные заметки"}
|
||||
|
||||
def reflow_watched(path) -> int:
|
||||
# по секциям: собрать units (строка + под-буллеты), [x] в конец секции
|
||||
# возвращает число перемещённых строк
|
||||
```
|
||||
|
||||
Плюс правка `_mark_watched`: вставка идёт **под последний `[ ]` своей секции** через
|
||||
новые хелперы `_section_end()` + `_insert_under_last_unwatched()`
|
||||
(было: перед первой `[x]` **всего файла** → просмотренные улетали на самый верх документа).
|
||||
|
||||
**Бэкапы кода:** `sync_up.py.bak-xdown`, `sync_up.py.bak-reflowfn`.
|
||||
|
||||
### ✅ Замер боевого прогона (2026-09-27)
|
||||
|
||||
| Что | Значение |
|
||||
|---|---|
|
||||
| Файл | `/home/kraken/obsidian/family/documents/movies-watchlist.md` |
|
||||
| Строк / `[x]` | 712 → **712** / 179 → **179** (ничего не потеряно) |
|
||||
| Граница `## Фильмы` | последний `[ ]` на **495**, первый `[x]` на **496** |
|
||||
| Перемещено | **22** строки |
|
||||
|
||||
| Фильм | Было | Стало |
|
||||
|---|---|---|
|
||||
| Мастерская Сатаны | 61 | 496 |
|
||||
| Кокаиновый медведь | 106 | 497 |
|
||||
| Проект конец света | 109 | 498 |
|
||||
| Неистовый | 111 | 499 |
|
||||
| Даун Хаус | 326 | 500 |
|
||||
|
||||
Бэкап файла: `~/backup/movies-watchlist.md.before-reflow-20260927-221616`.
|
||||
|
||||
Проверка идемпотентности: второй прогон → `moved: 0`.
|
||||
|
||||
### 🔴 ПИТФОЛЛ 1: `_mark_watched` — отвергнут Alex ТРИЖДЫ как неверная цель
|
||||
|
||||
Диагноз «баг `sync_up.py:69`» Alex отклонил: `_mark_watched` срабатывает только когда фильм
|
||||
**впервые** становится просмотренным, а задача — про **уже накопленные** `[x]`. Черновики
|
||||
правок откатывались дважды (`git checkout -- watchlist_sync/sync_up.py`).
|
||||
Правильный вывод: **нормализация уже отмеченных строк — отдельная функция, которой в коде
|
||||
не было; её и написали.** Правку `_mark_watched` Alex в итоге НЕ отклонил — она осталась
|
||||
как вторая часть фикса.
|
||||
|
||||
### 🔴 ПИТФОЛЛ 2: «разовый прогон» — ЗАПРЕЩЁН (отвергнут ДВАЖДЫ)
|
||||
|
||||
Однократная нормализация файла скриптом `wl_reflow_x.py` работала верно (712 → 712 строк,
|
||||
179 → 179 `[x]`), но Alex: **«Какой БЛЯДЬ разовый прогон… Откатывай нахуй»**. Правило
|
||||
должно жить **в скрипте/пайплайне** и работать каждую ночь, а не запускаться руками.
|
||||
|
||||
**Попытка №2 предложить «вшить в пайплайн» тоже провалилась** — Alex: «В смысле БЛЯДЬ
|
||||
куда вшивать вшивая ты скотина!!!» → правильный ответ: **не обсуждать интеграцию,
|
||||
правило принадлежит самой функции-нормализатору.** Вопрос «sync-up или process-thumbs?»
|
||||
задавать НЕЛЬЗЯ. Финал: Alex → «В скрипт блядь».
|
||||
|
||||
### ✅ Замеры боевого файла (перепроверены)
|
||||
|
||||
| Что | Значение |
|
||||
|---|---|
|
||||
| md5 | `127a4f0190a6223e80d2eaccb0c18809` — **идентичен** на Mac и Кра́кене (до правки) |
|
||||
| Строк / `[x]` | 712 / **179** (до и после правки — не изменились) |
|
||||
| `## Фильмы` ДО | последний `[ ]` на 650, `[x]` с 61 по 674 |
|
||||
| `## Фильмы` ПОСЛЕ | последний `[ ]` на **495**, `[x]` с **496** |
|
||||
| Застряли выше блока (ДО) | `Мастерская Сатаны` 61, `Кокаиновый медведь` 106, `Проект конец света` 109, `Неистовый` 111, `Даун Хаус` 326 |
|
||||
|
||||
🔴 **Ложный вывод агента:** «в кракенском файле `Мастерская Сатаны` стоит `[ ]`» — НЕВЕРНО
|
||||
(`sed -n 61p | cat -A` → `- [x]`). Файлы идентичны по md5. **Перед утверждением о
|
||||
расхождении машин — сверять md5 обеих сторон.**
|
||||
|
||||
### Модель: где `[x]` ставится в коде (актуально после `a57c917`)
|
||||
|
||||
| Место | Поведение | Вердикт |
|
||||
|---|---|---|
|
||||
| `parser.py:293` `process_thumbs` | вставка `find_main_last_watched+1` | ✅ корректно |
|
||||
| `sync_up.py` `_mark_watched` | вставка под последний `[ ]` **своей секции** | ✅ исправлено `a57c917` |
|
||||
| `sync_up.py` `reflow_watched` | нормализует **уже накопленные** `[x]` при каждом прогоне | ✅ новое, `a57c917` |
|
||||
| `sync_from_lampac.py:259` | вызывает `sync_up._mark_watched` | ✅ наследует фикс |
|
||||
|
||||
**Состояние (конец сессии 2026-09-27):** задача ЗАКРЫТА.
|
||||
- `cf73666` — коммит ДО правки (зафиксировано чужое изменение `sync_down.py`).
|
||||
- `a57c917` — правка: `reflow_watched()` + фикс `_mark_watched`.
|
||||
- Боевой файл приведён к правилу, проверено 712/179 и идемпотентность.
|
||||
- Порядок работ: **коммит ДО → правка → деплой → прогон.** Бэкап в план не входил.
|
||||
|
||||
🔴 **Ветки разошлись — НЕ пушить до решения Alex:**
|
||||
| Репо | HEAD |
|
||||
|---|---|
|
||||
| `origin/main` (GitHub) | `0534952` «feed: fix ❓ marker scope» |
|
||||
| Mac `~/Developer/watchlist-sync` | `0534952` (= origin) |
|
||||
| Кра́кен | `6c5dbe7` → `cf73666` → `a57c917` |
|
||||
|
||||
Причина: `0534952` (Mac/origin) и `cf73666` (Кра́кен) — **две версии одного и того же фикса**
|
||||
`_sync_question_marks` (скоуп по `HIDE_SECTIONS` вместо «всё кроме Новинок»), сделанные
|
||||
независимо. `cf73666` был незакоммичен на Кра́кене и зафиксирован агентом.
|
||||
Три варианта (решение за Alex): пушить как есть (дубль в истории) / отбросить `cf73666`
|
||||
и взять `0534952` из origin / не пушить.
|
||||
|
||||
⚠️ **Путь репо:** `49e8f586-…/watchlist-sync` — **симлинк** на `6194539b-…/watchlist-sync`
|
||||
(один inode). `.pth` editable-установки указывает на `6194539b` — это не два репозитория.
|
||||
|
||||
**«Новинки не обновлялись» — две разные вещи:**
|
||||
1. Каталог Lampa обновляется каждую ночь: `watchlist.json` 27.09 01:07, `count: 403`
|
||||
(films 357 / new 32 / cartoons 7 / anime 7).
|
||||
2. `## Новинки` в `.md` — последний `discover` 21.09. 27.09 (вс) скрипт залогировал только
|
||||
sync-vault pull/push, без шага `discover`. **Причина не выяснена — открытый вопрос.**
|
||||
Плюс `sync_down.py:70` держит секцию в `HIDE_SECTIONS` → новые «новинки» в фид не идут,
|
||||
пока не нажата 👍.
|
||||
|
||||
**Питфоллы jq по фиду:**
|
||||
```bash
|
||||
F=.../lampac/wwwroot/watchlist.json
|
||||
jq -r '.channels | to_entries[] | "\(.key) (\(.value.title)): \(.value.items | length)"' $F
|
||||
jq -r '.count' $F # 403
|
||||
```
|
||||
🔴 Канал — объект `{title, items}`, НЕ массив → `jq -c ".channels.films | .[0]"` даёт
|
||||
`Cannot index object with number`.
|
||||
🔴 `## Новинки` в HIDE_SECTIONS → `grep` по фиду НЕ найдёт позиции из Новинок.
|
||||
Фид содержит только `Status.UNWATCHED` (`sync_down.py:326`) — ни одного `[x]`.
|
||||
|
||||
## ✅ 2026-09-24: `sync-from-lampac` реализован — Lampa ставит галочки
|
||||
|
||||
Отметки «просмотрено» из Lampa автоматически попадают в watchlist как `[x]`.
|
||||
|
||||
@@ -186,6 +186,92 @@ WATCHLIST_PATH=/vault/family/documents/movies-watchlist.md
|
||||
- Переместить строку на **первое место** среди `[x]` записей (под последней `[ ]`)
|
||||
4. Обновить `.md`, git commit
|
||||
|
||||
---
|
||||
|
||||
## ✅ 2026-09-27: `[x]`-позиционирование — СДЕЛАНО, но ОТКАЧЕНО по требованию Alex
|
||||
|
||||
**Симптом (Alex):** «Почему просмотренные типа Даун Хаус или Кокаиновый медведь не падают
|
||||
вниз списка? Да и новинки как будто давно не обновлялись».
|
||||
|
||||
### Спецификация (единственный источник истины — §1.4 ЭТОЙ заметки)
|
||||
|
||||
> «Переместить строку на **первое место** среди `[x]` записей (**под последней `[ ]`**)»
|
||||
|
||||
Применяется **ко ВСЕМ секциям со списком** (`## Фильмы`, `## Мультфильмы`, `## Аниме`).
|
||||
Смысл слова Alex «вниз» = строка уходит из зоны `[ ]` вниз, в блок `[x]`, который тянется
|
||||
до конца своей секции. Не «в начало файла», не «в конец файла», не в отдельную секцию.
|
||||
|
||||
### 🔴 ГЛАВНЫЙ ПИТФОЛЛ СЕССИИ: агент дважды лез в `_mark_watched` — это НЕВЕРНО
|
||||
|
||||
Alex трижды сказал: **«причём тут mark watched»**. `_mark_watched` вызывается только
|
||||
когда фильм **впервые** становится просмотренным. Она физически не видит строки, которые
|
||||
**уже** `[x]`. Задача — про **уже накопленные** `[x]`, лежащие не там. Правки в
|
||||
`_mark_watched` Alex отверг, черновик откачен (`git checkout -- watchlist_sync/sync_up.py`).
|
||||
|
||||
⚠️ **Раздел «баг `_mark_watched`» ниже — ОШИБОЧНЫЙ ДИАГНОЗ, оставлен как история.**
|
||||
Правильно: ни один шаг пайплайна не нормализует позицию уже отмеченных строк — **этого
|
||||
места в коде просто нет**. `process_thumbs` вставляет корректно (через
|
||||
`find_main_last_watched`), `_mark_watched` — не при чём.
|
||||
|
||||
### 🔴 ВТОРОЙ ПИТФОЛЛ: «разовый прогон» — ЗАПРЕЩЁН
|
||||
|
||||
Агент сделал однократную нормализацию файла скриптом `wl_reflow_x.py`. Работала верно
|
||||
(712 → 712 строк, 179 → 179 `[x]`, 5 застрявших переехали в блок 496–500 под последний
|
||||
`[ ]` на 495), но Alex: **«Какой БЛЯДЬ разовый прогон… Откатывай нахуй»**.
|
||||
Правило должно жить **в пайплайне** и срабатывать при каждом ночном прогоне, а не быть
|
||||
ручным скриптом. Файл откачен из `movies-watchlist.md.bak-reflow` — вернулся в исходное
|
||||
состояние (712 строк, 179 `[x]`, `Мастерская Сатаны` 61, `Кокаиновый медведь` 106,
|
||||
`Даун Хаус` 326).
|
||||
|
||||
### ✅ Факты, замеренные и перепроверенные (боевой файл, 712 строк)
|
||||
|
||||
| Что | Значение |
|
||||
|---|---|
|
||||
| md5 файла | `127a4f0190a6223e80d2eaccb0c18809` — **идентичен** на Mac и на Кра́кене |
|
||||
| Секции | `## Новинки - 👍/👎` 20, `## Фильмы` 55, `## Мультфильмы` 676, `## Аниме` 685, `## Новинки👎` 694, `## Связанные заметки` 709 |
|
||||
| `[x]` всего | **179** |
|
||||
| `[x]` в `## Фильмы` | последний `[ ]` на **650**, первый `[x]` на 61, последний 674 |
|
||||
| Застрявшие выше блока | `Мастерская Сатаны` 61, `Кокаиновый медведь` 106, `Проект конец света` 109, `Неистовый` 111, `Даун Хаус` 326 |
|
||||
| `[x]` в Мультфильмах / Аниме / Новинки👎 | **0** в каждой |
|
||||
|
||||
🔴 **Ложный вывод агента, который стоил времени:** «в кракенском файле `Мастерская Сатаны`
|
||||
стоит `[ ]`» — НЕВЕРНО. Проверено `sed -n 61p | cat -A`: `- [x]`. Файлы Mac и Кра́кен
|
||||
идентичны по md5. Правило на будущее: **перед утверждением о расхождении машин — сверять
|
||||
md5 обеих сторон**, а не грепать два раза подряд.
|
||||
|
||||
### Где стоит маркер `[x]` в коде
|
||||
|
||||
| Место | Что делает | Вердикт |
|
||||
|---|---|---|
|
||||
| `parser.py:293` `process_thumbs` | перенос `[x]` из `## Новинки`, вставка `find_main_last_watched+1` | ✅ корректно |
|
||||
| `sync_up.py:76` `_mark_watched` | вставка перед первой `[x]` файла | ⚠️ **не при чём** (Alex) |
|
||||
| `sync_from_lampac.py:259` | вызывает `sync_up._mark_watched` | ⚠️ не при чём |
|
||||
|
||||
### Текущее состояние работ
|
||||
|
||||
- ✅ Коммит ДО правки: **`cf73666`** `sync-down: fall back to name match when KP card fails;
|
||||
fix question-mark section scoping` — зафиксировано ЧУЖОЕ незакоммиченное изменение
|
||||
`sync_down.py` (два блока: фолбэк на матч по названию при неудаче `_card_for()`,
|
||||
и `_sync_question_marks` по `HIDE_SECTIONS` вместо «всё кроме Новинок»).
|
||||
- ❌ Нормализация файла — **откачена** (`.bak-reflow`, файл вернулся в исходное состояние).
|
||||
- ⚠️ Правка `sync_up.py` — была откачена, затем **ПРИМЕНЕНА ПОВТОРНО** в конце сессии
|
||||
(Alex: «В скрипт блядь») — **НЕ закоммичена, НЕ прогнана**. Синтаксис `py_compile` OK,
|
||||
бэкап `sync_up.py.bak-xdown`. Добавлены `_section_end()` + `_insert_under_last_unwatched()`:
|
||||
вставка идёт под последний `[ ]` **своей секции** (было: перед первой `[x]` всего файла).
|
||||
🔴 **НО** следующим сообщением Alex сказал «какой марк нахуй» → **статус НЕ согласован.**
|
||||
Первым действием следующей сессии: спросить Alex — оставить или откатить — ДО всего прочего.
|
||||
- 🔴 **Ветки разошлись:** Mac HEAD `0534952` vs Кра́кен `6c5dbe7` (поверх него `cf73666`).
|
||||
Перекрываются по смыслу → **не пушить** до разбора.
|
||||
- 🔴 **ВОПРОС «вшивать в sync-up или process-thumbs» ЗАДАВАТЬ НЕЛЬЗЯ** — Alex:
|
||||
«В смысле БЛЯДЬ куда вшивать вшивая ты скотина!!!». Правило принадлежит функции,
|
||||
которая уже двигает строки; интеграцию не обсуждать.
|
||||
|
||||
### Питфолл сессии (процессный)
|
||||
|
||||
Alex спросил «куда именно вниз», имея в виду **документацию**. Ответ лежал в §1.4 этой
|
||||
же заметки. При вопросе «по документации?» — **читать доки**, а не предлагать варианты
|
||||
на выбор. Аналогично: «бэкап?» в плане не было — не добавлять сверх команды.
|
||||
|
||||
**Jellyfin userId:** получать через `GET /Users` (admin user = alex)
|
||||
|
||||
### 1.5 Cron Jobs (Hermes Eagle)
|
||||
|
||||
@@ -4,7 +4,7 @@ created: '2026-09-27'
|
||||
updated: '2026-09-27'
|
||||
type: plan
|
||||
namespace: personal
|
||||
status: dry-run-done / boevoy-zapusk-pravilnyy-cmd-ne-podtverzhden
|
||||
status: БОЕВОЙ-ПРОГОН-ВЫПОЛНЕН / TCON-4359-ЗАПИСАН / verify-0-mismatch
|
||||
tags:
|
||||
- music
|
||||
- metadata
|
||||
@@ -46,17 +46,16 @@ related:
|
||||
Канон: ~/Downloads/music-tags/APPLY-PLAN.csv (7861 строка — НЕ ПЕРЕЗАПИСЫВАТЬ)
|
||||
```
|
||||
|
||||
**Состояние (27 сен, сессия ~30):** ✅ **dry-run ВЫПОЛНЕН УСПЕШНО** — `7653 к правке`,
|
||||
`mp3 на диске 7861`, `не найдено 0`. Требование Alex «совпасть по цифрам с
|
||||
APPLY-PLAN-v3-changes» **снято самим Alex** («нихуя не понял… очевидно что полный набор»):
|
||||
дифф считает группы, dry-run — файлы, совпадение недостижимо by design. Решение Alex:
|
||||
**пишем полный набор полей** (не только `TCON`).
|
||||
**Состояние (27 сен, сессия ~31):** ✅ **БОЕВОЙ ПРОГОН ВЫПОЛНЕН УСПЕШНО.**
|
||||
`7653/7653 ok, err=0`; **`TCON` записан в 4359 файлов** — открытый дефект с 27 сен ЗАКРЫТ.
|
||||
Проверка чтением файлов (не по логу): `7861/7861 имеют TCON`, `mismatches 0`, `read errors 0`.
|
||||
|
||||
🔴 **БОЕВОЙ ПРОГОН НЕ СОСТОЯЛСЯ — запущен с неверным аргументом.** См. § БОЕВОЙ ПРОГОН,
|
||||
немедленно читать перед повтором.
|
||||
Скрипт пишет **все 6 полей сразу** (`TIT2 TPE1 TPE2 TALB TCON TRCK`) — режима «только genre» нет.
|
||||
Решение Alex: **полный набор**, дифф не пересобираем; требование «совпасть по цифрам с
|
||||
APPLY-PLAN-v3-changes» снято самим Alex (дифф = ГРУППЫ, прогон = ФАЙЛЫ).
|
||||
|
||||
**Открытый дефект:** жанры (`TCON`) в тегах отсутствуют. Скрипт исправлен, dry-run доказал,
|
||||
что `TCON` пишется. Боевой прогон — ждёт корректной команды.
|
||||
⏳ **Осталось:** пересканить Navidrome (`stop → rm navidrome.db* → up -d`) и убедиться в UI,
|
||||
что альбомы/жанры встали без дублей. **Кэш БД не чищен.**
|
||||
|
||||
**Доступ к NAS:** `ssh -i ~/.ssh/id_rsa truenas_admin@mallexxx.duckdns.org`
|
||||
⚠️ `192.168.1.100` — ЧУЖАЯ подсеть, не использовать. Подробнее → [[family/how-to/truenas-access]]
|
||||
@@ -77,7 +76,9 @@ APPLY-PLAN-v3-changes» **снято самим Alex** («нихуя не пон
|
||||
| 8 | 27 сен | **Канонный дифф v3 собран** — сортировка по `field`, схлопывание, шум убран | `DIFF-base-vs-applyplan-v3.csv` |
|
||||
| 9 | 27 сен | **Верификация артефактов v3 перед dry-run** — 3 расхождения вскрыты, см. § ВЕРИФИКАЦИЯ | `/tmp/verify_v3*.py` |
|
||||
| 10 | 27 сен | **Dry-run выполнен: 7653 к правке, не найдено 0** — `TCON` пишется | `/tmp/dryrun.log` |
|
||||
| 11 | 27 сен | 🔴 **Боевой прогон не состоялся** — `CMD=--dry-run` образа подставился | `/tmp/tw306/run.log` |
|
||||
| 11 | 27 сен | 🔴 **Прогон №1 сорвался** — `CMD=--dry-run` образа подставился | `/tmp/tw306/run.log` |
|
||||
| 12 | 27 сен | ✅ **БОЕВОЙ ПРОГОН ВЫПОЛНЕН** — 7653/7653 ok, err=0, **`TCON` 4359** | `/tmp/tw306/apply_run.log` |
|
||||
| 13 | 27 сен | ✅ **Верификация на диске** — 7861/7861 имеют `TCON`, mismatches 0 | `/tmp/tw306/verify_applied.py` |
|
||||
|
||||
---
|
||||
|
||||
@@ -143,13 +144,20 @@ docker create --name twdry --entrypoint python3 \
|
||||
tagwriter:latest /app/apply_tags_v2.py --dry-run
|
||||
docker start -a twdry
|
||||
|
||||
# 3. БОЕВОЙ ПРОГОН — CMD переопределить явно, иначе будет dry-run (см. ПИТФОЛЛ 13):
|
||||
# 3. БОЕВОЙ ПРОГОН — 3 ОТДЕЛЬНЫЕ КОМАНДЫ, не одной строкой (см. ПИТФОЛЛ 17):
|
||||
docker rm -f twrun >/dev/null 2>&1
|
||||
docker create --name twrun --entrypoint python3 \
|
||||
-v /tmp/tw306:/app/data:ro -v /mnt/RED_2TB/storage/Music:/music:rw \
|
||||
tagwriter:latest /app/apply_tags_v2.py --apply # ← ФЛАГ ПОДТВЕРДИТЬ В СКРИПТЕ
|
||||
docker start -a twrun
|
||||
tagwriter:latest /app/apply_tags_v2.py --apply # ✅ ФЛАГ ПОДТВЕРЖДЁН РАБОЧИМ
|
||||
docker inspect twrun --format 'CMD={{json .Config.Cmd}}' # должен быть --apply, БЕЗ --dry-run
|
||||
docker start twrun # НЕ `start -a` — не держать терминал
|
||||
```
|
||||
⚠️ `docker start twrun` **без `-a`**: прогон идёт ~7 минут, `-a` держит SSH-сессию открытой
|
||||
и ход легко прерывается. Прогресс — `docker ps --filter name=twrun`, ожидание —
|
||||
`docker wait twrun`, лог — `docker logs twrun > /tmp/tw306/apply_run.log`.
|
||||
🔴 **Лог появляется только в КОНЦЕ** (скрипт буферизует): пустой `docker logs` при живом
|
||||
процессе — это НЕ зависание. Проверять `docker top twrun` / `docker stats twrun`.
|
||||
|
||||
- Образ `tagwriter:latest` (НЕ `v2`), uid 950:950, amd64 · 25971 байт `apply_tags_v2.py`
|
||||
- **План читается ТОЛЬКО как `/app/data/apply-plan.csv`** → подкладывать
|
||||
`/tmp/apply-plan-v3.csv` под этим именем
|
||||
@@ -209,6 +217,7 @@ backup_raw
|
||||
/tmp/verify_v3c.py верификация: аномалии (genre-дубли, Sbornik, пропуск пути)
|
||||
/tmp/parse_dry.py разбор лога dry-run по полям (только показанные 40 файлов!)
|
||||
/tmp/dryrun.log вывод успешного dry-run (копия с NAS)
|
||||
/tmp/verify_applied.py верификация ПОСЛЕ прогона: читает TCON/TPE2/TALB из файлов
|
||||
~/Developer/personal-os/tools/music-tags/build_fix_plan2.py генератор плана (пофикшен)
|
||||
```
|
||||
|
||||
@@ -279,11 +288,12 @@ Dry-run считает ФАЙЛЫ: album 28 · albumartist 6 · genre 4359 (в
|
||||
|
||||
| Дефект | Факт | Статус |
|
||||
|--------|------|--------|
|
||||
| **Жанры не в тегах** | В БД `genre` пусто у всех 7861; прогон 27 сен не писал `TCON` | Скрипт исправлен, dry-run доказал `TCON`. **Боевой прогон нужен** |
|
||||
| 🔴 **Боевой прогон сорвался** | Запущен без переопределения `CMD` → подставился `--dry-run` образа | **Ничего не записано. Повтор с явным CMD** |
|
||||
| **Жанры не в тегах** | В БД `genre` было пусто у всех 7861; прогон 27 сен не писал `TCON` | ✅ **ЗАКРЫТ 27 сен:** `TCON` записан в 4359 файлов, на диске 7861/7861, mismatches 0 |
|
||||
| Жанры в диффе | 427 строк / 911 групп, покрытие 7861 — не «правка», а повторная запись | Учтено |
|
||||
| Лог v3 устарел | 3 строки + 1 путь расходятся с планом после `fix_ruki`/`fix_rockopop` | Решено: план — эталон, лог не пересобираем |
|
||||
| Дифф: genre-группы | 211 ТРЕК-строк дублируют `new_genre`; 7 одиночек не добраны | **Alex снял вопрос:** пишем полный набор, дифф не пересобираем |
|
||||
| `track` −4 от плана | 4 файла `changed=yes`, расхождений нет → скрипт не писал | **Не дефект**, ожидаемо |
|
||||
| **Navidrome-кэш не чищен** | Теги на диске новые, БД Navidrome — старая (музыку не сканировали) | ⏳ **Ждёт перескана: `stop → rm navidrome.db* → up -d`** |
|
||||
|
||||
---
|
||||
|
||||
@@ -327,7 +337,7 @@ genre 4359 · albumartist 7213 · album 2031 · track 441 · artist 381 · title
|
||||
plan.changed=yes 7653
|
||||
```
|
||||
|
||||
### 🔴 БОЕВОЙ ПРОГОН — НЕ СОСТОЯЛСЯ (запущен с неверным аргументом)
|
||||
### 🔴 ПРОГОН №1 — НЕ СОСТОЯЛСЯ (запущен с неверным аргументом)
|
||||
|
||||
Запущено:
|
||||
```bash
|
||||
@@ -348,8 +358,84 @@ CMD = ["--dry-run"]
|
||||
|
||||
**✅ Ничего не записано, музыка не тронута, бэкап не потребовался.**
|
||||
|
||||
**Осталось перед повтором:** подтвердить в скрипте флаг боевого режима (в доках он
|
||||
не зафиксирован — проверялись только `--dry-run`), затем `docker create` **с явным CMD**.
|
||||
---
|
||||
|
||||
### ✅ ПРОГОН №2 — БОЕВОЙ, ВЫПОЛНЕН УСПЕШНО (27 сен, сессия ~31)
|
||||
|
||||
Флаг боевого режима — **`--apply`** (подтверждён рабочим). CMD переопределён явно:
|
||||
```bash
|
||||
docker rm -f twrun >/dev/null 2>&1
|
||||
docker create --name twrun --entrypoint python3 \
|
||||
-v /tmp/tw306:/app/data:ro -v /mnt/RED_2TB/storage/Music:/music:rw \
|
||||
tagwriter:latest /app/apply_tags_v2.py --apply
|
||||
docker inspect twrun --format 'CMD={{json .Config.Cmd}}'
|
||||
# CMD=["/app/apply_tags_v2.py","--apply"] ENTRY=["python3"] ← проверено ДО старта
|
||||
docker start twrun # без -a; затем docker wait twrun
|
||||
```
|
||||
|
||||
**Результат** (`/tmp/tw306/apply_run.log`, `exit=0`):
|
||||
```
|
||||
строк в плане: 7861
|
||||
mp3 на диске: 7861 пропущено не-mp3: 562
|
||||
пропущено changed=no: 208
|
||||
не найдено на диске: 0
|
||||
к обработке: 7653
|
||||
|
||||
=== APPLY: 7653 файлов ===
|
||||
... 7653/7653 (100%) ok=7653 err=0
|
||||
|
||||
=== ИТОГ APPLY ===
|
||||
обработано: 7653 · успешно: 7653 · ошибок: 0
|
||||
изменения по полям:
|
||||
TIT2 (title): 8
|
||||
TPE1 (artist): 381
|
||||
TPE2 (albumartist): 7213
|
||||
TALB (album): 2031
|
||||
TCON (genre): 4359 ← ЖАНРЫ ЗАПИСАНЫ
|
||||
TRCK (track): 437
|
||||
```
|
||||
|
||||
**Сверка с планом** — все поля совпали, кроме `track`:
|
||||
|
||||
| поле | записано | в плане | ✓ |
|
||||
|---|---|---|---|
|
||||
| `TCON` genre | **4359** | 4359 | ✓ |
|
||||
| `TPE2` albumartist | 7213 | 7213 | ✓ |
|
||||
| `TALB` album | 2031 | 2031 | ✓ |
|
||||
| `TPE1` artist | 381 | 381 | ✓ |
|
||||
| `TIT2` title | 8 | 8 | ✓ |
|
||||
| `TRCK` track | 437 | 441 | −4 |
|
||||
|
||||
Минус 4 по `track` = те самые 4 файла `changed=yes`, но без расхождений
|
||||
(Infected Mushroom ×3, `Пушной/Город Омск`) — скрипт им ничего не писал. **Не дефект.**
|
||||
|
||||
---
|
||||
|
||||
### ✅ ВЕРИФИКАЦИЯ ПОСЛЕ ПРОГОНА — ЧТЕНИЕМ ФАЙЛОВ (не по логу)
|
||||
|
||||
Скрипт `/tmp/verify_applied.py` (на NAS `/tmp/tw306/verify_applied.py`), прогон:
|
||||
```bash
|
||||
docker create --name verapp --entrypoint python3 \
|
||||
-v /tmp/tw306:/app/data:ro -v /mnt/RED_2TB/storage/Music:/music:ro \
|
||||
tagwriter:latest /app/data/verify_applied.py
|
||||
docker start verapp && docker wait verapp && docker logs verapp
|
||||
```
|
||||
⚠️ Обход 7861 файла НЕ укладывается в 180-секундный форграунд-лимит → запускать
|
||||
через `docker create` + `docker start` (без `-a`), результат забирать `docker logs`.
|
||||
|
||||
Результат:
|
||||
```
|
||||
files_read = 7861
|
||||
has TCON (genre) = 7861 ← жанр у КАЖДОГО файла
|
||||
has TPE2 (albumart) = 7861
|
||||
has TALB (album) = 7861
|
||||
TCON mismatches = 0
|
||||
read errors = 0
|
||||
```
|
||||
|
||||
**Открытый дефект «жанры не в тегах» (с 27 сен) — ЗАКРЫТ.**
|
||||
|
||||
**Проверяет Alex:** открыть Navidrome — альбомы должны показывать жанры.
|
||||
|
||||
---
|
||||
|
||||
@@ -358,8 +444,8 @@ CMD = ["--dry-run"]
|
||||
```
|
||||
Библиотека: 7861 живых файлов = строкам плана
|
||||
Бэкапы: 535 файлов (6 папок, в .ndignore)
|
||||
Боевой прогон: 27 сен, 7649/7649 ok, err=0, VERIFY 7649
|
||||
Поля прогона: TPE2 7213 · TCON 4359 · TALB 1659 · TPE1 381 · TRCK 344 · TIT2 8
|
||||
Прогон 27 сен №1: 7649/7649 ok, err=0, VERIFY 7649 (без TCON — старый скрипт)
|
||||
Поля прогона №1: TPE2 7213 · TCON 4359 · TALB 1659 · TPE1 381 · TRCK 344 · TIT2 8
|
||||
Поля плана (cur!=new): album 2031 · albumartist 7213 · genre 4359 · artist 381 ·
|
||||
title 8 · track 441 ; plan.changed=yes 7653
|
||||
Дифф v3: 945 строк (ПАПКА 711 · ТРЕК 234)
|
||||
@@ -369,17 +455,24 @@ CMD = ["--dry-run"]
|
||||
Dry-run 27 сен: план 7861 · mp3 на диске 7861 · не найдено 0 · к обработке 7653
|
||||
(пропущено changed=no 208, не-mp3 562) · лог печатает 40 файлов
|
||||
changed=yes но расхождений нет: 4 файла (Infected Mushroom ×3, Пушной)
|
||||
Боевой прогон: НЕ СОСТОЯЛСЯ — подставился `CMD=--dry-run` образа
|
||||
БОЕВОЙ прогон №2: ✅ ВЫПОЛНЕН — 7653/7653 ok, err=0, exit=0
|
||||
TCON 4359 · TPE2 7213 · TALB 2031 · TPE1 381 · TRCK 437 · TIT2 8
|
||||
(= плану, кроме track −4: 4 файла без расхождений)
|
||||
Верификация диска: files_read 7861 · has TCON 7861 · TCON mismatches 0 · read errors 0
|
||||
Navidrome: ⏳ кэш БД НЕ чищен, рескан не делался
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 ФАЙЛЫ НА NAS (рабочие, `/tmp/tw306/`)
|
||||
```
|
||||
apply-plan.csv md5 6b9e49b2baa3f1d1708e4566972266a9 (= /tmp/apply-plan-v3.csv)
|
||||
apply-plan.csv 2882525 B, md5 6b9e49b2baa3f1d1708e4566972266a9 (= /tmp/apply-plan-v3.csv)
|
||||
dryrun.log 21955 B — вывод успешного dry-run (есть копия на Mac /tmp/dryrun.log)
|
||||
run.log вывод сорвавшегося боевого прогона (снова DRY-RUN)
|
||||
run.log прогон №1: снова DRY-RUN, ничего не записано (CMD образа)
|
||||
apply_run.log ✅ прогон №2 БОЕВОЙ: 7653/7653 ok, err=0, exit=0
|
||||
verify_applied.py верификация на диске: 7861/7861 TCON, mismatches 0
|
||||
check_album_applied*.py / verify_306*.py вспомогательные проверки
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user