diff --git a/personal/plans/music-artist-albumartist-repair.md b/personal/plans/music-artist-albumartist-repair.md index 524f8bcb..af1ee381 100755 --- a/personal/plans/music-artist-albumartist-repair.md +++ b/personal/plans/music-artist-albumartist-repair.md @@ -4,7 +4,7 @@ created: '2026-09-27' updated: '2026-09-27' type: plan namespace: personal -status: session20-APPLY-306-done-nav.md-REBUILT +status: session22-add-ALBUM-ROOT-DEFECT-821-diff-blind tags: - music - metadata @@ -1040,8 +1040,141 @@ album-строк: старый 152 → новый 164 (+12) --- +## 🟣 СЕССИЯ 22-ДОП (2026-09-27) — 🔴 ДЕФЕКТ `album` В КОРНЕ АРТИСТА: ДИФФ СЛЕП К НЕМУ (821 ФАЙЛ) + +> **ТРИГГЕР:** Alex, открыв Navidrome после сноса БД: «**А нам все равно, если б я был султан, +> платы паровоз — какой albumartist и album? Они же в песнях для детей лежат? Почему они не в одном +> альбоме для детей оказались?**» → «**А храбрый зайчик?**» → «**Черный кот в смысле**» → +> «**Вопрос к альбому**» → «**Делай. Новый csv составляй и новый diff. Слей базу navidrome так проще +> будет и сравни с полным csv где что расходится.**» + +### 🔴 ГЛАВНЫЙ ФАКТ: 821 ФАЙЛ С УНАСЛЕДОВАННЫМ `album` — ДИФФ ИХ НЕ ВИДИТ + +Детектор «файл прямо в `<категория>/<артист>/`, а `album` ≠ имя папки артиста» (правило **D21**) +даёт **821 файл в 85 папках**. + +```python +# файл прямо в <категория>/<артист>/file.mp3 -> parts == 3 +bad = [r for r in plan if len(rel.split("/")) == 3 and norm(r["new_album"]) != parts[1]] +``` + +| Проверка | Число | +|---|---:| +| файлов с `album` ≠ имя папки артиста | **821** | +| **из них в `DIFF-new-vs-38-v2.csv` хоть одной строкой** | **0** 🔴 | +| `album`-строк в диффе всего | 164 (113 ПАПКА + 51 ТРЕК) | +| путей с `album`-строкой в диффе | 51 | + +🔴 **ПОЧЕМУ ДИФФ ИХ НЕ ПОКАЗЫВАЕТ.** Дифф = «новый план против волны 38». У этих 821 файла +`new_album == cur_album` (копия тега), и в 38-м было **то же самое** → **разницы нет → 0 строк**. +Это ровно **D24** (дифф ловит ИЗМЕНЕНИЕ, а не ПРАВИЛЬНОСТЬ) в самом дорогом виде: дефект +унаследован от источника и присутствует в обеих версиях плана. + +> Следствие: **вопрос «почему оно всё ещё там» имеет ответ «дифф его никогда не показывал»**, +> а не «правку потеряли». Скрипт-правка — `/tmp/diff_album_check.py`. + +### 🔴 МЕХАНИКА ДЕФЕКТА: ПРАВИЛО КОРНЯ ПРИМЕНЕНО К `albumartist`, НО НЕ К `album` + +Факт по `!Retro/Руки` (12 файлов): + +``` +cur_album 'Сделай еще громче' -> new_album 'Сделай еще громче' ← СКОПИРОВАНО (не переопределено) +cur_album 'Супер ДискотЭка…' -> new_album 'Супер ДискотЭка…' ← копия, со спамом из тега +cur_album '' -> new_album 'Руки' ← корень применён +cur_albumartist '' -> new_albumartist 'Руки Вверх' ← корень применён +``` + +**Прогон делает `new_album = cur_album` при непустом `cur_album`; имя корня подставляется только +когда тег пуст.** Поэтому мусор и чужой релиз остаются на месте. `albumartist` при этом правится +всегда — отсюда асимметрия, которую Alex и заметил. + +### 🔴 `Храбрый Зайчик` — ОТВЕТ НА ВОПРОС ALEX (найдено фактом) + +``` +!Retro/Тамара Миансарова/Чёрный кот.mp3 + artist Тамара Миансарова + albumartist Тамара Миансарова + album 'Храбрый Зайчик. Песни для детей' ← чужой релиз, унаследован из тега + cur_album 'Храбрый Зайчик. Песни для детей' +``` + +Файл лежит **в `!Retro/Тамара Миансарова`**, а не в `!Детские` — поэтому правило корня дало +`albumartist = Тамара Миансарова`, но `album` остался от тега. **«В детский альбом» он не попал +потому, что физически лежит не в детской папке, а правило смотрит только на путь.** + +Три разных файла «Чёрный кот» в библиотеке: + +| путь | album | albumartist | +|---|---|---| +| `!Retro/Тамара Миансарова/Чёрный кот.mp3` | `Храбрый Зайчик. Песни для детей` | Тамара Миансарова | +| `!Retro/БРАВО - ЧЕРНЫЙ КОТ.mp3` | `Retro` | Various Artists | +| `!Rock&Folk/Браво/Чёрный кот.mp3` | `Браво` | Браво | + +Аналогично «Если б я был султан» / «Постой паровоз» / «А нам все равно» — **`!Retro/Юрий Никулин`, +3 файла, `album='Песни'`**, класс `АЛЬБОМ` (не `ДЕТСКИЕ`). + +### 🔴 КАНДИДАТЫ НЕ РАВНЫ ДЕФЕКТАМ: 1251 ≠ дефект, у 439 это НОРМАЛЬНЫЙ альбом + +Первый прогон правила «корень = имя папки» дал **1251 правку в 109 папках**. Сверка с БД +Navidrome показала, что так делать нельзя — часть «кандидатов» это реальные альбомы: + +``` +Сборник нового рока Various Artists 199 ← правило сломало бы: 'Sbornik_Novij_Rok' +Детский Хит Сезона Детские песни 156 ← ломать нельзя +Северный ветер Green Apelsin 11 ← реальный альбом +``` + +**Классификация 1251 кандидата** (`/tmp/classify_album_root.py`): + +| Класс | Число | Что это | Правильно ли трогать | +|---|---:|---|---| +| `ПУСТОЙ` | **558** | `album` пуст | ✅ ставить имя корня | +| `ДРУГОЙ_РЕЛИЗ` | **439** | `Пятница` (`5'nizza`), `Город дорог` (Guf), `In Search of Sunrise 3` (Tiesto), `N1NTENDO` | 🔴 **НЕ трогать** — реальные альбомы | +| `СОДЕРЖИТ_ИМЯ_ПАПКИ` | **161** | `Храбрый Зайчик…` у Миансаровой — чужой релиз | ⏳ решение Alex | +| `МУСОР/СПАМ` | **93** | `Non spécifié`/`NULL` (Benassi Bros), `2005` (Банд Эрос), `(Авария)`, `http://butt-head.ru`, `(zvezda)`, `(Агата)` | ✅ ставить имя корня | + +> 🔴 **Правило «корень = имя папки» НЕЛЬЗЯ применять массово** — оно сломает 439 настоящих +> альбомов. Это тот же класс, что **D23/D30** (детектор по форме даёт тысячи ложных). +> **Сначала классифицировать, потом спрашивать решение по классам.** + +### 📦 АРТЕФАКТЫ СЕССИИ + +| Файл | md5 / строк | Что | +|---|---|---| +| ⭐ `~/Downloads/music-tags/ALBUM-ROOT-FIX.csv` | `6616a4fbc9b007427fce9d9c48d1be58` · **1251** | кандидаты: `path, folder, cat, artist_folder, cur_album, cur_albumartist, new_album, new_albumartist, reason` — **НЕ УТВЕРЖДЁН**, требует решения по классам | +| `/tmp/dump_navidrome.py` | — | слив БД: `media_file` → `/tmp/navidrome_media_file.tsv` (**8167** строк), `album` → `/tmp/navidrome_album.tsv` (**837**) | +| `/tmp/root_album_check.py` | — | детектор 821 файла | +| `/tmp/diff_album_check.py` | — | 🔴 **доказательство слепоты диффа**: 821 → в диффе **0** | +| `/tmp/make_album_root_fix.py` | — | построение `ALBUM-ROOT-FIX.csv` | +| `/tmp/classify_album_root.py` | — | классификация 558/439/161/93 | +| `/tmp/show_targets.py` | — | построчный вывод по конкретным папкам | +| `/tmp/find_kot.py`, `/tmp/find_zaychik.py`, `/tmp/find_detskie.py` | — | поиск по плану | + +Команда слива БД (на NAS, `sqlite3` **есть напрямую** — `/usr/bin/sqlite3` 3.40.1): + +```bash +ssh truenas_admin@mallexxx.duckdns.org 'python3 /tmp/dump_navidrome.py' +# media_file 68 колонок; выгружено 13: id,path,title,artist,album_artist,album,genre, +# track_number,disc_number,year,size,missing,updated_at +``` + +### ⏭ ОТКРЫТО — ЖДЁТ РЕШЕНИЯ ALEX (4 класса) + +| # | Класс | Число | Предложение | +|---|---:|---|---| +| 1 | `ПУСТОЙ` | 558 | ставить имя корня артиста | +| 2 | `МУСОР/СПАМ` | 93 | стирать, ставить имя корня | +| 3 | `СОДЕРЖИТ_ИМЯ_ПАПКИ` (`Храбрый Зайчик`) | 161 | имя корня или оставить релиз? | +| 4 | `ДРУГОЙ_РЕЛИЗ` | 439 | **не трогать** (по умолчанию) | + +Плюс: **пункт 6 «Перегенерация `DIFF-new-vs-38-v2.csv`»** и **пункт 7 «валидатор смысла +`new_album`»** из остаточных дефектов — оба подтверждены этой сессией как реальные. + +--- + ## 🔵 СЕССИЯ 17 (2026-09-27) — ПОВТОРНЫЙ РУЧНОЙ ПРОХОД ДИФФА, ЧИТАТЬ ПЕРВЫМ + > ``` > APPLY-PLAN.csv 7861 строка md5 42d32ede85fef1b2fad6e2ce87012b7f (✅ ИЗМЕНЁН gluefix) > DIFF-new-vs-38.csv 2852 строки md5 4e073fe50c191cc50015d3f15f6a6d28 (✅ ПЕРЕГЕНЕРИРОВАН)