diff --git a/personal/plans/tagwriter-container.md b/personal/plans/tagwriter-container.md index a956e581..55a5b976 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: converted-tags-lost-pending-restore +status: 40mp3-destroyed-rollback-ready tags: - music - truenas diff --git a/personal/tech/music-tags-repair-truenas.md b/personal/tech/music-tags-repair-truenas.md index d7da49d9..cda0ec3a 100755 --- a/personal/tech/music-tags-repair-truenas.md +++ b/personal/tech/music-tags-repair-truenas.md @@ -43,10 +43,25 @@ related: > | ✅ Решение Alex | битые/DRM **удалять** («какая разница, они все равно не играют») | > | **Конвертация 41 (`convert41.py --apply`)** | ✅ **выполнено: 41/41, 0 ошибок** — оригиналы ogg/flac удалены скриптом | > | 🔴 **Теги новых MP3** | 🔴 **40 из 41 ПУСТЫЕ** (`check_conv_tags.py`) — ffmpeg **не переносит Vorbis comments → ID3** | -> | ⏳ Восстановление тегов 40 | `fix40_source.json` собран (матч 40/40 по basename), `fix40.py` не написан — ждёт решения Alex по заголовкам Кирпичей | +> | ✅ Решение Alex по Кирпичам | «Нормально делать» → ведущий ` - ` в `new_title` **срезать** (номер остаётся в `TRCK`) | +> | ✅ `fix40.py` DRY-RUN | **40/40 готовы, 0 ошибок** | +> | 🔴🔴 `fix40.py --apply` | отчёт «40/40 записано, 0 ошибок» — **ЛОЖНАЯ ПРИЁМКА: аудио уничтожено** | +> | 🔴 Причина | `ID3(p).save(tmp)` пишет **только тег-блок**, MPEG-поток не копируется → 40 MP3 стали ~1.1 КБ | +> | ✅ Ущерб локализован | `backup_conv40/` **40/40 целых** (2–10 МБ) + `backup_raw/` **41/41 оригиналов** → **откат возможен** | +> | ⏳ Откат 40 из `backup_conv40/` + перезапись правильным способом | ждёт «откат» от Alex | > | ⏳ Удаление 29 битых/DRM | **не выполнено** — команды не было (список уже сохранён) | +> | ⏳ Правка дыры `apply_tags.py` (нет `.mp3`-фильтра) | Alex сказал «правь» — не выполнено | > | Приёмка в Jellyfin | ⏳ ждёт Alex | > +> **🔴🔴🔴 НОВЫЙ КЛАСС ПРОБЛЕМЫ: `mutagen.ID3().save()` уничтожает аудио.** `ID3(path)` — это +> парсер **тег-блока**, он не привязан к MPEG-потоку: `save()` сериализует только фреймы ID3, +> а последующий `os.replace` затирает оригинал → файл размером ~1 КБ без единого аудио-фрейма +> (`ffprobe`: `Failed to find two consecutive MPEG audio frames`). **Проверено на живой библиотеке: +> 40 MP3 (2–10 МБ) превратились в 1.1 КБ.** Правильно: `ID3(p).save(p)` — **в тот же путь** +> (тогда mutagen копирует поток), либо `MP3(p)` + `.save()`, либо `shutil.copy2(p, tmp)` перед правкой. +> ⚠️ **«N/N записано, 0 ошибок» ≠ приёмка** — валидировать `MP3(p).info.length` и `ffprobe` кодек, +> а не факт выполнения `save()`. Подробно — [[personal/plans/tagwriter-container]]. +> > **🔴 НОВЫЙ КЛАСС ПРОБЛЕМЫ: конвертация теряет теги между системами метаданных.** > `ogg` хранит теги в **Vorbis comments** (`ARTIST=`/`TITLE=`), `mp3` — в **ID3v2** (`TPE1`/`TIT2`). > `-map_metadata 0` этот маппинг **не делает** → 40/41 новых MP3 вышли с пустыми тегами