[2026-09-27] eagle: personal/tech/music-tags-repair-truenas.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-27 23:51:40 +06:00
1 parent 2332ce79fb
commit e0e395dfcf
1 file changed
+95
@@ -23,8 +23,103 @@ related:
# Music Tags Repair — TrueNAS (7906 → 7905 файлов)
> ## 🔴🔴 КАК СТРОИЛСЯ `APPLY-PLAN.csv` И ДИФФ — ЧИТАТЬ ДО ЛЮБОЙ ПЕРЕСБОРКИ
>
> **`APPLY-PLAN.csv` собран НЕ `build_fix_plan2.py`.** Это главная путаница.
> Настоящая цепочка (восстановлено из Zulip DB 27 сен):
> ```
> папка сборки: /Users/admin/milestones/music-csv-2026-09-26/
> tag-inventory3.csv ← свежий сбор тегов с диска (6432 номера треков)
> APPLY-PLAN-FINAL.csv 12:18 — 6 полей, валидация чистая, НО new_track сырой
> APPLY-PLAN-FINAL2.csv 12:26 — ПРАВДА, мусор в track вычищен
> APPLY-PLAN.csv ← канон, = FINAL2
> колонки: path, folder, class, cur_title/artist/albumartist/album/genre/track,
> new_title/artist/albumartist/album/genre/track, changed
> ```
> 🔴 **FINAL и FINAL2 различимы только по `new_track` (142 строки) и `changed` (20).**
> Схема колонок в них **идентична** — сравнивать надо значения, не заголовки.
>
> 🔴 **`build_fix_plan2.py` — это ДРУГОЙ скрипт, для волны 38.**
> Он НЕ пишет `albumartist` вообще (0 упоминаний) и НЕ собирал канон.
> Подробности ниже — «ДЕФЕКТЫ build_fix_plan2.py».
>
> **Дифф к канону:** `DIFF-base-vs-applyplan-v3.csv` (945 строк) —
> собирался `/tmp/build_canon_diff_v3.py`, **не** `build_fix_plan2.py`.
>
> 🔑 **ПРАВИЛО ХРАНЕНИЯ ЗНАНИЙ:** любая пересборка плана/диффа обязана
> начинаться с чтения этого блока. Три раза подряд я писал новый сборщик
> «с нуля», теряя сортировку, схлопывание и правило `album`.
> **Сборщик живёт в папке проекта (`~/Downloads/music-tags/`), НЕ в `/tmp`.**
> ## 🔴 ДЕФЕКТЫ `build_fix_plan2.py` (найдены 27 сен, не исправлены в боевом файле)
>
> | # | Дефект | Где | Последствие |
> |---|---|---|---|
> | 1 | `albumartist` НЕ пишется вообще | `plan.append([...])` стр. 795-800 | все сборники без albumartist |
> | 2 | `is_release_folder`: `n.startswith("!") → True` | стр. 569-570 | папки `!rock_o_pop`, `!Retro`, `!Рэп` объявлены релизом → `derive_from_path` даёт `('','')` → правило корня выключено |
> | 3 | файл ПРЯМО в категории → `dirs=[]` | стр. 504-505 | `!Retro/x.mp3` не получает `album='Retro'` |
> | 4 | `9999 - Разное` уходит в `artist` | стр. 523-530 | `artist='9999 - Разное'` вместо реального исполнителя |
>
> 🔑 **Рабочая копия для правок: `music-tags/tagwriter` (указание Alex).**
> Бэкапы: `build_fix_plan2.py.bak-before-rootfix-20260927-203300`.
>
> **ЦЕЛЕВАЯ МОДЕЛЬ (подтверждена Alex):**
> - `albumartist` = **папка-владелец** (по правилу корня): `Агата Кристи`, `Трофим`
> - `artist` = **реальный исполнитель трека** из тега: `Чайф`, `Би-2`, `Слот`
> - сборник ≠ схлопывание исполнителя: в `9999 - Разное` артистов СОХРАНЯТЬ
> - `album` = имя папки без цифрового префикса (`01 Аристократия помойки` → `Аристократия помойки`)
> ## 🔴 ИСТОЧНИК ИСТИНЫ ПРИ ПЕРЕСБОРКЕ = БАЗА NAVidrome, НЕ КАНОН
>
> Канон `APPLY-PLAN.csv` описывает состояние **ДО** боевого прогона 27 сен.
> После прогона диск ушёл вперёд: теги на диске ≠ канон.
> **Дифф, собранный от канона, НЕ ВИДИТ уже записанных дефектов**
> (пример: Птаха — в каноне верно, в БД `album='Птаха - Красивые, богатые (2009)'`).
>
> ✅ **Правильно: дифф от БД.** БД читать так:
> ```
> ~/Downloads/navidrome-db/navidrome-after-v3.db ← локальная копия
> sqlite3 через python3 (НЕ внутри контейнера — там нет sqlite3)
> 🔴 жанр НЕ в media_file.genre (всегда пусто!) — он в media_file.tags (jsonb):
> {"genre":[{"id":"...","value":"Бардовская песня"}]}
> либо в таблицах tag / media_file_tags / album_tags
> ```
> 🔴 **Обязательный фильтр:** `WHERE path NOT LIKE 'backup%'`.
> 🔴 Поля: `track_number` (НЕ `track`), `album_artist` (НЕ `albumartist`).
> 🔴 `track_number = 0` при пустом TRCK → все треки слипаются в один.
> Navidrome показывает `AudioTrack N` когда `TIT2` пуст.
> ## 📍 ФИЗИЧЕСКИЕ ДУБЛИ (удалено 27 сен)
>
> Трофим лежал в 3 местах; копии удалены, эталон `!Рэп/Трофим` (157 файлов):
> ```
> !Pop, Club, Любэ/!Radio/z Старое/disk/3 SHANSON/Трофим 25 → УДАЛЕНО
> !Pop, Club, Любэ/!Radio/z Старое/disk_v2/3 SHANSON/Трофим 25 → УДАЛЕНО
> !Рэп/Трофим 157 → ЭТАЛОН
> ```
> Файлы в сборниках (`disk/`, `disk_v2/`) **удалять нельзя** — указание Alex:
> «они корректно живут в сборниках». Удаляем ТОЛЬКО дубли альбомов.
> ## 🔴 АКТУАЛЬНОЕ СОСТОЯНИЕ (2026-09-27, сессия ~30) — ЧИТАЙ ЭТО ПЕРВЫМ
>
> ✅ **БОЕВОЙ ПРОГОН ВЫПОЛНЕН:** 7653/7653 ok, err=0.
> `TCON 4359 · TPE2 7213 · TALB 2031 · TPE1 381 · TRCK 437 · TIT2 8`.
> **Проверено чтением файлов: `TCON` у 7861/7861, mismatches 0.**
> 🔑 **ПИТФОЛЛ ЗАПУСКА:** у образа `tagwriter:latest` в `CMD` прописан `--dry-run`.
> Явно передавать `--apply`, иначе прогон молча уходит в dry-run:
> `docker create ... tagwriter:latest /app/apply_tags_v2.py --apply`
> 🔑 Боевой прогон запускать ДВУМЯ шагами: `docker create` затем `docker start`.
> Составная команда прерывается по таймауту.
>
> ✅ **NAVIDROME БД ПЕРЕСОЗДАНА:** `stop → rm navidrome.db* → up -d`, скан 4м13с,
> импортировано **7861** трек. Бэкапы БД: `navidrome.db.bak-20260927-apply-v3`,
> `navidrome.db.bak-20260927-053238`.
> 🔴 **ПУТЬ БД: `/mnt/RED_2TB/docker/navidrome/data/`** — БЕЗ `storage/`!
> В доке ранее был неверный путь `/mnt/RED_2TB/storage/docker/navidrome/data`.
> Композ-проект: `/mnt/RED_2TB/docker/navidrome`.
> ## 🔴 АКТУАЛЬНОЕ СОСТОЯНИЕ (сессия ~29) — АРХИВ
>
> ✅ **DRY-RUN ВЫПОЛНЕН УСПЕШНО.** План `/tmp/apply-plan-v3.csv` (md5
> `6b9e49b2baa3f1d1708e4566972266a9`) скопирован на NAS как `/tmp/tw306/apply-plan.csv`
> (md5 совпал). Вывод — `/tmp/dryrun.log` / NAS `/tmp/tw306/dryrun.log`: