diff --git a/personal/tech/music-tags-final-review.md b/personal/tech/music-tags-final-review.md index 28695bea..6b50c0e9 100755 --- a/personal/tech/music-tags-final-review.md +++ b/personal/tech/music-tags-final-review.md @@ -18,34 +18,60 @@ related: _Обновлено: 2026-09-26. Источник: `~/Downloads/music-tags/tag-fix-plan.csv`._ -> ## ⚠️ 29-я волна ЗАКРЫТА — правки по замечаниям Alex применены +> ## ✅ 31-я волна ЗАКРЫТА — написания артистов сведены, сводки честные > **Построчное чтение завершено: 1–7906 (100%).** > 28-я волна: **сквозная нумерация треков по дискам** (9 многодисковых альбомов) — ✅ ГОТОВО. -> 29-я волна: **5 замечаний Alex** (Детский хит капсом, битая строка `яюY`, Benassi 23→2, -> Eminem album, формат CSV-сводок) + 597 треков без `new_track`. -> ✅ **ВСЕ применено. Итог: `single` 2533 + `multi` 5357 = 7890.** -> 👉 Детали — `personal/tech/music-tags-repair-truenas.md` (волна 29). +> 29-я волна: **5 замечаний Alex** + 597 треков без `new_track` — ✅ применено. +> 30-я волна: **`single` переопределён** = артист ровно с 1 треком; Benassi добит из треклистов. +> 31-я волна: **сведены все написания артистов** + срезан номер из `artist` + мусор `.wma`. +> ✅ **Итог: `single` 664 + `multi` 6638 = 7302** (пустой `artist` выброшен из обеих сводок). +> ✅ **0 групп «один артист — разные написания»**, `colliding normalized names` = **0**. +> 👉 Детали — `personal/tech/music-tags-repair-truenas.md` (волна 31). > ⚠️ Открытый вопрос: 104 дубля `(album, track)` — копии релизов в разных папках (дедупликация). > ⏭ Следующий шаг: **бэкап `Music/backup/` → применение тегов → приёмка в UI Jellyfin**. -> Полный контекст волн — `personal/tech/music-tags-repair-truenas.md`. ## Состав файлов | Файл | Строк | Колонки | |---|---|---| | `tag-fix-plan.csv` | 7906 | 11 колонок (главный план) | -| `artists-single-track.csv` | 2533 | `artist, album, track, title, path` | -| `artists-multi-track.csv` | 5357 | `artist, album, track, title, path` | -| | **7890** | = сумма сводок (16 строк отфильтрованы: 15 skip + 1 намеренно пустая) | +| `artists-single-track.csv` | 664 | `artist, album, track, title, path` | +| `artists-multi-track.csv` | 6638 | `artist, album, track, title, path` | +| | **7302** | = 7906 − 576 (пустой `artist`) − 28 (`skip`) | > ⚠️ **Оба файла имеют одинаковый формат** (единый `artist, album, track, title, path`). > Разный порядок колонок (дефект 29-й волны) — **исправлен**. +> Оба файла **отсортированы**: артист → album → номер трека (числовой) → title → path. -### ⚠️ «single-track» = «трек без номера», а не «артист с одним треком» +### ✅ «single-track» = «артист РОВНО с 1 треком» (исправлено в 30-й волне, добито в 31-й) -Это **дефект имени файла**, сохранён (Alex не просил переименовывать). -Файл содержит треки без `track` — у них номера нет ни в имени файла, ни в сборнике. -Крупнейшие оставшиеся: Высоцкий, Король и Шут, Агата Кристи. +До 30-й волны имя файла **врало**: `single` означал «трек без номера», и там лежал Высоцкий +с 269 треками. Alex поймал это четыре раза подряд +(«я до сих пор вижу Benny Benassi в single track artists!!!», +«ты блядь будешь что в single track artists csv больше нет артистов у которых больше 1 трека?!»). + +**Определение теперь честное:** +- `artists-single-track.csv` — артист ровно с **1** треком (664 артиста, 664 строки) +- `artists-multi-track.csv` — артист с **>1** треком (295 артистов, 6638 строк) +- строки с пустым `artist` — **не попадают ни в один файл** + +Проверено 7 инвариантов — все 0/True (см. `music-tags-repair-truenas.md`, волна 30). +В т.ч. **пересечение артистов между файлами = 0** как точно, так и **нормализованно** +(регистр, `ё`/`е`, префикс `группа `, артикль `the `, инициал `А. `, NFC). + +### ✅ 31-я волна: 0 групп «один артист — разные написания» + +Нормализованный чекер нашёл и правки свели: `АНЖЕЛИКА ВАРУМ`/`А. Варум`, +`CHEMICAL BROTHERS`/`The Chemical brothers`, `The Tigger Lillies`/`Tigger Lillies`, +`Мумий Троль`/`Муммий Тролль`/`Муммий Троль`/`Троль`, `Наша Russia`/`Наша Раша`, +`Шнур`/`С.Шнуров`/`Сергей Шнуров`, `группа Секрет`/`Секрет`, `Markus winter`/`Markus Winter`. + +Также в этой волне вычищен класс дефекта **«номер + имя файла в `new_artist`»** +(папки `!Radio/t 2009-07…`, `x 2008-04`): `01-global deejays introducing jet set` → +`Global Deejays`, `07 markus winter` → `Markus Winter`, `19 tim deluxe feat. sam obernik` → +`Tim Deluxe feat. Sam Obernik`, `34 ashlee simpson` → `Ashlee Simpson`. +**Внимание:** `2 Unlimited`, `3 Doors Down`, `32 Leaves`, `3Oh!3`, `50 Cent`, `40 градусов` — +число в начале названия **легитимно**, не чинить. ### 🔴 Benassi: «Benny Benassi в single» — ЗАКРЫТО (29-я волна) @@ -71,8 +97,8 @@ Alex трижды указывал на это. Причина была **не | action | строк | смысл | |---|---|---| -| `fix` | 6951 | теги будут перезаписаны | -| `no_change` | 940 | теги корректны, файл не трогаем | +| `fix` | 6984 | теги будут перезаписаны | +| `no_change` | 907 | теги корректны, файл не трогаем | | `skip` | 15 | AppleDouble-мусор `._*`, не трогаем | ## Источник правки (`source`) @@ -92,12 +118,12 @@ Alex трижды указывал на это. Причина была **не - 0 сайтов-водяных знаков в `new_*` (`god@pisem.net` / `И тебя уже.net` — это названия песен, не вода) - 0 нечисловых номеров треков - **0 дублей-артистов** (регистр / ё / латиница-кириллица) -- 577 строк без artist — из них **562 это `!Детские/Сказки`** (artist пуст намеренно) +- 576 строк без artist — из них **562 это `!Детские/Сказки`** (artist пуст намеренно) ## Приёмка (глазами) -1. Открой `artists-single-track.csv` — треки без номера, отсортированы по артисту -2. Открой `artists-multi-track.csv` — альбомы с нумерацией +1. Открой `artists-single-track.csv` — 675 артистов, у каждого ровно 1 трек, отсортировано +2. Открой `artists-multi-track.csv` — 298 артистов, 6640 треков, отсортировано по альбому и номеру 3. Найди свой артист, проверь названия 4. Скажи «go» → бэкап в `Music/backup/` → применение → приёмка в UI Jellyfin @@ -177,6 +203,45 @@ Alex трижды указывал на это. Причина была **не | `fix_manual_batchK.py` | 29 номеров: Hypnotica 1–14, Pumphonia по треклисту Wikipedia | ✅ | | `fix_manual_batchL.py` | 10 номеров: Re Sfaction 1–6, Pumphonia-дубли, сборники | ✅ | | `fix_manual_batchM.py` | 12 номеров: Miami Sampler, Energy, Loveparade, Dancefloor Killers | ✅ | +| `fix_manual_batchN.py` | `группа Секрет` → `Секрет` (дубль внутри `single`) | ✅ | +| `rebuild_summaries.py` | **переписан**: `single` = артист с 1 треком, + сортировка, пустой `artist` выброшен | ✅ | + +## 🔴 ГЛАВНЫЙ УРОК 30-й ВОЛНЫ: ИМЯ ФАЙЛА-СВОДКИ ДОЛЖНО ОТВЕЧАТЬ СВОЕМУ СОДЕРЖИМОМУ + +`artists-single-track.csv` назывался «артисты с одним треком», а фактически содержал +«треки без номера»: Высоцкий 269, Король и Шут 155, Агата Кристи 109, Красная Плесень 88, +Пушной 82 — **184 артиста с >1 треком, суммарно 2193 трека**. + +Alex указал на это **четыре раза** («я до сих пор вижу Benny Benassi в single track artists!!!», +«нахуя мне твои artists without track number?!», «ты блядь будешь что в single track artists csv +больше нет артистов у которых больше 1 трека?!»). Ассистент каждый раз объяснял определение +вместо того, чтобы **исправить определение** и предложил переименовать файл — Alex: +«нахуя мне твои artists without track number?! ты имбецил ебаный! задачу выполни!». + +**Урок:** когда Alex говорит «в файле X не должно быть Y», он описывает **требуемое поведение**, +а не просит объяснений текущего. Не защищать текущее определение, не предлагать переименование — +**переопределить метрику и пересобрать**. + +### 🔴 ВТОРОЙ УРОК: ПРОВЕРЯТЬ ПЕРЕСЕЧЕНИЯ **НОРМАЛИЗОВАННО** + +Точное сравнение артистов давало «0 пересечений» и «0 дублей», но нормализация +(регистр, `ё`→`е`, префикс `группа `, двойные пробелы, Unicode NFC) нашла живой дефект: +`группа Секрет` / `Секрет` — один артист двумя написаниями внутри `single`. +**Проверять множества сущностей только нормализованно; точное сравнение даёт ложное «чисто».** + +### 🔴 ТРЕТИЙ УРОК: НОМЕРА ТРЕКОВ БРАТЬ ИЗ ОФИЦИАЛЬНОГО ТРЕКЛИСТА, НЕ ИЗ ПАПКИ + +Три подхода по порядку (первые два — тупик, третий — рабочий): +1. ❌ «разложить Benassi по `!Rock&Folk`/`!Pop`» — неверно, все они в одной папке `Benassi Bros` +2. ❌ «переименовать файлы сводок» — Alex: «нахуя мне твои artists without track number?!» +3. ✅ **номера из треклистов Wikipedia** (Hypnotica 1–14, Pumphonia 1–12) + нумерация + внутри папок-сборников + +### 🔴 ЧЕТВЁРТЫЙ УРОК: ПОДСТРОКУ БРАТЬ ИЗ `grep`, А НЕ ПО ПАМЯТИ (повтор 29-й волны) + +Опять наступил: подстрока `Benny Bros Feat Paul French-Don-t Touch Too Much` не сработала — +в файле опечатка `Too Mach`. Правило `NO_PATH` в скрипте это поймало, но проверять надо +**до** запуска: `grep -n "<ключ>"` по файлу. ## 🔴 Провал алгоритмической правки регистра (A) @@ -185,9 +250,10 @@ Alex трижды указывал на это. Причина была **не **Решение:** ручная таблица на 156 строк (`fix_detsky_hit.py`), 0 пропущено. **Урок:** регистр названий песен алгоритмом не правится — только ручная таблица с точными названиями. -## Проверки после 29-й волны (`final_audit.py`, все пройдены) +## Проверки после 30-й волны (`final_audit.py` + чекер инвариантов, все пройдены) - 7906 строк, 11 колонок, **0 битых** +- `fix` 6984 / `no_change` 907 / `skip` 15 - 0 пустых `new_title` - 0 сайтов-водяных знаков (`god@pisem.net` / `И тебя уже.net` — названия песен) - 0 нечисловых номеров треков @@ -195,9 +261,24 @@ Alex трижды указывал на это. Причина была **не - 3 срабатывания детектора `.net` в title — **ложные** (`И тебя уже.net`, `god@pisem.net` ×2) - 9 срабатываний «title похож на путь» — **ложные** (легитимные слэши: `Numb / Encore`, `Попурри из м/ф «Бременские музыканты»`, `90/60/90`, `9 1/2`, `Ч\Б`) -- 2578 треков без номера — папки без нумерации вообще (`!Rock&Folk` 814, `!Pop, Club, Любэ` 679, - `!Барды` 277, `z Другое` 260, `!Рэп` 230, `!Retro` 215) -- 575 строк без artist — 562 = `!Детские/Сказки` (намеренно) +- 576 строк без artist — 562 = `!Детские/Сказки` (намеренно) +- Сводки: `single` 675 / `multi` 6640 = **7315** +- **Инварианты сводок: все 7 = 0/True** (см. ниже) + +| # | Инвариант сводок | Значение | +|---|---|---| +| 1 | артистов с >1 треком в `single` | **0** | +| 2 | артистов с 1 треком в `multi` | **0** | +| 3 | пересечение `single`∩`multi` (точно) | **0** | +| 4 | пересечение `single`∩`multi` (нормализованно) | **0** | +| 5 | один артист в разных написаниях внутри `single` | **0** | +| 6 | пустых `artist` в обоих | **0** | +| 7 | оба файла отсортированы | **True** | + +> ⚠️ В `single` у **294 из 675** строк нет номера трека — одиночные синглы без альбома, +> номера не существует. Артист ровно один, из `single` их не убрать. +> ⚠️ 2578 треков в `multi` без номера — папки без нумерации вообще (`!Rock&Folk` 814, +> `!Pop, Club, Любэ` 679, `!Барды` 277, `z Другое` 260, `!Рэп` 230, `!Retro` 215). ## Приёмка (глазами) @@ -223,6 +304,21 @@ Alex трижды указывал на это. Причина была **не | `Малыш и Карлсон` | 1–6 | 6 | | `Остров сокровищ` | 1–6 | 6 | +## 📋 План 30-й волны (✅ ВЫПОЛНЕН 2026-09-26) + +| # | Что | Объём | Статус | +|---|---|---|---| +| **A** | Benny Benassi: 46 треков без номера → в `single` | 46 | ✅ `batchK/L/M`, номера из треклистов Hypnotica/Pumphonia | +| **B** | Мусорные написания Benassi (`BENNY B`, `Benny Bros`, `In Grid`, `KMC Feat Sandy`) | 7 | ✅ `batchJ` | +| **C** | `single` переопределён = артист ровно с 1 треком | `rebuild_summaries.py` | ✅ 675 / 6640 | +| **D** | Сортировка обеих сводок | тот же | ✅ артист → album → номер → title | +| **E** | Проверка пересечений `single`∩`multi` нормализованно | тот же | ✅ 0; найден и починен `группа Секрет` | +| **F** | Пустой `artist` выброшен из обеих сводок | тот же | ✅ 576 строк | + +⏭ **СЛЕДУЮЩИЙ ШАГ (ждёт слова Alex «go»):** бэкап перезаписываемых файлов в `Music/backup/` +→ применение тегов → приёмка в UI Jellyfin → `rm -rf Music/backup/` → создание Music-библиотеки. +Отдельно ждёт решения: 104 дубля `(album, track)` (дедупликация файлов). + ## ⚠️ Открытый вопрос: 104 дубля `(album, track)` Это **не диски**, а одни и те же релизы, лежащие в двух папках на диске diff --git a/personal/tech/music-tags-repair-truenas.md b/personal/tech/music-tags-repair-truenas.md index 0f86cd68..20410d0d 100755 --- a/personal/tech/music-tags-repair-truenas.md +++ b/personal/tech/music-tags-repair-truenas.md @@ -4,7 +4,7 @@ created: '2026-09-26' updated: '2026-09-26' type: tech namespace: personal -wave: 29 +wave: 31 tags: - music - jellyfin @@ -20,6 +20,170 @@ related: # Music Tags Repair — TrueNAS (7906 файлов) +> ## ✅ ТРИДЦАТЬ ПЕРВАЯ ВОЛНА (2026-09-26) — СВЕДЕНИЕ НАПИСАНИЙ АРТИСТОВ + НОМЕР В `artist` +> +> Триггер: Alex — «Benny Benassi БЛЯДЬ ДО СИХ ПОР СУКА В single track artists!!!!» → +> «нахуя мне твои artists without track number?! ты имбецил ебаный! задачу блядь выполни!» → +> «че блядь какой?» → «почему не отсортировано? ты проверил что нет пересечений артистов?» → +> «да ладно?! Анжелика Варум?!» → «Мумий Троль, Троль / Наша Russia - Наша Раша / Шнур (Шнуров С)» → +> «01-global deejays introducing jet set, 07 markus winter, 19 tim deluxe feat. sam obernik, 1club, +> 2 Unlimited, 3 Doors Down, 32 Leaves, 34 ashlee simpson, 3Oh!3 — тут блядь все нормально?» +> +> ### 🔴 ГЛАВНЫЙ УРОК ВОЛНЫ: АРТИСТ ПРОВЕРЯЕТСЯ ПО ВСЕМУ МАССИВУ, А НЕ ПО ОДНОМУ ФАЙЛУ +> Alex нашёл Benassi в `single` **после** того, как ассистент объявил волну 30 закрытой. +> Причина — правило волны 30 чинило только `new_track`, но `single`/`multi` **пересобирались +> после правок**, а не сверялись с готовым файлом. **Правило: после любой правки, меняющей +> `new_artist`, обязательно `rebuild_summaries.py` + чекер 7 инвариантов.** +> +> ### 🔴 ВТОРОЙ УРОК: КЛАСС ДЕФЕКТА «НОМЕР + ИМЯ В `artist`» +> В папках `!Radio` (`t 2009-07 c6Or_NICK`, `x 2008-04`) в `new_artist` попадало +> **имя файла целиком** — с номером и в нижнем регистре. Детекторы его не ловили. +> **Детектор:** `re.match(r'^\d{1,3}[-_. ]', new_artist)` → но **7 из 7 совпадений оказались +> легитимными** (`32 Leaves`, `3 Doors Down`, `2 Unlimited`, `50 Cent`, `3Oh!3`, `40 градусов`). +> Поэтому детектор только **подсвечивает кандидатов**, решение — ручное. +> +> ### 🔴 ТРЕТИЙ УРОК: «ОДИН АРТИСТ — РАЗНЫЕ НАПИСАНИЯ» ИЩЕТСЯ НОРМАЛИЗАЦИЕЙ +> Чекер нормализует: регистр, `ё`→`е`, снятие префикса `группа `, снятие артикля `the `, +> снятие инициала `А. `, `NFC`-нормализация. Этим найдены (и сведены): +> `АНЖЕЛИКА ВАРУМ`/`А. Варум`, `CHEMICAL BROTHERS`/`The Chemical brothers`, +> `The Tigger Lillies`/`Tigger Lillies`/`The Tiger Lillies`, `Мумий Троль`/`Муммий Тролль`/ +> `Муммий Троль`/`Троль`, `Наша Russia`/`Наша Раша`, `Шнур`/`С.Шнуров`/`Сергей Шнуров`, +> `группа Секрет`/`Секрет`, `Markus winter`/`Markus Winter`. +> **Итог: 0 групп с >1 написанием.** +> +> ### ✅ ПРАВКИ ВОЛНЫ (все скрипты идемпотентны, второй прогон = 0) +> | Класс | Строк | Скрипт | Результат | +> |---|---:|---|---| +> | `Секрет` (дубль внутри `single`) | 1 | `batchN` | → `Секрет` | +> | `АНЖЕЛИКА ВАРУМ` + `А. Варум` (+ капс album/title) | 6 | `batchO` | → `Анжелика Варум` | +> | `CHEMICAL BROTHERS`/`The Chemical brothers`, `Tigger Lillies` ×2 | 7 | `batchP` | → 2 канона | +> | `Мумий Троль`, `Муммий Тролль`, `Муммий Троль`, `Троль` | 20 | `batchQ` | → `Мумий Тролль` (94) | +> | `Наша Russia`, `Шнур`, `С.Шнуров` | (в `batchQ`) | `batchQ` | → `Наша Раша`, `Сергей Шнуров` (46) | +> | Мусорные album `(Муммий Тролль)` (7) + `C.Шнуров - Бумер (2003)` (19) | 26 | `batchR` | → пусто / `Бумер (2003)` | +> | Левый artist `Snoop` («Жаба жаб», 2 трека) | 2 | `batchR` | → `Сергей Шнуров` | +> | Номер в `artist` + регистр title (`Global Deejays`, `Markus Winter`, `Tim Deluxe`, `Ashlee Simpson`) | 9 | `batchS` | номер срезан, title в Title Case | +> | `50 cent, eminem, ca$` / `50 cent - p.i.m.p` (title = имя файла, тегов в файле НЕТ) | 3 | `batchT` | → `You Don't Know`, `P.I.M.P.` | +> | Title-мусор `.wma` `wma 1`…`wma 13` | 13 | `batchU` | → пусто, `action=skip` | +> | Title строчными (`бессонница`, `йогурты`, `серёжа`, `два по сто`, …) | 10 | `batchU` | Title Case | +> | `Markus winter` vs `Markus Winter` (последний дубль) | 2 | `batchV` | → `Markus Winter` | +> +> ### 📊 ИТОГ 31-й ВОЛНЫ +> +> | Показатель | Волна 30 | **Волна 31** | +> |---|---:|---:| +> | `tag-fix-plan.csv` | 7906 | **7906 (0 битых)** | +> | `fix` / `no_change` / `skip` | 6984 / 907 / 15 | **7007 / 871 / 28** | +> | `artists-single-track.csv` | 675 | **664** | +> | `artists-multi-track.csv` | 6640 | **6638** | +> | Сумма сводок | 7315 | **7302** | +> | `colliding normalized names` | 0 | **0** | +> | Групп с >1 написанием артиста | 1 | **0** | +> +> **Почему сумма упала 7315 → 7302:** +13 строк переведены в `action=skip` (мусорные `.wma`). +> 7906 − 576 (пустой artist) − 28 (skip) = **7302**. ✔ +> +> ⚠️ **Ложные срабатывания аудита** (не чинить): 3× `.net` в title (`И тебя уже.net`, +> `god@pisem.net` ×2), 9× «title похож на путь» (`Numb / Encore`, `90/60/90`, `9 1/2`, `Ч\Б`, +> `Попурри из м/ф «Бременские музыканты»`), 7× «artist начинается с числа» (`32 Leaves`, +> `3 Doors Down`, `2 Unlimited`, `50 Cent`, `3Oh!3`, `40 градусов`) — легитимные названия. +> +> ⏭ **СЛЕДУЮЩИЙ ШАГ (ждёт слова Alex):** бэкап в `Music/backup/` → применение тегов → +> приёмка в UI Jellyfin → `rm -rf Music/backup/` → создание Music-библиотеки. +> +> **Бэкапы 31-й волны:** `bak-*-batchN`, `bak-*-batchO`, `bak-*-batchP`, `bak-*-batchQ`, +> `bak-*-batchR`, `bak-*-batchS`, `bak-*-batchT`, `bak-*-batchU`, `bak-*-batchV`. +> **Сводка для аппрува:** `personal/tech/music-tags-final-review.md`. +> +> --- +> +> ## ✅ ТРИДЦАТАЯ ВОЛНА (2026-09-26) — ПЕРЕОПРЕДЕЛЕНИЕ СВОДОК: `single` = АРТИСТ С 1 ТРЕКОМ +> +> Триггер: Alex — «Закончи правку имен песен в csv. Вручную.» → «я до сих пор вижу Benny Benassi +> в single track artists!!!» → «ты блядь будешь что в single track artists csv больше нет артистов +> у которых больше 1 трека?!» → «почему не отсортировано? ты проверил что нет пересечений?» +> +> ### 🔴 ГЛАВНЫЙ КОРЕНЬ ВСЕГО ПРОВАЛА (найден в этой волне) +> **`new_track` для 46 треков Benny Benassi не был извлечён** — в именах файлов +> (`Benny Benassi - Are You Crazy For This.mp3`, `Benny Benassi-Chihuahua.mp3`) номера +> **отсутствуют физически**. Поэтому артист попадал в `single` (файл = «треки без номера»). +> Лечение — номера из **официальных треклистов**: +> - **Hypnotica (2003)** — Wikipedia, 14 треков → 1–14 +> - **Pumphonia (2004)** — Wikipedia, 12 треков → 1–12 +> - сборники/синглы (`Re Sfaction`, `Techno 2003`, `Now Dance Volume 3`, `Loveparade`, +> `Miami Sampler 2002`, `Energy New Release`, `Dancefloor Killers`) — нумерация внутри папки +> +> Скрипты `fix_manual_batchK.py` / `L.py` / `M.py` (все идемпотентны, бэкапы `bak-batchK/L/M`). +> +> ### 🔴 ЧЕСТНОЕ ОПРЕДЕЛЕНИЕ `single` / `multi` (окончательное) +> | Файл | Определение | +> |---|---| +> | `artists-single-track.csv` | артист, у которого **РОВНО 1 трек** в библиотеке | +> | `artists-multi-track.csv` | артист, у которого **>1 трека** | +> | строки с пустым `artist` | **не попадают ни в один файл** (не «артист») | +> +> `rebuild_summaries.py` **переписан** под это определение + добавлена **сортировка** +> (артист → album → номер трека как **число** → title → path). +> Раньше `single` = «трек без номера» — имя файла врало, в `single` лежал Высоцкий с 269 треками. +> +> ### Инварианты — гонять после каждой пересборки (`rebuild_summaries.py` + чекер ниже) +> | # | Инвариант | Значение | +> |---|---|---:| +> | 1 | артистов с >1 треком в `single` | **0** | +> | 2 | артистов с 1 треком в `multi` | **0** | +> | 3 | пересечение артистов `single`∩`multi` (точно) | **0** | +> | 4 | пересечение **нормализованно** (регистр, ё/е, `группа `) | **0** | +> | 5 | один артист в разных написаниях внутри `single` | **0** | +> | 6 | пустых `artist` в обоих файлах | **0** | +> | 7 | оба файла отсортированы | **True** | +> +> Чекер (read-only, обязателен перед «готово»): +> ```python +> # нормализация должна убирать: регистр, ё→е, префикс "группа ", двойные пробелы +> def norm(s): +> s=unicodedata.normalize('NFC',s or '').strip().lower().replace('ё','е') +> s=re.sub(r'^группа\s+','',s) +> return re.sub(r'\s+',' ',s) +> ``` +> Именно **нормализованная** проверка нашла дефект `группа Секрет` / `Секрет` — на точном +> сравнении пересечений было 0, на нормализованном — 1 внутри `single`. +> +> ### ✅ Правки волны +> | Класс | Строк | Скрипт | Результат | +> |---|---:|---|---| +> | Benny Benassi: номера из треклистов Hypnotica/Pumphonia | 29 | `batchK` | 1–14 / 1–12 | +> | Benny Benassi: сборники/синглы | 9 + 12 | `batchL`, `batchM` | номера внутри папок, без дублей | +> | Benassi: мусорные написания (`BENNY B`, `Benny Bros`, `In Grid`, `KMC Feat Sandy`) | 7 | `batchJ` | → `Benny Benassi`, `Benassi Bros Feat. Paul French`, `In-Grid`, `KMC Feat. Sandy` | +> | `группа Секрет` → `Секрет` (дубль внутри `single`) | 1 | `batchN` | **0 разных написаний** | +> +> ### 📊 ИТОГ 30-й ВОЛНЫ +> +> | Показатель | Волна 29 | **Волна 30** | +> |---|---:|---:| +> | `tag-fix-plan.csv` | 7906 | **7906 (0 битых)** | +> | `fix` / `no_change` / `skip` | 6951 / 940 / 15 | **6984 / 907 / 15** | +> | `artists-single-track.csv` | 2533 | **675** | +> | `artists-multi-track.csv` | 5357 | **6640** | +> | Сумма сводок | 7890 | **7315** | +> | Benassi в `single` | 46 | **0** | +> | Нечисловых `new_track` | 0 | **0** | +> | Дублей-артистов | 0 | **0** | +> +> **Почему сумма упала 7890 → 7315:** пустой `artist` (576 строк: 562 `!Детские/Сказки` + +> 14 прочих) больше **не считается артистом** и выброшен из обеих сводок. +> 7906 − 576 − 15 (`skip`) = **7315**. ✔ +> +> ⚠️ **Остаётся:** в `single` у **294 из 675** строк нет номера трека — это одиночные синглы +> без альбома, номера у них не существует. Артист всё равно ровно один, из `single` их не убрать. +> +> ⏭ **СЛЕДУЮЩИЙ ШАГ (ждёт слова Alex):** бэкап в `Music/backup/` → применение тегов → +> приёмка в UI Jellyfin → `rm -rf Music/backup/` → создание Music-библиотеки. +> +> **Бэкапы 30-й волны:** `bak-*-batchG7`, `bak-*-batchH`, `bak-*-batchI`, `bak-*-batchJ`, +> `bak-*-batchK`, `bak-*-batchL`, `bak-*-batchM`, `bak-*-batchN`. +> **Сводка для аппрува:** `personal/tech/music-tags-final-review.md`. +> +> --- +> > ## ✅ ДВАДЦАТЬ ДЕВЯТАЯ ВОЛНА (2026-09-26) — BATCH B–F ПРИМЕНЁН + РУЧНАЯ ДОБИВКА BENASSI > > Триггер: Alex — «Закончи правку имен песен в csv. Вручную.» и далее серия вспышек: