diff --git a/personal/plans/tagwriter-container.md b/personal/plans/tagwriter-container.md index 4c96517d..17fa869f 100755 --- a/personal/plans/tagwriter-container.md +++ b/personal/plans/tagwriter-container.md @@ -4,7 +4,7 @@ namespace: personal related: - '[[personal/plans/music-tags-wave38-fixes]]' - '[[personal/tech/music-tags-repair-truenas]]' -status: applied-verifying +status: applied-delta-closed tags: - music - truenas @@ -17,9 +17,69 @@ updated: '2026-09-26' --- # tagwriter — контейнер применения тегов MP3 (TrueNAS) -_Создан: 2026-09-26. **Статус: ✅ APPLY ВЫПОЛНЕН — 7041 файл, 0 ошибок. 🔴 НАЙДЕН ДЕФЕКТ ПЛАНА: 353 строки с ошибочным `action=no_change` (cur != new). MISSING 83 = 82 не-MP3 + 1 (ни одного потерянного MP3). MISMATCH 212 → факт-чек по диску: 165 реальных правок, 45 ложных, 2 мусор. Бэкапы: `backup/` 7041 файл 42 ГБ, `backup_raw/` 70 файлов 386 МБ. ⏭ ЖДЁТ РЕШЕНИЯ A/B/C: 75 правок «удалить TRCK». Далее — apply дельта-правок + конвертация не-MP3 → MP3.**_ +_Создан: 2026-09-26. **Статус (обновлён 2026-09-26, вечер): ✅ APPLY 7041 + ✅ ДЕЛЬТА-ПРАВКИ 165/165 (readback 0 расхождений) + ✅ МУСОР `._*` ВЫЧИЩЕН (29 удалено, 0 осталось) + ⏳ КОНВЕРТАЦИЯ не-MP3 ЗАБЛОКИРОВАНА DRM (28 файлов WMA защищены Windows Media DRM, `License_URL ... DRM`, decode error rate 0.99). Решение Alex по TRCK = **B** (номера не удалять). Бэкапы: `backup/` 7041 файл 42 ГБ · `backup_raw/` 70 файлов 386 МБ · `backup_fix/` 165 файлов. Образ пересобран с ffmpeg 8.1.2.**_ _Основание: [[personal/plans/music-tags-wave38-fixes]]._ +## 🆕 СОСТОЯНИЕ НА КОНЕЦ 2026-09-26 (последние шаги сессии) + +| Шаг | Статус | +|---|---| +| **Решение Alex по 75 правкам «удалить TRCK»** | ✅ **B — где `new_track` пустой, TRCK НЕ трогаем** (Alex: «это косяк плана, не надо удалять номер трека») | +| **Решение Alex по `._*` мусору** | ✅ **удалять** | +| **`rebuild_final.py`** | ✅ пересобрал `final-update.csv` с правилом B: **165 строк**, поля TRCK 53 · TPE1 98 · TALB 29 · TIT2 25 | +| **Бэкап 165** | ✅ → `/mnt/RED_2TB/storage/Music/backup_fix/` (165 файлов, размеры сверены) | +| **APPLY 165 (`apply_fix165.py --apply`)** | ✅ **обновлено 165, ошибок 0** | +| **READBACK 165** | ✅ **совпало 165/165, расхождений 0** | +| **Удаление `._*` мусора (`del_junk.py --apply`)** | ✅ **29 удалено, ошибок 0, `._*` в Music осталось 0** | +| **Пересборка образа с ffmpeg** | ✅ `apk add --no-cache ffmpeg` → ffmpeg **8.1.2**, mutagen **1.47.0** | +| **DRY-RUN конвертации 70 не-MP3** | ⚠️ **28 ошибок** — WMA c **Windows Media DRM** | +| **Диагностика `probe_convert.py`** | ⏳ запущена: классификация 70 файлов → ok / drm / corrupt | +| **APPLY конвертации** | ⛔ **НЕ ЗАПУСКАТЬ** до разбора DRM-файлов | +| **Приёмка в Jellyfin** | ⏳ ждёт Alex | +| **Обновление доков** | ✅ этот документ + `personal/tech/music-tags-repair-truenas.md` | + +### 🔴 БЛОКЕР КОНВЕРТАЦИИ: Windows Media DRM в `.wma` + +Первый dry-run `convert_nonmp3.py` дал **28 FFMPEG_FAIL**. Причина из stderr: + +``` +License_URL : http://go.microsoft.com/fwlink/?prd=816&pver=7.1&sbp=DRM&plcid=0x409&clcid=0x409&ar=PersonalV2 +[dec:wmav2] Decode error rate 0.994975 exceeds maximum 0.666667 +Conversion failed! +``` + +Файлы НТЛ `wma/Track 1–13.wma` **защищены Windows Media DRM**: декодер получает мусор +(99.5 % ошибок) вместо аудио. **Это не сбой конвейера — контент защищён, конвертация технически +невозможна без снятия DRM.** Оригиналы в `backup_raw/` есть, ничего не потеряно. + +**Проверка форматов (по логу dry-run):** ошибки затронули `.wma`; `.ogg`/`.m4a`/`.flac` в списке +ошибок не фигурировали так массово — точная разбивка даётся `probe_convert.py` +(классы `ok` / `drm` / `corrupt` / `other`, отчёт `/app/data/convert-probe.json`). + +**Правило:** перед конвертацией формата с DRM — сначала probe каждого файла, потом конвертация +только класса `ok`. DRM-файлы оставить как есть (или по решению Alex — удалить/перекодировать иначе). + +### 📄 `final-update.csv` — 165 правок (решение B) + +Колонки: `path,set_title,set_artist,set_album,set_track,diffs`. Правило B реализовано так: +если `new_track` пустой — ключ `TRCK` **вообще исключается** из сравнения (номер на диске остаётся). +Пустые `set_*` при apply **пропускаются** (не затирают тег). + +Запуск (одна команда — бэкап + apply + readback): + +```bash +cd /mnt/RED_2TB/docker/tagwriter +docker compose --profile tools run --rm \ + -v /mnt/RED_2TB/docker/tagwriter/apply_fix165.py:/app/apply_fix165.py:ro \ + --entrypoint python tagwriter /app/apply_fix165.py --apply +``` + +### 🧹 `del_junk.py` — чистка `._*` + +Читает `junk-files.json` (29 путей), удаляет **только** элементы списка, имя обязано начинаться +с `._`, `assert` против `backup*`. Поддерживает файлы и папки (`shutil.rmtree` для +`._Savant - Vybz`). Без `--apply` — dry-run. Результат: 29 удалено, остаток 0. + ## Задача Применить `tag-fix-plan.csv` (7905 строк) к MP3 на `/storage/Music`, **без пересжатия аудио**, @@ -98,11 +158,15 @@ docker run --rm -u 0 -v /mnt/RED_2TB/docker:/docker alpine:latest sh -c \ 8. ✅ **Бэкап не-MP3** — `backup_nonmp3.py`: **70 файлов, 386 МБ → `/music/backup_raw/`**. 9. 🔴 **НАЙДЕН ДЕФЕКТ ПЛАНА** — 353 строки с ложным `action=no_change` (см. § ГЛАВНЫЙ ДЕФЕКТ). 10. ✅ **ФАКТ-ЧЕК 212 MISMATCH** — `build_update_plan.py` + `fact_check_212.py`: **165 реальных правок**, 45 ложных, 2 мусор (см. § ФАКТ-ЧЕК). -11. 🔴 **ОТКРЫТЫЙ ВОПРОС: 75 правок «удалить TRCK»** — ждёт `A`/`B`/`C` от Alex (см. § ОТКРЫТЫЙ ВОПРОС). -12. ⏳ **Apply дельта-правок (165)** — после ответа Alex (бэкап уже есть). -13. ⏳ **Конвертация не-MP3 → MP3** — план готов (ffmpeg в образ, VBR V0, удаление оригиналов после проверки бэкапа). **Ждёт `go`.** -14. ⏳ **Приёмка в Jellyfin** (глазами Alex). -15. ✅ **Обновить техдок** `personal/tech/music-tags-repair-truenas.md` — **сделано.** +11. ✅ **Ответ Alex по TRCK = B** («косяк плана, не надо удалять номер трека») + `._*` удалять. +12. ✅ **`rebuild_final.py`** — `final-update.csv` по правилу B: **165 строк**. +13. ✅ **Бэкап 165** → `/music/backup_fix/` + **APPLY 165** + **READBACK 165/165, 0 расхождений**. +14. ✅ **Чистка `._*`** — `del_junk.py --apply`: **29 удалено, 0 осталось**. +15. ✅ **Образ пересобран с ffmpeg 8.1.2** (`apk add --no-cache ffmpeg`). +16. ⚠️ **DRY-RUN конвертации: 28 ошибок — WMA с Windows Media DRM.** `probe_convert.py` запущен. +17. ⛔ **APPLY конвертации** — ждёт разбора DRM-файлов (класс `ok` конвертируем, `drm`/`corrupt` — нет). +18. ⏳ **Приёмка в Jellyfin** (глазами Alex). +19. ✅ **Обновить доки** — `personal/plans/tagwriter-container.md` + `personal/tech/music-tags-repair-truenas.md`. ## ✅ СОСТОЯНИЕ НА 2026-09-26 (факты) @@ -118,12 +182,12 @@ docker run --rm -u 0 -v /mnt/RED_2TB/docker:/docker alpine:latest sh -c \ | **СВЕРКА С ПЛАНОМ** (`verify_tags.py`) | ✅ **7610/7905 = 96.3%**, MISSING 83 (**всё не-MP3: 40 ogg+26 m4a+16 wma+1 flac**), MISMATCH 212 (**всё `no_change`/`skip` — не трогались**) | | **🔴 ДЕФЕКТ ПЛАНА: ложный `no_change`** | ❌ **353 строки** `action=no_change`, где `cur_*` ≠ `new_*` (TRCK 262, TIT2 49, TALB 21, TPE1 21) — требуют `fix`; **причина — устаревший `cur_*` + ложная логика генератора** | | **ФАКТ-ЧЕК 212 MISMATCH ПО ДИСКУ** | ✅ **165 требуют правки**, 45 уже ОК (ложные), 2 ошибки (`._*` мусор). Поля: TRCK 128 · TPE1 98 · TALB 29 · TIT2 25. Скрипты: `build_update_plan.py` + `fact_check_212.py` | -| **🔴 ОТКРЫТЫЙ ВОПРОС: 75 правок «удалить TRCK»** | ⏳ **ждёт `A`/`B`/`C`** (почти все — папка Наутилус Помпилиус; похоже на дефект плана) | -| **БЭКАП НЕ-MP3** | ✅ **70 файлов, 386.1 МБ → `/mnt/RED_2TB/storage/Music/backup_raw/`** (40 ogg · 16 wma · 13 m4a · 1 flac) | -| **`/music/backup/` не тронут** | ✅ 42 ГБ, 7041 файл — проверено после `backup_raw` | -| **APPLY ДЕЛЬТА-ПРАВОК (165)** | ⏳ **НЕ запускать до ответа Alex по TRCK** | -| **ПЕРЕСЧЁТ `action` ПО ДИСКУ** | ⏳ частично заменён коротким путём (212 из verify → факт-чек → 165); полный пересчёт нужен только для валидации всего плана | -| **КОНВЕРТАЦИЯ не-MP3 → MP3** | ⏳ план готов, **ждёт `go`** (см. § ПЛАН конвертации) | +| **🔴 ОТКРЫТЫЙ ВОПРОС: 75 правок «удалить TRCK»** | ✅ **РЕШЕНО: вариант B** (Alex: «косяк плана, не надо удалять номер трека») | +| **APPLY ДЕЛЬТА-ПРАВОК (165)** | ✅ **обновлено 165, ошибок 0; readback 165/165, 0 расхождений** | +| **БЭКАП 165** | ✅ **165 файлов → `/music/backup_fix/`** | +| **МУСОР `._*`** | ✅ **29 удалено, 0 осталось** (`del_junk.py --apply`) | +| **ПЕРЕСЧЁТ `action` ПО ДИСКУ** | ✅ **не понадобился** — заменён коротким путём (212 из verify → факт-чек → 165). **Правило Alex: есть список — не пересчитывать план.** | +| **КОНВЕРТАЦИЯ не-MP3 → MP3** | ⛔ **ЗАБЛОКИРОВАНА DRM**: 28 WMA защищены Windows Media DRM. Идёт `probe_convert.py` | ### Результат независимой сверки `verify_tags.py` (2026-09-26, ПОЛНЫЙ лог) @@ -221,9 +285,9 @@ Alex: «У тебя блядь есть список несовпавших mp3! | `SD-card-2026-05/Несчастный случай/Генералы песчаных карьеров.mp3` | `Несчастный Случай` | `Несчастный случай` | | `Infected Mushroom/.../Infected Mushroom - You dont exist 140bpm.mp3` | TALB `old - unreleased` | `Unreleased Tracks` | -### 🔴 ОТКРЫТЫЙ ВОПРОС (ждёт решения Alex): 75 правок «удалить TRCK» +### ✅ РЕШЕНО (Alex, 2026-09-26): 75 правок «удалить TRCK» → вариант **B** -В `final-update.csv` **75 правок вида `TRCK: 'N'->''`** — план требует **удалить** номер трека: +В `final-update.csv` было **75 правок вида `TRCK: 'N'->''`** — план требовал **удалить** номер трека: ``` TPE1: 'Nautilus Pompilius'->'Наутилус Помпилиус'; TRCK: '1'->'' @@ -231,19 +295,20 @@ TPE1: 'NTL'->'НТЛ'; TRCK: '51'->'' TIT2: 'Fever // By Maddalinio //'->'Fever'; TRCK: '02'->'' ``` -Почти все — папка **Наутилус Помпилиус** (~20 файлов). Похоже на **дефект плана** -(`new_track` пустой = «не задано», а не «удалить»), а не намерение. +Почти все — папка **Наутилус Помпилиус** (~20 файлов). -**Варианты, предложенные Alex:** -- **A** — удалить номера (буквально выполнить план); -- **B** — **не трогать `TRCK`, где `new_track` пустой** (рекомендация ассистента: удаление - трек-номеров деструктивно для библиотеки); -- **C** — показать полный список 75 → Alex решит точечно. +**Ответ Alex: «Я думаю это косяк плана, не надо удалять номер трека» → вариант B.** -**Второй вопрос:** 2 файла `._Infected Mushroom - Tiwanacu.MP3` и `._МИМИКРИЯ.MP3` — -AppleDouble-мусор на диске. Удалять? +**Реализация B** (`rebuild_final.py`): если `new_track` пустой — ключ `TRCK` **исключается** +из сравнения целиком; на диске номер остаётся как есть. Пересчёт дал **165 строк** +(TRCK 53 · TPE1 98 · TALB 29 · TIT2 25) — меньше 212 за счёт отсева «только удаление TRCK». -**Статус: ждёт `A`/`B`/`C` от Alex. До ответа `apply` дельта-правок НЕ запускать.** +**Второй вопрос — `._*` мусор:** Alex сказал **удалять**. Реализовано `del_junk.py`: +29 файлов (`.DS_Store` 8 + AppleDouble-двойники 19 + папка `._Savant - Vybz`), результат — 0 осталось. + +**Правило на будущее:** пустой `new_track` в плане генерации = «не задано», а **не** «удалить». +Удаление трек-номеров деструктивно; генерировать `action=fix` на удаление тега запрещено без +явного решения Alex. ### ⏭ ПЛАН: пересчёт `action` по фактическому диску (ЖДЁТ `go`) @@ -346,7 +411,14 @@ ffmpeg -i src.wma -vn -acodec libmp3lame -q:a 0 -map_metadata 0 -id3v2_version 3 4. **только при успехе** — `os.replace(tmp, final)`, затем удалить оригинал; 5. `assert "backup" not in path` на каждом шаге. -**Статус:** план составлен, **не запущен** (ждёт `go` от Alex). +**Статус:** образ с ffmpeg собран (8.1.2), **первый dry-run дал 28 ошибок — WMA с Windows Media DRM** +(см. § БЛОКЕР КОНВЕРТАЦИИ: DRM). Запущена диагностика `probe_convert.py`, которая классифицирует +все 70 файлов на `ok` / `drm` / `corrupt` / `other` → `/app/data/convert-probe.json`. +**Конвертировать только класс `ok`.** Для `drm` — конвертация невозможна без снятия защиты. + +Табличная форма диагноза: `probe_convert.py` прогоняет `ffmpeg` на каждый файл, смотрит +`returncode` + размер выхода (>10 000 Б) + маркеры в stderr (`License_URL`/`DRM` → `drm`; +`Decode error rate`/`Invalid data`/`out of range` → `corrupt`). ### 🔧 `verify_tags.py` — скрипт сверки (создан 2026-09-26) @@ -374,8 +446,13 @@ docker compose --profile tools run --rm \ | `build_update_plan.py` | локально `/tmp/` | из MISMATCH-лога берёт пути → фильтрует MP3 → тянет `new_*` из плана → `update-plan.csv` | | `fact_check_212.py` | NAS `/mnt/RED_2TB/docker/tagwriter/` | читает реальные ID3 → сравнивает с `new_*` → `final-update.csv` (165 строк) | | `backup_nonmp3.py` | NAS | бэкап не-MP3 → `backup_raw/` | +| `rebuild_final.py` | NAS | пересборка `final-update.csv` с правилом B (TRCK не удалять) + сбор `junk-files.json` | +| `apply_fix165.py` | NAS | бэкап 165 → `backup_fix/` + apply + readback (одним прогоном, `--apply`) | +| `del_junk.py` | NAS | удаление `._*` по списку `junk-files.json` (dry-run без `--apply`) | +| `convert_nonmp3.py` | NAS | конвертация не-MP3 → MP3 (VBR V0, `-map_metadata 0`, ID3v2.3), dry-run/`--apply` | +| `probe_convert.py` | NAS | классификация 70 не-MP3: `ok`/`drm`/`corrupt`/`other` → `convert-probe.json` | | `recompute_action.py` | NAS | полный пересчёт `action` по диску (не понадобился — заменён коротким путём) | -| `deep_classify.py`, `find_false_nochange.py`, `action_check.py`, `classify2.py` | локально `/tmp/` | анализаторы расхождений | +| `deep_classify.py`, `find_false_nochange.py`, `action_check.py`, `classify2.py`, `build_update_plan.py`, `fact_check_212.py` | локально `/tmp/` | анализаторы расхождений | **Правило, выведенное Alex'ом:** если список несовпавших файлов **уже есть** (из verify) — не пересчитывать весь план, а **сразу взять этот список** и обновить теги по нему. @@ -451,6 +528,9 @@ docker compose --profile tools run --rm \ `no_change`/`skip` — файл не менялся, расхождение было ДО. Это может быть как норма (регистр/ведущий ноль), так и **скрытый дефект плана**. Не списывать «всё ок» — Alex это ловит. - ⚠️ `ffmpeg` на хосте NAS **нет**; добавлять в контейнер (`apk add --no-cache ffmpeg`), не использовать чужие контейнеры. +- 🔴🔴 **WMA бывает с Windows Media DRM — конвертация НЕВОЗМОЖНА.** Признак: stderr ffmpeg содержит `License_URL : ...&sbp=DRM` и `Decode error rate 0.99... exceeds maximum`. Файл НТЛ `wma/Track 1–13.wma` — такие. **Правило: перед конвертацией любого формата — probe каждого файла** (`probe_convert.py`), конвертировать только класс `ok`; `drm` оставить как есть. Не трактовать DRM-ошибку как сбой скрипта и не пытаться «дожать» повторными прогонами. +- ⚠️ **Лог ffmpeg забивается баннером** (`libav*/62.12.102`) — при разборе ошибок грепать маркеры (`License_URL`, `Decode error rate`, `Conversion failed`), а не листать хвост. +- 🔴 **Пустой `new_track` в плане = «не задано», а НЕ «удалить тег».** Генерировать `action` на удаление тега нельзя: Alex подтвердил («это косяк плана, не надо удалять номер трека»). Реализация: при пустом `new_track` **исключать** `TRCK` из сравнения целиком (иначе 75 файлов Наутилуса потеряли бы номера). - ⚠️ macOS-мусор `._*` (AppleDouble) попадает в `find` как «m4a» — **исключать** (`if f.startswith("._"): continue`), иначе счёт файлов завышен вдвое (26 vs 13). - 🔴 **Длительные операции на NAS (бэкап/apply) — только в фоне** (`background=true` + `notify_on_complete`): foreground-таймаут 600 с обрывает ssh, операция продолжается «осиротевшей».
Два независимых долгих процесса можно вести **параллельно** (ЧТЕНИЕ тегов + КОПИРОВАНИЕ файлов не конфликтуют) — Alex это ожидает. - 🔴 **Апрув-таймаут ≠ «не смог».** Если команда заблокирована («Approval request timed out — do NOT retry»), это значит **Alex не увидел промпт**, а не запрет. Ассистент обязан: (1) сообщить точную формулировку блокировки, (2) **не повторять вслепую**, (3) попросить подтверждение. Alex реагирует жёстко на «почему не сделал?» — нужно сразу объяснять механику блокировки, а не оправдываться. diff --git a/personal/tech/music-tags-repair-truenas.md b/personal/tech/music-tags-repair-truenas.md index 0c2fbcec..94eea287 100755 --- a/personal/tech/music-tags-repair-truenas.md +++ b/personal/tech/music-tags-repair-truenas.md @@ -23,7 +23,34 @@ related: # Music Tags Repair — TrueNAS (7906 → 7905 файлов) -> ## ✅ ТРИДЦАТЬ ВОСЬМАЯ ВОЛНА (2026-09-26) — ФИНАЛЬНЫЙ АУДИТ + 4 ПРАВКИ ВЫПОЛНЕНЫ +> ## ✅ ТРИДЦАТЬ ВОСЬМАЯ ВОЛНА (2026-09-26) — ФИНАЛЬНЫЙ АУДИТ + 4 ПРАВКИ + ПРИМЕНЕНИЕ НА NAS +> +> ### 🆕 ИТОГ ПРИМЕНЕНИЯ (вечер 2026-09-26) — дельта закрыта, конвертация упёрлась в DRM +> +> | Шаг | Результат | +> |---|---| +> | Решение Alex по 75 правкам «удалить TRCK» | ✅ **B** — «это косяк плана, не надо удалять номер трека» | +> | Решение Alex по `._*` | ✅ **удалять** | +> | `rebuild_final.py` → `final-update.csv` | ✅ **165 строк** (TRCK 53 · TPE1 98 · TALB 29 · TIT2 25) | +> | Бэкап 165 → `/music/backup_fix/` | ✅ 165 файлов | +> | **APPLY 165 + READBACK** | ✅ **165/165, ошибок 0, расхождений 0** | +> | Чистка `._*` (`del_junk.py --apply`) | ✅ **29 удалено, 0 осталось** | +> | Образ с ffmpeg | ✅ пересобран, ffmpeg **8.1.2** + mutagen 1.47.0 | +> | **DRY-RUN конвертации не-MP3** | ⛔ **28 ошибок — WMA с Windows Media DRM** (`License_URL … sbp=DRM`, `Decode error rate 0.99`) | +> | Диагностика `probe_convert.py` | ⏳ классифицирует 70 файлов: `ok`/`drm`/`corrupt`/`other` | +> | APPLY конвертации | ⛔ **НЕ ЗАПУСКАТЬ** — конвертировать только класс `ok` | +> | Приёмка в Jellyfin | ⏳ ждёт Alex | +> +> **🔴 НОВЫЙ КЛАСС ПРОБЛЕМЫ: зашифрованный контент.** Часть `.wma` (НТЛ `wma/Track 1–13.wma`) +> защищена **Windows Media DRM** — ffmpeg не может их декодировать (99.5 % ошибок). Это не сбой +> скрипта и не потеря файлов (оригиналы в `backup_raw/`). Обходного пути без снятия DRM нет. +> **Правило: перед конвертацией формата — probe каждого файла, конвертировать только валидные.** +> +> **Итог по MP3: план закрыт.** 7041 (основной apply) + **165 (дельта)** = все MP3 приведены к плану. +> Остались только не-MP3 (70 файлов), из которых часть конвертируема, часть — DRM. +> +> **Новое правило Alex:** если список несовпавших файлов **уже есть** — не пересчитывать весь план, +> взять список сразу («У тебя же уже есть этот список зачем пересчет»). > > Триггер: Alex — «проводи финальный полный аудит списка на переименование» > → «Csv блядь который ты делал» → «Чини». @@ -123,11 +150,12 @@ related: > `Shop`/`Candy` → `Candy Shop`/`50 Cent`; Наутилус `Nautilus Pompilius` → `Наутилус Помпилиус`; > НТЛ `NTL` → `НТЛ`; `Wolfgang Gartner - Fire Power` пустые теги → заполнить. > -> 🔴 **ОТКРЫТЫЙ ВОПРОС: 75 правок вида `TRCK: 'N'->''`** (удалить номер трека; почти все — -> Наутилус Помпилиус). Похоже на дефект плана (`new_track` пустой = «не задано»). -> Варианты: **A** удалить как в плане · **B** не трогать пустой `new_track` (рекомендация) · -> **C** показать полный список 75. **Ждёт ответа Alex. До ответа `apply` дельта-правок не запускать.** -> Отдельно: 2 файла `._Infected Mushroom - Tiwanacu.MP3`, `._МИМИКРИЯ.MP3` — удалять? +> ✅ **РЕШЕНО Alex: вариант B** — «это косяк плана, не надо удалять номер трека». +> 75 правок `TRCK: 'N'->''` (почти все — Наутилус Помпилиус) **отброшены**: при пустом `new_track` +> ключ `TRCK` исключается из сравнения, номер на диске остаётся. +> `._*` мусор — Alex сказал **удалять**; выполнено: **29 файлов, 0 осталось**. +> Пересчёт `rebuild_final.py` → **165 правок** (было 212, минус 45 ложных и «только удаление TRCK»). +> **APPLY 165 + READBACK: 165/165, ошибок 0.** > > **Скрипты этой сессии:** `build_update_plan.py` (локально) + `fact_check_212.py` (NAS). > @@ -199,9 +227,11 @@ related: > > ⏭ **Осталось:** (1) ✅ полный разбор 83 MISSING + 212 MISMATCH — **сделан, вскрыл ДЕФЕКТ ПЛАНА > (353 строки ложного `no_change`) + факт-чек (165 реальных правок)**; -> (2) 🔴 **ответ Alex по TRCK (A/B/C) — 75 правок «удалить»** → затем **apply дельта-правок (165)** -> (бэкап уже есть); (3) конвертация не-MP3 → MP3 (**ждёт `go`**); -> (4) приёмка в UI Jellyfin (глазами Alex); (5) после приёмки — удалить бэкап. +> (2) ✅ **ответ Alex по TRCK = B** → **apply дельта-правок (165): 165/165, 0 расхождений**; +> (3) ⛔ конвертация не-MP3 → MP3 — **заблокирована Windows Media DRM** (28 WMA); идёт `probe_convert.py`, +> конвертировать только класс `ok`; +> (4) приёмка в UI Jellyfin (глазами Alex); (5) после приёмки — удалить бэкапы +> (`backup/`, `backup_raw/`, `backup_fix/`). > > ### 🔴 ПИТФОЛЛ: sentinel-группа собирается по КОРНЮ сборника, НЕ по ближайшей папке >