[2026-09-27] eagle: personal/plans/music-artist-albumartist-repair.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-27 18:52:45 +06:00
1 parent 41ae82ab3c
commit a7be0a699a
1 file changed
+134 -1
@@ -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 (✅ ПЕРЕГЕНЕРИРОВАН)