diff --git a/family/how-to/navidrome-truenas-android.md b/family/how-to/navidrome-truenas-android.md index 65c45aed..a6047244 100755 --- a/family/how-to/navidrome-truenas-android.md +++ b/family/how-to/navidrome-truenas-android.md @@ -392,8 +392,16 @@ artist=Maria Makarova (organ) ← исполнитель вмес - [x] ~~Пробросить порт / настроить Caddy subdomain~~ → ✅ `music.mallexxx.duckdns.org`, сертификат Let's Encrypt выпущен - [x] ~~Исключить бэкап-папки~~ → ✅ `.ndignore` (формат подтверждён строками в бинаре) -- [ ] 🔴 **Выгрузить CSV по 306 файлам со «скобочным» `album`** → решение Alex по подходу -- [ ] 🔴 **Проверить, не проиндексировались ли бэкап-папки** (8043 vs 7861) — запрос к БД +- [x] ~~Выгрузить CSV по «скобочному» `album`~~ → ✅ **ВЫПОЛНЕНО**: + `~/Downloads/music-tags/REPORT-new-album-equals-cur.csv` (6202 строки) + + `REPORT-album-kept-all-folders.csv` (558 папок с классификацией kind). + **Уточнено: реальный мусор — 9 папок / 265 треков** (только значения-огрызки в скобках). +- [ ] 🔴 **БЛОКЕР: решение Alex по правке `album` для 9 папок** — какой `album` ставить + (имя папки / реальный альбом из источника). Полный разбор — + [[personal/plans/music-artist-albumartist-repair]] §СЕССИЯ 18. +- [ ] ⚠️ **Проверить, не проиндексировались ли бэкап-папки** (8043 трека vs 7861 на диске, + т.е. +182) — запрос к БД Navidrome. ⚠️ **Скан завершён, проверка НЕ выполнена.** + `.ndignore` создан ПОСЛЕ первого скана → нужен рескан или проверка БД. - [ ] 🔴 **АКТИВНО (2026-09-27): ремонт `artist` + `albumartist` по 7861 файлу** — правила Alex зафиксированы, идёт ручная разбивка по группам. План — [[personal/plans/music-artist-albumartist-repair]] diff --git a/personal/plans/music-artist-albumartist-repair.md b/personal/plans/music-artist-albumartist-repair.md index 8a9ba42e..1957285a 100755 --- a/personal/plans/music-artist-albumartist-repair.md +++ b/personal/plans/music-artist-albumartist-repair.md @@ -19,11 +19,16 @@ related: - '[[personal/tech/music-tags-repair-truenas]]' - '[[personal/plans/tagwriter-container]]' - '[[family/how-to/navidrome-truenas-android]]' -status: session17-gluefix-applied-image-deployed-dryrun-ok-awaiting-apply-go +status: session18-navidrome-deployed-album-kept-defect-open # Music `artist` + `albumartist` Repair — правила Alex и ход работ ## 🟣 СЕССИЯ 18 (2026-09-27) — NAVIDROME РАЗВЁРНУТ, ВСКРЫТ ДЕФЕКТ-КЛАСС «ОСТАВЛЕНО КАК ЕСТЬ» +> **СТАТУС СЕССИИ 18:** Navidrome ✅ развёрнут и работает (см. ниже + `[[family/how-to/navidrome-truenas-android]]`). +> Вскрыт дефект-класс `new_album == cur_album` (6202 строки, 79%). Уточнён масштаб реального мусора: +> **9 папок / 265 треков** (не 28 папок). **Решение о правке `album` НЕ принято — ждёт Alex.** +> Артефакты: `REPORT-new-album-equals-cur.csv`, `REPORT-album-kept-all-folders.csv`. + > **Контекст:** Navidrome поднят и просканировал библиотеку (8043 трека). Alex открыл UI и > спросил: «**Откуда альбомы в скобках взялись?** Типа `Дискотека Авария` — для корня, > а `(Авария)` — откуда??» → затем «**Как так получилось что что-то было оставлено?**» @@ -100,13 +105,157 @@ status: session17-gluefix-applied-image-deployed-dryrun-ok-awaiting-apply-go | `~/Downloads/music-tags/REPORT-new-album-equals-cur.csv` | **6202 строки**: `folder, album_kept, count, path, title, artist, albumartist, genre` | | `/tmp/report_kept_album.py` | генератор отчёта (группировка папка → значение → count) | +### 🔴 ОТВЕТ ALEX: дифф НЕ покрывает дефект (проверено фактом) + +Alex спросил: «**В диффе есть правила по папкам. Если принять общие правила оттуда — строки +в диффе покрывают эти проблемы? Я рассчитывал что ты вносишь исправление на всю папку, +а не "оставляешь как есть"**». + +**Гипотеза Alex НЕ подтвердилась.** Проверка скриптом `/tmp/check_diff_coverage.py` +(`DIFF-new-vs-38.csv` vs `APPLY-PLAN.csv`): + +| | Папок | Треков | +|---|---:|---:| +| `album` оставлен **и есть** запись в диффе по `album` | 67 | 469 | +| `album` оставлен **и НЕТ** записи в диффе | **491** | **5733** | + +Дифф по полю `album` содержит всего **152 записи** (101 ПАПКА + 51 ТРЕК), тогда как строк +«оставлено как есть» — **6202 в 558 папках**. **Покрытие = 469/6202 = 7,6%.** + +**Устройство диффа (из докстринга `~/Downloads/music-tags/diff_new_vs_38.py`):** +```python +ПРАВИЛА (согласовано с Alex): + 1. Изменение = new_ в 38-м != new_ сейчас. Появление новой колонки + (albumartist/genre в 38-м НЕ БЫЛО) — ТОЖЕ изменение. + 2. Схлопывание в одну запись папки — ТОЛЬКО если новое значение одинаково + у ВСЕХ файлов папки. Если хоть у одного отличается — все файлы построчно. + Никакого 'доминирующего большинства'. + 3. Ни одна правка не теряется: сумма покрытых схлопыванием + построчные == полное число. +``` +> 🔴 **Правила 1–3 — про ФОРМАТ ОТЧЁТА, не про расчет значения.** Пункт 2 («схлопывание») +> определяет, как **показать** изменение, а не каким оно должно быть. Правила «на папку брать X» +> в диффе **нет**. Дифф сравнивает `new_*` нового плана против `new_*` 38-го прогона — если мусор +> унаследован из источника, он стоит **в обоих**, дифф видит «совпало» и строки не создаёт. + +**Подтверждение гипотезы Alex, что «надо было чинить папку целиком» — ВЕРНА.** +`new_album` заполнялся **построчно** копией `cur_album` при непустом значении, **решение на +уровне папки не принималось вообще**. Следствие на примере: папка `!Барды/Владимир Высоцкий` +разошлась на **5 разных «альбомов»** (`(Высоцкий)`, `(Философские)`, `(Морские)`, `(Блатные)`, +`(Высоцкий - Разное)`) — каждый трек получил своё значение из своего тега. При правиле на папку +значения схлопнулись бы в одно и мусор был бы виден сразу. + +### 🔬 ВАЖНОЕ УТОЧНЕНИЕ: `(Авария)` — мусор в РАЗНЫХ папках, не «один альбом с двумя именами» + +Alex: «**`(Авария)` и `Дискотека Авария` — это в одной папке файлы или всё-таки из разных?**» +Проверка `/tmp/where_avaria.py` — **из РАЗНЫХ папок**: + +| Папка | Файлов | `album` в тегах | +|---|---:|---| +| `Дискотека Авария/Москва пьёт пиво` | 17 | `(Авария)` — все 17 | +| `Дискотека Авария/Старые хиты` | 10 | `(Авария)`×7 + `Марафон`, `Старые хиты`, `ХХХиРНР` | +| `Дискотека Авария` (корень) | 7 | пусто ×4 + `(Авария)`×2 + мойибаке ×1 | +| `!Retro` (другая категория) | 4 | `(Авария)` | +| `Дискотека Авария/2006 - Четверо парней` | 17 | `Четверо парней`×16 + `Четверо Парней`×1 | +| `Дискотека Авария/Дискотека авария - Суровый Рэп CDM` | 7 | `Суровый рэп` | +| `Дискотека Авария/Маньяки` | 12 | `Маньяки` | + +> 🔑 **Один мусорный тег `(Авария)` размазан по ЧЕТЫРЁМ разным папкам-альбомам.** Поскольку +> `new_album` копировался построчно, мусор закрепился в `Москва пьёт пиво` **и** в `Старые хиты` +> одновременно. При правиле «на папку» `Москва пьёт пиво` получила бы своё имя, и мусор исчез. + +### 📋 ПОЛНЫЙ СПИСОК КОСЯЧНЫХ ПАПОК — 28 штук (артефакт по требованию Alex) + +Скрипт `/tmp/report_all_junk_folders.py`, CSV: +**`~/Downloads/music-tags/REPORT-album-kept-all-folders.csv`** +(колонки `kind, folder, files, unique_albums, values`; 558 папок со «оставлено как есть»). + +| Класс | Папок | +|---|---:| +| МУСОР (все значения мусорные) | **18** | +| СМЕШАННАЯ (часть мусор) | **10** | +| OK | 530 | + +**МУСОРНЫЕ — 18 папок, 358 треков:** + +| Треков | Папка | Значение | +|---:|---|---| +| 97 | `!Барды/Владимир Высоцкий/Филосовские` | `(Философские)` | +| 44 | `!Барды/Владимир Высоцкий/Разное` | `(Высоцкий - Разное)` | +| 42 | `!Барды/Владимир Высоцкий/Блатные` | `(Блатные)` | +| 23 | `!Рэп/Gazgolder - К тебе (2015)` | `Gazgolder. к тебе` | +| 21 | `!Rock&Folk/ЗАХАР МАЙ/изBESTняк/CD 1` | `изBESTняк` | +| 21 | `!Rock&Folk/ЗАХАР МАЙ/изBESTняк/CD 2` | `изBESTняк` | +| 17 | `!Pop, Club, Любэ/Дискотека Авария/Москва пьёт пиво` | `(Авария)` | +| 17 | `!Барды/Владимир Высоцкий/Морские` | `(Морские)` | +| 16 | `!Барды/Владимир Высоцкий/Из сказок` | `(Из Сказок)` | +| 15 | `z Другое…/Ленинград/2001 - Made In Жопа` | `Made In Жопа` | +| 14 | `!Барды/Владимир Высоцкий/Спортивные` | `(Спортивные)` | +| 14 | `z Другое…/Ленинград/2002 - Пираты XXI века` | `Пираты XXI века` | +| 12 | `z Другое…/Сектор Газа/1999 - Extasy (Ремиксовый альбом)` | `Extasy (Ремиксовый альбом)` | +| 11 | `!Rock&Folk/NONSONS - zvezda` | `(zvezda)` | +| 11 | `!Rock&Folk/Ария, Кипелов/A Tribute To Ария` | `A Tribute To Ария` | +| 10 | `!Rock&Folk/Агата Кристи/1998 - rmx Два korablya` | `Два korablya` | +| 4 | `!Рэп/Вилли Токарев` | `(Вилли Токарев)` | +| 2 | `!Pop, Club, Любэ/Дискотека Авария` | `(Авария)` | + +**СМЕШАННЫЕ — 10 папок:** + +| Треков | Папка | Значения | +|---:|---|---| +| 51 | `!Retro` | `Просвистела`×5, `Супер ДискотЭка…`×4, **`(Авария)`×4**, `Опиум`×3, … | +| 29 | `!Барды/Владимир Высоцкий` (корень) | **`(Высоцкий)`×24**, `Песни о войне`×2, `Вертикаль (OST)`, `Песни для театра и кино`, **`(Блатные)`×1** | +| 23 | `!Retro/Забугр` | `Pride`×6, `Happy Nation`×4, `Very Best`×3, `Showbiz`×2, … | +| 10 | `!Pop, Club, Любэ/Дискотека Авария/Старые хиты` | **`(Авария)`×7**, `Марафон`, `Старые хиты`, `ХХХиРНР` | +| 10 | `!Rock&Folk/Пилот/misc` | `Квартирник, Тверь`×2, `сингл "Проводник"`×2, `Live in ПОЛИГОН`, … | +| 5 | `!Rock&Folk/Несчастный Случай` | **`(Несчастный Случай)`×4**, `Несчастный случай: 30 лет. Лучшее.` | +| 5 | `!Pop, Club, Любэ/Глюкоzа` | `NOSTRA`×4, `Глюк'OZA Nostra`×1 | +| 5 | `!Классика` | 5 разных реальных альбомов — **НОРМА** | +| 5 | `z Другое…/Классика` | 5 реальных альбомов — **НОРМА** | +| 3 | `!Рэп/Птаха - Красивые, богатые (2009)` | `Chek this sound`, **`(prod. Shorty)`**, `Новый русский хип-хоп. Vol 2` | + +### 🔴 ПОПРАВКА ALEX: значения БЕЗ скобок — НЕ мусор + +Alex: «**Чем тебе не угодили те которые не в скобках??**» + +**Он прав.** Классы `МУСОР` в моём отчёте содержат осмысленные значения, ошибочно отнесённые +к дефектным. **Мусор — ТОЛЬКО огрызок в скобках**, где из тега вырвано слово: + +`(Авария)` · `(Философские)` · `(Морские)` · `(Высоцкий - Разное)` · `(Блатные)` · +`(Из Сказок)` · `(Спортивные)` · `(zvezda)` · `(Вилли Токарев)` · `(Высоцкий)` · +`(Несчастный Случай)` · `(prod. Shorty)` + +**НЕ мусор (осмысленные названия, я зря приписал):** + +| Папка | Значение | Что это на самом деле | +|---|---|---| +| `!Рэп/Gazgolder - К тебе (2015)` | `Gazgolder. к тебе` | реальный альбом «К тебе» | +| `ЗАХАР МАЙ/изBESTняк/CD 1`, `CD 2` | `изBESTняк` | реальное название сборника | +| `Ленинград/2001 - Made In Жопа` | `Made In Жопа` | реальный альбом | +| `Ленинград/2002 - Пираты XXI века` | `Пираты XXI века` | реальный альбом | +| `Сектор Газа/1999 - Extasy (Ремиксовый альбом)` | `Extasy (Ремиксовый альбом)` | реальный альбом | +| `Ария, Кипелов/A Tribute To Ария` | `A Tribute To Ария` | реальный трибьют | +| `Агата Кристи/1998 - rmx Два korablya` | `Два korablya` | реальный ремикс-альбом | +| `!Retro`, `!Retro/Забугр` | `Просвистела`, `Pride`, … | сборники, значения — реальные альбомы | +| `Пилот/misc` | `Квартирник, Тверь`, `Live in ПОЛИГОН` | реальные записи (`misc` — подпапка) | +| `Глюкоzа` | `NOSTRA`, `Глюк'OZA Nostra` | один альбом, две записи | + +> 🔑 **ИТОГ УТОЧНЕНИЯ: чинить надо 9 папок / 265 треков**, а не 28 / 358. +> **6 папок полностью** (`(Философские)`, `(Высоцкий - Разное)`, `(Блатные)`, `(Морские)`, +> `(Из Сказок)`, `(Спортивные)`, `(Авария)`×2, `(zvezda)`, `(Вилли Токарев)`) + +> **3 папки частично** (корень Высоцкого, `Старые хиты`, `!Retro`, `Птаха`). +> **Правило: мусор определяется по паттерну «значение целиком в скобках», а не по «странности» +> названия. Отсутствие скобок = значение легитимно.** + ### ⏭ Что нужно решить (ждёт Alex) 1. **Валидатор смысла `new_album`** — паттерны: огрызок в скобках `^\(.+\)$`, заглушки (`нет альбома`, `NULL`, `no title`, `Album`, `Non spécifié`), спам-URL. **В пайплайне его нет.** -2. Для 306 «скобочных» — какой `album` ставить: реальное название из внешнего источника, - имя подпапки, или имя папки артиста. +2. Для «скобочных» папок — какой `album` ставить: реальное название из внешнего источника, + имя подпапки, или имя папки артиста. **Кандидат-правило:** `album` = имя папки + минус год; для `misc`/`disk`/`base`/`plux` — имя ПОДпапки; для корня артиста — имя папки. 3. Регистровые дубли (`Четверо Парней`/`Четверо парней`, `Бунт на Корабле`) — канонизация. +4. 🔴 **Правило «на всю папку», которого не хватало:** `album` решать на уровне ПАПКИ, + не построчно. Построчное наследование `cur_album` — корень дефекта. ---