From c8778307e9d1665efb8c0b078a481485bb2e65c2 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Sun, 27 Sep 2026 20:49:21 +0600 Subject: [PATCH] [2026-09-27] eagle: personal/plans/music-artist-albumartist-repair.md personal/tech/music-tags-repair-truenas.md --- .../plans/music-artist-albumartist-repair.md | 136 +++++++++++++++++- personal/tech/music-tags-repair-truenas.md | 45 +++++- 2 files changed, 179 insertions(+), 2 deletions(-) diff --git a/personal/plans/music-artist-albumartist-repair.md b/personal/plans/music-artist-albumartist-repair.md index 368ab102..81e4ec3d 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: session29sexies-SBORNIK-BLOCKER-CLOSED-CONTAINER_FOLDERS-fix-4878 +status: session29okti-CANON-DIFF-v3-BUILT-SORT-FIXED tags: - music - metadata @@ -21,6 +21,76 @@ related: - '[[family/how-to/navidrome-truenas-android]]' # Music `artist` + `albumartist` Repair — правила Alex и ход работ +## ✅ СЕССИЯ 29-СЕПТИ (2026-09-27) — ВЕРИФИКАЦИЯ «КОРОТКОГО СПИСКА ОПЕЧАТОК»: ВСЁ УЖЕ СТОИТ, v3 НИЧЕГО НЕ ТЕРЯЕТ + +> **ТРИГГЕР:** «**учел фикс опечаток типа "Муммий тролль" "филосовские" из того же короткого списка??**» +> → «**ты сам ответил где искать**» → «**сука ты все правки из короткого списка учел?! все блядь +> готово?!**» + +### 🔑 ГЛАВНЫЙ ВЫВОД: НИ ОДНОЙ ПРАВКИ ДЕЛАТЬ НЕ НАДО — ВСЁ В `APPLY-PLAN.csv` + +Вопрос Alex означал: унаследует ли v3-генератор (правило корня поверх `new_*`) ручные правки +опечаток. Проверка по самому файлу → **все 6 правок короткого списка НА МЕСТЕ**. Скрипт: +**`/tmp/check_shortlist_full.py`** (читает CSV парсером, считает по НУЖНЫМ колонкам). + +``` + new cur статус +artist: Простоквашено (опечатка) 0 0 OK +artist: Агата кристи (строчная) 0 0 OK +artist: 11 Track 11 0 1 OK ← в cur остался, в new вычищен +artist: Josh Wink 1 0 (цель правки) +album: Infected Mushroom - Compilations 0 0 OK +album: Radio - (склейка) 0 0 OK +album: Бард - Авангард (склейка) 0 18 OK ← в cur 18, в new вычищено +album: Бард-авангард 18 0 (цель правки) +album: Non spécifié/NULL/no title/NoTitLe/Album/melody.az/mix 0 в new_album OK +``` + +**Следствие для архитектуры:** раз все ручные правки живут в `new_*` канона, v3-генератор +(правило корня **поверх** плана, а не перегенерация) их наследует **автоматически** — это +ровно то, ради чего выбиралась архитектура «от `new_*`, не с нуля» (см. § СЕССИЯ 29-СЕКСИ). + +### 🔴🔴 ПИТФОЛЛ СЕССИИ: `grep` ПО ВСЕМУ ФАЙЛУ ДАЁТ ЛОЖНУЮ ТРЕВОГУ «ПРАВКИ ОТКАТИЛИСЬ» + +Первый прогон: `grep -c "Простоквашено" APPLY-PLAN.csv` → **2**, `"Агата кристи"` → 2, +`"Infected Mushroom - Compilations Tracks"` → 12, `"Бард - Авангард"` → 18. +Вывод «часть правок откатилась» — **ЛОЖНЫЙ**. + +**Причина:** опечатки живут в колонке **`title`** (название песни), а правки — в +`new_artist`/`new_album`. Файл при этом ОДИН И ТОТ ЖЕ и не менялся. + +Доказательство (строка 6947): +``` +title = "Все, как он сказал (Би-2 + Агата кристи)" ← строчная "к" в названии ПЕСНИ, так и должно +new_artist = "Би-2 + Агата Кристи" ← правка СТОИТ ✅ +``` + +🔑 **ПРАВИЛО: «есть ли правка в файле» проверяется по КОЛОНКЕ через CSV-парсер, НЕ через +`grep` по файлу.** `grep` по всему CSV отвечает на вопрос «встречается ли строка в файле», а +не «стоит ли она в поле назначения». Это тот же класс ошибки, что `awk -F','` по путям с +запятыми (сессия 29-секси) и `grep -c ',yes$'` (сессия 19). + +### ✅ РАЗРЕШЁН ОТКРЫТЫЙ ВОПРОС «`Муммий` vs `Мумий`» (висел с 09:08 протокола) + +Факт по колонкам: +``` +'Муммий' в new_album/new_artist = 0 ← в ТЕГАХ опечатки НЕТ, там 'Мумий Тролль' (95 artist, 13 album) +'Муммий' в path = 88 ← опечатка ТОЛЬКО в имени папки на диске +``` +**Теги уже правильные.** Остаётся лишь расхождение имени папки на диске +(`!Rock&Folk/Муммий Тролль/`, 88 файлов) с правильным написанием группы — **правка тегов +не требуется**; вопрос переименования папки вынесен Alex (решение не принято). +⚠️ Ранее я озвучивал **176** — это был **счёт вхождений по двум колонкам подряд**, а не число +файлов. Правильная цифра файлов — **88** (`path`). + +### 🎯 ИТОГ: МОЯ ПРЕДЫДУЩАЯ ОЦЕНКА ПОЛЯ БЫЛА МИМО ЦЕЛИ + +Я в первой реплике сказал «`Муммий`=176, **не исправлено**, v3 не учитывает» — на самом деле +в `new_artist`/`new_album` опечатки **нет вообще**. Класс ошибки: отчёт по `grep` вместо +отчёта по колонке (см. питфолл выше). + +--- + ## 🔴 СЕССИЯ 29-СЕКСИ (2026-09-27) — ГЕНЕРАТОР ПОФИКШЕН, `apply-plan-v2.csv` СОБРАН, ДИФ К БАЗЕ СДЕЛАН > **ТРИГГЕР (последовательность):** «**нет. зайчика и "песни" мы руками не ловим. там было правило @@ -5374,6 +5444,70 @@ sorted(file_lines, key=lambda x: (fkey(x[2]), x[0], x[1])) # ТРЕК Группировка: сначала блок `ПАПКА`, затем блок `ТРЕК`, затем `НЕТ-В-38` / `ТОЛЬКО-В-38`. Вложенность ключа: поле → папка → путь. +## ✅ СОРТИРОВКА ПО `field` — АЛФАВИТНАЯ (2026-09-27, сессия 29-окти) + +Alex: «**почему сортировки по филду нету в диффе**». + +### 🔴 КОРЕНЬ: список полей был ЛОГИЧЕСКИЙ, а не АЛФАВИТНЫЙ + +Скрипт `build_canon_diff_v3.py` (сборка канонного диффа база → v3-план) сортировал по +**логическому** списку `FIELDS = [title, artist, albumartist, album, genre, track]`: + +```python +FIELD_ORDER = {f: i for i, f in enumerate(FIELDS)} # ❌ ЛОГИЧЕСКИЙ +rows.sort(key=lambda r: (FIELD_ORDER[r[3]], r[1], r[2], r[5])) +``` + +Давало `albumartist → album → genre → track` — **не по алфавиту** и **`album` после `albumartist`**. +Это ровно тот дефект, который Alex закрывал в сессии 11 +(§ СОРТИРОВКА ДИФФА — ПО `field`, выше): правило — **алфавит**. + +### ✅ ФИКС + +```python +FIELD_ALPHA = sorted(FIELDS) # album, albumartist, artist, genre, title, track +FIELD_ORDER = {f: i for i, f in enumerate(FIELD_ALPHA)} +``` + +🔑 **ПРАВИЛО (повтор): `album` ОБЯЗАН идти ПЕРЕД `albumartist`.** Любой новый генератор +диффа обязан брать `sorted(...)`, а не список в порядке объявления. Причина, по которой +дефект вернулся: скрипт писался с нуля в сессии 29-окти, и знание из сессии 11 не было +перенесено в код. **Знание в vault не защищает от повторения — оно должно быть В КОДЕ.** + +### Артефакт сессии 29-окти + +| Файл | Что | +|---|---| +| `/tmp/build_canon_diff_v3.py` | сборка канонного диффа база → `apply-plan-v3.csv`; схлопывание `(folder, field, new)`; сортировка `field → folder → path` | +| `~/Downloads/music-tags/DIFF-base-vs-applyplan-v3.csv` | **1062 записи** (710 ПАПКА + 352 ТРЕК) | +| `/tmp/apply-plan-v3.csv` | **7861 строка**, собран из `new_*` `APPLY-PLAN.csv` + правило корня | +| `~/Downloads/music-tags/APPLY-PLAN-v3-changes.csv` | **31 правка** с колонкой `reason` (`album==title`, `слово-заглушка`, `мусор-подстрока`) | + +**Распределение по полям (после фикса — порядок алфавитный):** +``` +album 27 +albumartist 6 +genre 911 +track 118 +``` +БД 7861, план 7861, сопоставлено 7861, **не найдено 0** (фильтр `path NOT LIKE 'backup%'`). + +### ⚠️ Два дефекта, найденные при верификации (НЕ закрыты) + +1. **`!Детские/Из чего же.mp3`**: `album` в БД = `[Unknown Album]` → в диффе `new` **пусто**. + Это НЕ правило корня — это потеря значения. Проверить, откуда взялось. +2. **`Sbornik_Novij_Rok`**: папка-сборник, у неё `genre` НЕ одно значение (`Folk`, `Pop`, + `Rock`, `Punk`, `Rap`) → даёт несколько ПАПКА-строк по одному полю. Для сборника ожидаемо, + но требует решения Alex: выводить сборники иначе или оставить. + +### 🔑 МЕТОД-УРОК: схлопывание `(folder, field, new)` разваливается на сборниках + +Ключ схлопывания включает `new` → если у папки несколько разных `new` по одному полю, +получается N ПАПКА-строк вместо одной сводки. Для папок-артистов (одно значение) работает +верно. Проверка перед отчётом: `uniq -c` по колонке `field` — если один `field` идёт +**неподряд**, сортировка битая; если один `folder`+`field` повторяется с разными `new` — +это сборник, не дефект. + ## 🔴 ОСТАВШИЙСЯ ДЕФЕКТ: `!Rock&Folk/Rammstein/misc` — 3 файла Обнаружен Alex в конце сессии: «**`!Rock&Folk/Rammstein/misc` - album - rammstein - неправильно**». diff --git a/personal/tech/music-tags-repair-truenas.md b/personal/tech/music-tags-repair-truenas.md index b424e8d9..b2872ec2 100755 --- a/personal/tech/music-tags-repair-truenas.md +++ b/personal/tech/music-tags-repair-truenas.md @@ -23,7 +23,42 @@ related: # Music Tags Repair — TrueNAS (7906 → 7905 файлов) -> ## 🔴 АКТУАЛЬНОЕ СОСТОЯНИЕ (2026-09-27, сессия 29-секси) — ЧИТАЙ ЭТО ПЕРВЫМ +> ## 🔴 АКТУАЛЬНОЕ СОСТОЯНИЕ (2026-09-27, сессия 29-ОКТИ) — ЧИТАЙ ЭТО ПЕРВЫМ +> +> ✅ **КАНОННЫЙ ДИФФ v3 СОБРАН:** `~/Downloads/music-tags/DIFF-base-vs-applyplan-v3.csv` +> — **1062 записи** (710 ПАПКА + 352 ТРЕК), из них `genre` 911 · `track` 118 · `album` 27 · +> `albumartist` 6. База 7861 ↔ план 7861, сопоставлено 7861, **не найдено 0**. +> Источник: `/tmp/apply-plan-v3.csv` (7861, собран из `new_*` `APPLY-PLAN.csv` + правило +> корня; **31 правка**, лог с колонкой `reason` — `~/Downloads/music-tags/APPLY-PLAN-v3-changes.csv`). +> Сборщик: `/tmp/build_canon_diff_v3.py`. +> +> 🔴 **ДЕФЕКТ СОРТИРОВКИ (найден Alex: «почему сортировки по филду нету в диффе») — ИСПРАВЛЕН.** +> Сортировка обязана быть **ПО АЛФАВИТУ**: `album → albumartist → artist → genre → title → track`, +> т.е. **`album` ПЕРЕД `albumartist`**. Скрипт писался с нуля и взял ЛОГИЧЕСКИЙ список +> (`title, artist, albumartist, album, genre, track`) → давал `albumartist → album → …`. +> Знание из сессии 11 не было перенесено в код. **Любой новый генератор дифа: +> `sorted({...})`, НЕ список в порядке объявления.** Разбор — +> [[personal/plans/music-artist-albumartist-repair]] § СОРТИРОВКА ПО `field` — АЛФАВИТНАЯ. +> +> ⚠️ **ОТКРЫТО (2 дефекта верификации v3-диффа):** +> 1. `!Детские/Из чего же.mp3` — `album` в БД `[Unknown Album]` → `new` в диффе **пусто** +> (потеря значения, не правило корня). +> 2. `Sbornik_Novij_Rok` — сборник, `genre` не одно значение (`Folk/Pop/Rock/Punk/Rap`) → +> N ПАПКА-строк по одному полю. Схлопывание `(folder, field, new)` на сборниках +> разваливается; нужно решение Alex. +> +> ✅ **ВЕРИФИЦИРОВАН «короткий список опечаток» — все 6 правок УЖЕ в `APPLY-PLAN.csv`** +> (Простоквашено 0 · Агата кристи 0 · 11 Track 11 0 · IM-склейка 0 · `Radio - ` 0 · +> Бард - Авангард 0 в `new_*`). v3-генератор их наследует автоматически, как и задумано +> архитектурой «от `new_*`, не с нуля». Скрипт проверки: `/tmp/check_shortlist_full.py`. +> 🔑 **ПИТФОЛЛ: `grep` по ВСЕМУ CSV даёт ложную тревогу «правки откатились»** — опечатки +> живут в колонке `title` (название песни). Проверять ТОЛЬКО по колонке через CSV-парсер. +> `Муммий` в `new_*` = 0 (в тегах `Мумий Тролль`), в `path` = 88 (имя папки на диске; +> **продукт не трогается — переименование папок не входило в задачу**). +> +> Подробно — [[personal/plans/music-artist-albumartist-repair]] § СЕССИЯ 29-ОКТИ / 29-СЕПТИ. + +> ## 🗄️ ПРЕДЫДУЩЕЕ СОСТОЯНИЕ (сессия 29-секси) — АРХИВ > > 🔴 **ГЕНЕРАТОР ПЛАНА НАЙДЕН И ПОФИКШЕН: `~/Developer/personal-os/tools/music-tags/build_fix_plan2.py`** > Вызов: `python3 build_fix_plan2.py INVENTORY.csv OUT.csv [HOST_ROOT]`. Ищется **только через @@ -134,6 +169,14 @@ related: > 🔑 **ПИТФОЛЛ: «Чёрный кот» пишется через Ё** — `grep "черный кот"` даёт 0 и создаёт > ложное «файла нет». Правило: искать и через `ё`, и через `е`, и без гласной. +> 🔴 **ПИТФОЛЛ (сессия 29-септи): `grep` ПО CSV ДАЁТ ЛОЖНУЮ ТРЕВОГУ «правки откатились».** +> `grep -c "Простоквашено" APPLY-PLAN.csv` → 2, `"Бард - Авангард"` → 18 — и это **не** откат: +> опечатки живут в колонке **`title`** (название песни), а правка — в `new_artist`/`new_album`. +> «Стоит ли правка в файле» проверяется **по КОЛОНКЕ через CSV-парсер**, не `grep` по файлу +> (`/tmp/check_shortlist_full.py`). Тот же класс, что `awk -F','` по путям с запятыми и +> `grep -c ',yes$'`. **Итог проверки: все 6 правок короткого списка опечаток НА МЕСТЕ в +> `APPLY-PLAN.csv`** (Простоквашено/Агата кристи/`11 Track 11`/IM-склейка/`Radio -`/`Бард-авангард`), +> `Муммий` в тегах **отсутствует** (там `Мумий Тролль`) — опечатка только в имени папки, 88 файлов. > 🔴 **Питфолл БД:** колонка — **`track_number`**, не `track`; возвращается **int**; > `0` = «номер не проставлен». > ✅ Класс **«`albumartist` размножен от чужого файла в корне папки»** — ИСПРАВЛЕН (7 папок, 40 строк).