diff --git a/personal/plans/music-artist-albumartist-repair.md b/personal/plans/music-artist-albumartist-repair.md index 56379816..a3f9ee87 100755 --- a/personal/plans/music-artist-albumartist-repair.md +++ b/personal/plans/music-artist-albumartist-repair.md @@ -19,22 +19,25 @@ related: - '[[personal/tech/music-tags-repair-truenas]]' - '[[personal/plans/tagwriter-container]]' - '[[family/how-to/navidrome-truenas-android]]' -status: session18-album-306-fixed-new-diff-generated +status: session18-complete-waiting-apply-step2 # Music `artist` + `albumartist` Repair — правила Alex и ход работ ## 🟣 СЕССИЯ 18 (2026-09-27) — NAVIDROME РАЗВЁРНУТ, ДЕФЕКТ-КЛАСС ВСКРЫТ, ПРАВИЛА ВОССТАНОВЛЕНЫ ИЗ ZULIP, 306 СТРОК ИСПРАВЛЕНЫ, НОВЫЙ ДИФФ ГОТОВ -> **СТАТУС СЕССИИ 18 (финал):** Navidrome ✅ развёрнут и работает (см. ниже + +> **СТАТУС СЕССИИ 18 (ФИНАЛ):** Navidrome ✅ развёрнут и работает (см. ниже + > `[[family/how-to/navidrome-truenas-android]]`). Дефект-класс `new_album == cur_album` > вскрыт (6202 строки, 79%), реального мусора **9 папок / 265 треков→306 строк**. > Правила `album` восстановлены из базы Zulip. **306 строк исправлены в `APPLY-PLAN.csv`**, > затем **ещё 58 строк по 3 дефектам** (склейка артист+год 18, чужой `albumartist` 7, -> `album`=название песни 33). Итог по файлу: **скобок 0, `albumartist`-разброс 7→2 папки, -> `Green Apelsin` 13 значений→1**. Дифф `DIFF-new-vs-38-v2.csv` сгенерирован (164 album-строки), -> но ⏭ **устарел после правки 58 строк — требует перегенерации**. -> ⚠️ Открыто: 2 папки с разным `albumartist` (`Ленинград`/`Сергей Шнуров`; `ВИА МЕА`), -> вычитка диффа Alex, валидатор смысла. -> См. §ПРАВКА 3 ДЕФЕКТОВ, §КАЛИБРОВКА ДЕТЕКТОРОВ, §СДЕЛАНО: правка 306 строк, §НОВЫЙ ДИФФ. +> `album`=название песни 33), затем **+12** (`Шнуров`→`Ленинград` 1, `NONSONS - zvezda`→`zvezda` 11). +> **Всего 371 строка. Проверено по файлу: скобок 0, `albumartist`-разброс 7→1 папка, +> `Green Apelsin` 13→1 значение.** +> ✅ Дифф **`DIFF-new-vs-38-v2.csv` ПЕРЕГЕНЕРИРОВАН** (164 album-строки, +12), полнота проверена — +> все 18 целевых `album` и 6 `albumartist` внутри. Старый дифф **не тронут**. +> Alex дал команду **«применяй»** → **ШАГ 1 (сверка артефактов) ПРОЙДЕН**: найдено 2 расхождения +> (скрипт на NAS и план на NAS — оба старые). ⏭ **ШАГ 2 не начат — ждёт «шаг 2» от Alex.** +> См. §ПРАВКА 3 ДЕФЕКТОВ, §КАЛИБРОВКА ДЕТЕКТОРОВ, §СДЕЛАНО: правка 306 строк, §НОВЫЙ ДИФФ, +> §СВЕРКА АРТЕФАКТОВ ШАГ 1. > **Контекст:** Navidrome поднят и просканировал библиотеку (8043 трека). Alex открыл UI и > спросил: «**Откуда альбомы в скобках взялись?** Типа `Дискотека Авария` — для корня, @@ -459,19 +462,88 @@ new_album начинается со скобки: 306 → 0 Green Apelsin: album значений 13 → 1 ('Северный ветер') ``` -### ⚠️ ОСТАЛОСЬ 2 ПАПКИ С РАЗНЫМ `albumartist` (ждут решения Alex) +### ✅ ОБА ВОПРОСА ЗАКРЫТЫ ALEX (2026-09-27, конец сессии 18) -| Папка | Значения | Вопрос | +Alex: «**Шнурова править. `Другое..` — нет. Альбом должен быть `zvezda`**». + +| Папка | Решение Alex | Сделано | |---|---|---| -| `z Другое.../Ленинград` | `Ленинград` ×4, **`Сергей Шнуров`** ×1 | ставить `Ленинград`? | -| `z Другое.../Enigma.../Ленинград` (корень) | **`ВИА МЕА`** ×1, `Красная Плесень` ×2 | что с `ВИА МЕА`? | +| `z Другое.../Ленинград` | `Сергей Шнуров` → **`Ленинград`** | ✅ 1 строка | +| `z Другое, Enigma, Ленинград` (корень) | **НЕ трогать** (разные артисты — легитимно) | — | +| `!Rock&Folk/NONSONS - zvezda` | `album` = **`zvezda`** (не `NONSONS - zvezda`) | ✅ 11 строк | -**Также осталось:** 11 «склеек» — **ложные** (`NONSONS - zvezda` = имя папки артиста, верно). +Скрипт `/tmp/fix_shnur_zvezda.py`, бэкап +`APPLY-PLAN.csv.bak-before-shnur-zvezda-20260927-174058`. -### ⏭ НЕ СДЕЛАНО: перегенерация диффа после правки 3 дефектов +**Проверка фактом после правки:** +``` +Ленинград: albumartist={'Ленинград'} +NONSONS - zvezda: album={'zvezda'} +Папок с РАЗНЫМИ albumartist: 1 (только z Другое корень — по решению Alex) +``` -`DIFF-new-vs-38-v2.csv` сгенерирован **ДО** правки 58 строк. **План изменился — дифф устарел, -требует перегенерации** (`python3 ~/Downloads/music-tags/diff_new_vs_38_v2.py`). +> 🔑 `NONSONS - zvezda` — **имя папки артиста**, а `album` должен быть `zvezda`: правило +> «в корне группы `album` = имя папки артиста» НЕ отменяет правило Alex «имя папки и склейка +> `Родитель - Папка` в `album` ЗАПРЕЩЕНЫ». Для этой папки правильное значение — чистый альбом. + +### ✅ ПЕРЕГЕНЕРАЦИЯ ДИФФА ВЫПОЛНЕНА + +`DIFF-new-vs-38-v2.csv` перегенерирован ПОСЛЕ всех правок (306 + 58 + 12). + +| | album-строк | +|---|---:| +| Старый `DIFF-new-vs-38.csv` | 152 (101 ПАПКА + 51 ТРЕК) | +| **Новый `DIFF-new-vs-38-v2.csv`** | **164 (112 ПАПКА + 52 ТРЕК)** | + +**Проверка полноты (`/tmp/final_verify.py`):** все **18** целевых значений `album` найдены +в новом диффе, все **6** целевых `albumartist` найдены. `Не найдено: нет`. +Схлопывание сработало: 306 построчных правок → **15 записей по папкам** (значение одинаково +у всех файлов папки — правило 2 диффа). + +**MD5:** старый `4e073fe50c191cc50015d3f15f6a6d28` (mtime 15:46 — **НЕ ТРОНУТ**), +новый `7bc222a1087787c390026d624af932f3`. + +### 🔴 КОМАНДА ALEX «ПРИМЕНЯЙ» → GATE: ШАГ 1 (СВЕРКА АРТЕФАКТОВ) ПРОЙДЕН, ШАГ 2 НЕ НАЧАТ + +Alex: «**Отлично, применяй**». Прогон **НЕ запущен** — сначала сверка артефактов на NAS +(прогон необратим, меняет 7861 mp3). + +**Результат сверки (шаг 1, факты):** + +| Артефакт | MD5 / состояние | Вердикт | +|---|---|---| +| Скрипт на Mac (`~/Automation` = `~/Downloads/tagwriter`) | `c7a2bc143e38820f2050310cbe01b799` | ✅ эталон | +| **Скрипт в образе `tagwriter:latest`** | `c7a2bc143e38820f2050310cbe01b799` | ✅ **совпал** | +| **Скрипт на NAS** `/mnt/RED_2TB/docker/arr/tagwriter/` | `c8083f9760a424d453b34f646556c1ea` | 🔴 **расходится** | +| `ENTRYPOINT`/`CMD`/`USER` в `latest` | `["python3","/app/apply_tags_v2.py"]` / `["--dry-run"]` / `950:950` | ✅ фиксы на месте | +| **План на NAS** `apply-plan.csv` | `245efb55ab1de26cb5172f0754192c3d` | 🔴 **СТАРЫЙ** (без 371 правки) | +| Бэкап `Music/backup` | 50 ГБ | ✅ есть (без него `cmd_apply()` → `exit 2`) | +| `tagwriter:v2` | `e5e2437a2fda90cb6b06d6daa6330cb` | ⚠️ старая версия — **не использовать** | +| uid образа `latest` | `uid=950 gid=950 groups=950` | ✅ `USER 950:950` работает | + +> 🔴 **ПИТФОЛЛ: `Dockerfile.v2` на Mac — УСТАРЕВШАЯ СПРАВОЧНАЯ КОПИЯ.** +> В нём НЕТ `ENTRYPOINT` и `USER 950:950`, хотя в доке они описаны как фиксы. **Боевой образ +> `tagwriter:latest` собран с фиксами** (проверено `docker inspect` + `id` внутри контейнера). +> **Не пересобирать из этого файла — потеряешь фиксы.** Файл на Mac: +> ``` +> FROM python:3.11-slim +> RUN pip install --no-cache-dir mutagen==1.47.0 +> WORKDIR /app +> COPY apply_tags_v2.py /app/apply_tags_v2.py +> CMD ["python3", "/app/apply_tags_v2.py", "--dry-run"] ← нет ENTRYPOINT, нет USER +> ``` + +### ⏭ ШАГ 2 (НЕ ВЫПОЛНЕН — ждёт «шаг 2» от Alex) + +1. `docker cp` актуального `apply_tags_v2.py` (Mac) → контейнер `/app/apply_tags_v2.py` +2. Залить актуальный `APPLY-PLAN.csv` (Mac) → NAS `/mnt/RED_2TB/docker/arr/tagwriter/apply-plan.csv` +3. Сверить MD5 обоих на NAS после заливки +4. `--dry-run` → сверить счётчики +5. **Только после «go»** — `--apply --verify` + +> 🔴 **Правило шага 1:** **перед необратимым прогоном сверять MD5 скрипта (Mac / образ / NAS) +> и плана (Mac / NAS).** В этой сессии расхождения нашлись в ДВУХ местах из двух проверенных — +> без сверки прогон пошёл бы **по старому плану без 371 правки**. ### ✅ Артефакты сессии 18 @@ -500,6 +572,29 @@ Green Apelsin: album значений 13 → 1 ('Северный вет | `/tmp/check_diff_coverage.py` | проверка покрытия дефекта диффом (7,6%) | | `/tmp/where_avaria.py` | где физически лежат файлы `(Авария)` | | `/tmp/album_rules_v2.py` | применение финальных правил (КОРЕНЬ/ПОДПАПКА/СБОРНИК) | +| `/tmp/fix_shnur_zvezda.py` | ✅ **правка 12 строк** (`Шнуров`→`Ленинград`, `NONSONS - zvezda`→`zvezda`) | +| `APPLY-PLAN.csv.bak-before-shnur-zvezda-20260927-174058` | бэкап плана до этой правки | +| `/tmp/final_verify.py` | ✅ проверка перегенерированного диффа (18 album + 6 albumartist найдены) | +| `/tmp/verify_new_diff.py` | сравнение album-строк старого/нового диффа (152→164) | + +### 📊 ИТОГ СЕССИИ 18 — 4 волны правок `APPLY-PLAN.csv` + +| Волна | Строк | Скрипт | Бэкап | +|---|---:|---|---| +| Скобочный мусор в `album` | 306 | `/tmp/fix_album_306.py` | `.bak-before-album-305fix-20260927-173213` | +| 3 дефекта (склейка/чужой aa/название песни) | 58 | `/tmp/fix_3defects.py` | `.bak-before-3defects-20260927-173855` | +| Шнуров + `zvezda` | 12 | `/tmp/fix_shnur_zvezda.py` | `.bak-before-shnur-zvezda-20260927-174058` | +| **ИТОГО** | **371** | | 3 бэкапа | + +**ФИНАЛЬНЫЕ ПРОВЕРКИ ПО ФАЙЛУ (не по коду):** +``` +new_album начинается со скобки: 0 +Папок с РАЗНЫМИ new_albumartist: 1 (z Другое корень — решение Alex «не трогать») +Green Apelsin: album значений 1 ('Северный ветер') +Целевые значения в DIFF-new-vs-38-v2.csv: 18/18 album, 6/6 albumartist +album-строк: старый 152 → новый 164 (+12) +Старый DIFF-new-vs-38.csv: md5 4e073fe5… НЕ ТРОНУТ (mtime 15:46) +``` | `/tmp/verify_new_diff.py` | проверка попадания 15 групп в новый дифф | --- diff --git a/personal/plans/tagwriter-container.md b/personal/plans/tagwriter-container.md index 278d55e5..aa831587 100755 --- a/personal/plans/tagwriter-container.md +++ b/personal/plans/tagwriter-container.md @@ -549,7 +549,68 @@ FIELD_ORDER = sorted({"title", "artist", "albumartist", "album", "genre", "track ``` **Правило: сортировка по `field` = по алфавиту, а не по логической важности.** -### 🔴 ОТКРЫТЫЙ ДЕФЕКТ: `!Rock&Folk/Rammstein/misc` +### ✅ ЗАКРЫТО (сессия 18): `!Rock&Folk/Rammstein/misc` — дефекта НЕТ + +Alex: «**Что блядь с рамшьайно не закрыто? Какой нахуй Puhdys?! Мы меняли на misc album!**» + +**Проверка фактом по `APPLY-PLAN.csv` (135 строк Rammstein):** +``` +!Rock&Folk/Rammstein/misc → album='misc', albumartist='Rammstein' ✅ (3 файла) +``` +`Puhdys` встречается **ровно 1 раз и корректно**: в `artist` файла +`misc/Puhdys - Wut Will Nicht Sterben.mp3` (`albumartist='Rammstein'`, `album='Wilder Freiden'`) — +песня реально исполнена Puhdys, альбом принадлежит Rammstein. **Дефекта `album='Rammstein'` / +`albumartist='Puhdys'` в плане НЕТ — это был снимок ДО правок.** + +| Было (эта дока, до правок) | Сейчас (факт по файлу) | +|---|---| +| `album '' → 'Rammstein'` ❌ | `album='misc'` ✅ | +| `albumartist → 'Puhdys'` ❌ | `albumartist='Rammstein'` ✅ | + +Все 135 строк Rammstein проверены: `albumartist='Rammstein'` везде, альбомы корректные +(`Sehnsucht`, `Rosenrot`, `Herzeleid`, `Engel [Fan Edition]`, `Lost Highway`, `Du Hast`, +`Sehnsucht [Japan]`). **Открытых дефектов по Rammstein нет.** + +### 🔴 ПИТФОЛЛ: `Dockerfile.v2` на Mac — УСТАРЕВШАЯ СПРАВОЧНАЯ КОПИЯ + +Проверено в сессии 18. Файл `~/Automation/music-tags/Dockerfile.v2` содержит: +```dockerfile +FROM python:3.11-slim +RUN pip install --no-cache-dir mutagen==1.47.0 +WORKDIR /app +COPY apply_tags_v2.py /app/apply_tags_v2.py +CMD ["python3", "/app/apply_tags_v2.py", "--dry-run"] ← НЕТ ENTRYPOINT, НЕТ USER 950:950 +``` +**Фиксов дефектов 1 и 2 в нём НЕТ**, хотя выше в §«ДВА ДЕФЕКТА `Dockerfile.v2`» они описаны. +**Боевой образ `tagwriter:latest` собран С фиксами** — проверено фактом: +``` +docker inspect tagwriter:latest --format '{{json .Config.Entrypoint}} | {{json .Config.Cmd}} | USER={{.Config.User}}' +→ ["python3","/app/apply_tags_v2.py"] | ["--dry-run"] | USER=950:950 +docker run --rm --entrypoint sh tagwriter:latest -c 'id' → uid=950 gid=950 groups=950 +``` +🔴 **НЕ пересобирать образ из `Dockerfile.v2` на Mac — потеряешь `ENTRYPOINT` и `USER 950:950`.** + +### ✅ СВЕРКА АРТЕФАКТОВ ПЕРЕД ПРОГОНОМ (сессия 18, шаг 1) — 2 РАСХОЖДЕНИЯ ИЗ 2 + +Alex: «**Отлично, применяй**» → прогон **не запущен**, сначала сверка (прогон необратим). + +| Артефакт | MD5 | Вердикт | +|---|---|---| +| Скрипт Mac (`~/Automation` = `~/Downloads/tagwriter`) | `c7a2bc143e38820f2050310cbe01b799` | ✅ эталон | +| Скрипт в образе `tagwriter:latest` | `c7a2bc143e38820f2050310cbe01b799` | ✅ совпал | +| **Скрипт на NAS** `/mnt/RED_2TB/docker/arr/tagwriter/` | `c8083f9760a424d453b34f646556c1ea` | 🔴 **расходится** | +| **План на NAS** `apply-plan.csv` | `245efb55ab1de26cb5172f0754192c3d` | 🔴 **СТАРЫЙ** | +| Бэкап `Music/backup` | 50 ГБ | ✅ есть | +| `tagwriter:v2` | `e5e2437a2fda90cb6b06d6daa6330cb` | ⚠️ старая — не использовать | + +> 🔴 **Правило: перед необратимым прогоном сверять MD5 скрипта (Mac / образ / NAS) и плана +> (Mac / NAS).** Здесь расхождения нашлись в **обоих** проверенных местах — без сверки прогон +> пошёл бы по **старому плану без 371 правки** (сессия 18 внесла 371 изменение). + +**Шаг 2 (не выполнен, ждёт Alex):** `docker cp` скрипта + заливка актуального плана → MD5-сверка → +`--dry-run` → `--apply --verify` только после «go». + +### 🔴 ОТКРЫТЫЙ ДЕФЕКТ (требует проверки): `!Rock&Folk/Rammstein/misc` Alex: «**`!Rock&Folk/Rammstein/misc` - album - rammstein - неправильно**».