[2026-09-27] eagle: personal/plans/music-artist-albumartist-repair.md personal/tech/id3-tag-repair.md
This commit is contained in:
1 parent
fbba9c65f2
commit
c486da75fa
2 files changed
+216
-5
No files matched your search
@@ -4,7 +4,7 @@ created: '2026-09-27'
|
||||
updated: '2026-09-27'
|
||||
type: plan
|
||||
namespace: personal
|
||||
status: RC-complete-defects-fixed
|
||||
status: session18-dop-diff-inventoried-folders-counted-awaiting-apply-go
|
||||
tags:
|
||||
- music
|
||||
- metadata
|
||||
@@ -19,9 +19,190 @@ related:
|
||||
- '[[personal/tech/music-tags-repair-truenas]]'
|
||||
- '[[personal/plans/tagwriter-container]]'
|
||||
- '[[family/how-to/navidrome-truenas-android]]'
|
||||
status: session18-step2-done-dryrun-ok-awaiting-apply-go
|
||||
# Music `artist` + `albumartist` Repair — правила Alex и ход работ
|
||||
|
||||
## 🟣 СЕССИЯ 18-ДОП (2026-09-27, вечер) — ИНВЕНТАРЬ ДИФФА ПО ФАКТУ, ПОСЛЕ ВОПРОСА ALEX «ГДЕ ДИФ?»
|
||||
|
||||
> **Триггер:** Alex — «**Где диф последний с 371 правкой альбомов/albumartist который ты готовил?**»
|
||||
> → затем «**Какие там записи?**». Отвечено из **Zulip DB** (по скиллу `zulip-db-forensics`),
|
||||
> затем проверено по самим файлам на диске.
|
||||
|
||||
### 📍 Местонахождение (факт с диска, mtime 2026-09-27 17:41)
|
||||
|
||||
| Файл | MD5 | Строк | Статус |
|
||||
|---|---|---:|---|
|
||||
| ⭐ `~/Downloads/music-tags/DIFF-new-vs-38-v2.csv` | `7bc222a1087787c390026d624af932f3` | **2854** | **АКТУАЛЬНЫЙ** (после 371 правки) |
|
||||
| `~/Downloads/music-tags/DIFF-new-vs-38.csv` | `4e073fe50c191cc50015d3f15f6a6d28` | 2852 | устаревший (mtime 15:46) — **НЕ трогать** (указание Alex) |
|
||||
| `~/Downloads/music-tags/milestones/RC-20260927/DIFF-RC-20260927-153717.csv` | — | — | снапшот RC |
|
||||
|
||||
Генератор — `~/Downloads/music-tags/diff_new_vs_38_v2.py` (17:32).
|
||||
|
||||
### 🧩 Состав `DIFF-new-vs-38-v2.csv` (факт, `csv.DictReader`)
|
||||
|
||||
Колонки: `scope, folder, path, field, old_38, new_apply_plan`.
|
||||
Всего **2854** строки = **2768 правок** + **86 контроль**.
|
||||
Правки = `ПАПКА` **1501** + `ТРЕК` **1267**.
|
||||
|
||||
| field | строк | что именно |
|
||||
|---|---:|---|
|
||||
| `genre` | 911 | снятие `!`-префиксов, `!Radio`→`Radio`, `!Rock&Folk`→`Rock&Folk` |
|
||||
| `track` | 883 | `#2_04_`→`4`, ведущие нули, суффиксы `-bpm`/`-aQB`/`-1king` |
|
||||
| `albumartist` | 634 | 🔴 `old_38 = '<КОЛОНКИ НЕ БЫЛО>'` → значение: колонки в 38-м **не существовало** (ср. **D3**) |
|
||||
| `album` | 164 | скобочный мусор, склейки `Артист - Год`, `Нечетный`→`Нечётный`, заполнение пустых |
|
||||
| `artist` | 134 | опечатки, регистр, лишние пробелы |
|
||||
| `title` | 42 | дубли `album == title` |
|
||||
|
||||
Разбивка по scope × field: `ПАПКА` genre 700 · aa 577 · track 76 · album 113 · artist 35 ·
|
||||
`ТРЕК` track 807 · genre 211 · artist 99 · title 42 · albumartist 57 · album 51.
|
||||
|
||||
**Контроль (86):** `ТОЛЬКО-В-38` — файлы `._*.m4a` (AppleDouble) в
|
||||
`!Pop, Club, Любэ/Infected Mushroom/(2012) Army of Mushrooms/` и не-ID3 форматы.
|
||||
Не правки, список полноты (ср. D-секцию «служебные секции в хвосте диффа»).
|
||||
|
||||
**Классы правок `album`** (примеры, полный дамп `/tmp/diff_v2_dump.txt`):
|
||||
`(Авария)`→`Москва пьёт пиво`, `(Философские)`→`Философские`, `(zvezda)`→`zvezda`,
|
||||
`(Несчастный Случай)`→`Несчастный Случай`, `Бард - Авангард`→`Бард-авангард`,
|
||||
`Нечетный`→`Нечётный`, `Земфира (2000)`→`Земфира`, `'<N разных>'`→имя подпапки/корня,
|
||||
сборники `!Retro`/`!Radio` → `Retro` + `Various Artists`.
|
||||
|
||||
> 🔴 **Число 371 ≠ число строк диффа.** `371` — это **строки `APPLY-PLAN.csv`, изменённые
|
||||
> в сессии 18** (306 + 58 + 12). Дифф показывает **дельту плана против 38-го прогона**:
|
||||
> 2768 записей, из них `album`+`albumartist` = **798 строк**, `album` = **164**.
|
||||
> ⚠️ **Не выдавать число ЗАПИСЕЙ диффа за число правок сессии и наоборот** —
|
||||
> две разные базы счёта (ср. правила счёта в [[personal/tech/id3-tag-repair]] § D-правила).
|
||||
|
||||
### 🛠 Скрипты проверки (созданы в этой сессии, `/tmp/`)
|
||||
|
||||
| Скрипт | Что делает |
|
||||
|---|---|
|
||||
| `/tmp/check_diff_v2.py` | заголовок, размер, MD5, разбивка по `scope` |
|
||||
| `/tmp/check_diff_v2b.py` | матрица `scope × field` (правки/контроль раздельно) |
|
||||
| `/tmp/dump_diff_v2.py` | полный дамп → `/tmp/diff_v2_dump.txt` (5626 строк до стопа на `head`) |
|
||||
| `/tmp/dump_diff_v2c.py` | секции `albumartist` / `artist` построчно |
|
||||
|
||||
> 🔴 **ПИТФОЛЛ (повтор D4):** `python3 dump.py 2>&1 | head -160` → `TypeError` в ветке
|
||||
> контрольной секции **дописался в лог, но файл `/tmp/diff_v2_dump.txt` остался от прошлого
|
||||
> прогона**. Дамп писать в файл и смотреть файл, а не полагаться на пайп.
|
||||
> Также: форматирование `None` через `{:12s}` падает — приводить `str(...)` для полей
|
||||
> контрольной секции (у них `field`/`path` = `None`).
|
||||
|
||||
### 🗂 РАЗБИВКА ДИФФА ПО ПАПКАМ — 633 папки, с числом файлов
|
||||
|
||||
Alex: «**Все папки**» → «**С количеством файлов**».
|
||||
|
||||
Артефакт: **`/tmp/folders_report.txt`** (639 строк, генератор `/tmp/diff_v2_folders2.py`).
|
||||
Колонки: `FOLDER · fld_edits · files_in_folder · files_changed · album · aa · artist · genre · track · title`.
|
||||
|
||||
**Верхний уровень — ровно 6 папок:**
|
||||
|
||||
```
|
||||
!Pop, Club, Любэ
|
||||
!Retro
|
||||
!Детские
|
||||
!Классика
|
||||
!Рэп
|
||||
z Другое, Enigma, Ленинград
|
||||
```
|
||||
|
||||
Остальные **627 — вложенные** (артист/альбом). `!Rock&Folk` и `!Барды` затронуты
|
||||
**только через вложенные** — верхнеуровневых строк у них нет.
|
||||
|
||||
**Топ-10 папок по числу файлов:**
|
||||
|
||||
| файлов | edits | папка |
|
||||
|---:|---:|---|
|
||||
| 203 | 8 | `!A Not sorted/Sbornik_Novij_Rok` |
|
||||
| 179 | 44 | `!Retro` |
|
||||
| 156 | 3 | `!Детские/Детский хит` |
|
||||
| 97 | 3 | `!Барды/Владимир Высоцкий/Филосовские` |
|
||||
| 71 | 18 | `!Rock&Folk/Агата Кристи` |
|
||||
| 69 | 27 | `!Rock&Folk/!rock_o_pop` |
|
||||
| 69 | 21 | `!Pop, Club, Любэ/!Radio/x 2008-04` |
|
||||
| 63 | 4 | `!Рэп/НТЛ` |
|
||||
| 61 | 31 | `!Pop, Club, Любэ/!Radio/z Старое/disk_v2/1 DRIVE` |
|
||||
| 58 | 29 | `!Pop, Club, Любэ/!Radio/z Старое/disk/1 DRIVE` |
|
||||
|
||||
> 🔴 **ПИТФОЛЛ (счёт файлов по ПАПКА-строке):** ПАПКА-строка диффа разворачивается
|
||||
> в **ВСЕ файлы папки**, включая те, у которых целевое значение уже совпадает с текущим.
|
||||
> Это даёт **фантомные файлы**. Сумма по папкам → `8852`, тогда как по плану меняется `7651`,
|
||||
> а по конкретному полю — см. ниже. **Число файлов из ПАПКА-строки ≠ число реально меняющихся файлов.**
|
||||
|
||||
### 🔴 ОШИБКА СЧЁТА `7963` ПО `genre` — ВСКРЫТА И ПРИЗНАНА
|
||||
|
||||
Alex: «**Чё за нахуй?! В смысле блядь 7963?!!!**»
|
||||
|
||||
**Что я сделал неверно:** в диффе 911 genre-строк, из них **700 — уровня ПАПКА**.
|
||||
Каждую ПАПКА-строку я развернул во **все файлы папки** и сложил → `7752 + 211 = 7963`.
|
||||
|
||||
**Правильное число по плану — `4359`** (строк `APPLY-PLAN.csv`, где `cur_genre != new_genre`).
|
||||
|
||||
```
|
||||
plan rows 7861
|
||||
genre differing files 4359 ← правда
|
||||
albumartist differing 7213
|
||||
album differing 2003
|
||||
artist differing 381
|
||||
track differing 344
|
||||
title differing 8
|
||||
ANY field differing 7651
|
||||
```
|
||||
|
||||
**Причина расхождения 7752 vs 4359 (3393 фантома):** ПАПКА-строка = «папка целиком меняет genre»,
|
||||
но у части файлов genre **уже равен** целевому — скрипт пишет значение без изменения.
|
||||
Косвенное подтверждение из плана: `distinct cur_genre` = **156** значений → `new_genre` = **64**;
|
||||
пустой genre у **2950** файлов (их и заполняют).
|
||||
|
||||
> 🔑 **МЕТОД-УРОК (счёт файлов):** **ПАПКА-строка диффа разворачивается в файлы, которых
|
||||
> правка не касается.** Для числа «реально меняющихся файлов» считать **по `APPLY-PLAN.csv`**
|
||||
> (`cur_X != new_X`), а не по диффу. Дифф отвечает на вопрос «что изменилось против 38-го прогона»,
|
||||
> план — «что реально отличается от целевого». **Две разные базы счёта** (ср. §Число 371 ≠ строки диффа).
|
||||
> Проверочный скрипт: `/tmp/explain_genre.py`.
|
||||
|
||||
### 🧾 Список удаления скобок — ГДЕ ЛЕЖИТ (ответ на «Где список с удалением скобок»)
|
||||
|
||||
Alex: «**Где список который ты готовил с удалением скобок**»
|
||||
|
||||
**Два файла, оба mtime 2026-09-27 17:21–17:32:**
|
||||
|
||||
| Файл | MD5 | Строк | Назначение |
|
||||
|---|---|---:|---|
|
||||
| ⭐ `~/Downloads/music-tags/ALBUM-FIX-TABLE.csv` | `1597f2716ac5a2881efabaec13755d4c` | **306** | читаемая таблица: `folder, cur_album, new_album, path, title` |
|
||||
| `~/Downloads/music-tags/ALBUM-FIX-306.csv` | `49ba645462964cc299da7dcffb55ca09` | **306** | + `new_album_was` / `new_album_now` (история уточнения значения) |
|
||||
|
||||
**Факт (`csv.DictReader`):** `cur_album` начинается с `(` — **306 из 306**, значение **целиком
|
||||
в скобках** — **306 из 306**, уникальных путей **306**, уникальных пар «папка+было→стало» — **17**.
|
||||
|
||||
**17 пар (полный список):**
|
||||
|
||||
| папка | было | стало |
|
||||
|---|---|---|
|
||||
| `!Барды/Владимир Высоцкий` | `(Высоцкий)` | `Высоцкий` |
|
||||
| `!Барды/Владимир Высоцкий/Морские` | `(Морские)` | `Морские` |
|
||||
| `!Барды/Владимир Высоцкий/Филосовские` | `(Философские)` | `Философские` |
|
||||
| `!Барды/Владимир Высоцкий/Спортивные` | `(Спортивные)` | `Спортивные` |
|
||||
| `!Барды/Владимир Высоцкий/Блатные` | `(Блатные)` | `Блатные` |
|
||||
| `!Барды/Владимир Высоцкий/Разное` | `(Высоцкий - Разное)` | `Высоцкий - Разное` |
|
||||
| `!Барды/Владимир Высоцкий/Из сказок` | `(Из Сказок)` | `Из Сказок` |
|
||||
| `!Retro` | `(Авария)` | `Авария` |
|
||||
| `!Retro` | `(Вилли Токарев)` | `Вилли Токарев` |
|
||||
| `!Рэп/Птаха - Красивые, богатые (2009)` | `(prod. Shorty)` | `prod. Shorty` |
|
||||
| `!Рэп/Вилли Токарев` | `(Вилли Токарев)` | `Вилли Токарев` |
|
||||
| `!Pop, Club, Любэ/Дискотека Авария` | `(Авария)` | `Авария` |
|
||||
| `!Pop, Club, Любэ/Дискотека Авария/Старые хиты` | `(Авария)` | `Авария` |
|
||||
| `!Pop, Club, Любэ/Дискотека Авария/Москва пьёт пиво` | `(Авария)` | `Авария` |
|
||||
| `!Rock&Folk/Несчастный Случай` | `(Несчастный Случай)` | `Несчастный Случай` |
|
||||
| `!Rock&Folk/NONSONS - zvezda` | `(zvezda)` | `zvezda` |
|
||||
|
||||
> ⚠️ **Важно для читателя списка:** значения в `ALBUM-FIX-TABLE.csv` — **промежуточные**
|
||||
> (снятие скобок механически). По **финальным правилам** (§ФИНАЛЬНЫЕ РЕШЕНИЯ ПО 306 СТРОКАМ)
|
||||
> в корне папки артиста `album` = **имя папки артиста**, а в подпапке — **имя подпапки**.
|
||||
> Поэтому `(Авария)` → `Москва пьёт пиво`, а не `Авария`; `(Высоцкий)` → `Дискотека Авария`
|
||||
> в одноимённой папке. Отличие `ALBUM-FIX-TABLE.csv` от `ALBUM-FIX-306.csv` фиксирует
|
||||
> ровно эту правку уточнения (`new_album_was` → `new_album_now`).
|
||||
> Проверочный скрипт: `/tmp/verify_alb_fix.py`.
|
||||
|
||||
---
|
||||
|
||||
## 🟣 СЕССИЯ 18 (2026-09-27) — NAVIDROME РАЗВЁРНУТ, ДЕФЕКТ-КЛАСС ВСКРЫТ, ПРАВИЛА ВОССТАНОВЛЕНЫ ИЗ ZULIP, 306 СТРОК ИСПРАВЛЕНЫ, НОВЫЙ ДИФФ ГОТОВ
|
||||
|
||||
> **СТАТУС СЕССИИ 18 (ФИНАЛ):** Navidrome ✅ развёрнут и работает (см. ниже +
|
||||
|
||||
@@ -72,8 +72,13 @@ related:
|
||||
|
||||
> ⚠️ **Обновлён до v2.1.0 (сессия 17):** **A7** (склейка `Родитель - Папка` и технический префикс
|
||||
> в `album`; 🔴 разделитель бывает ТРЁХ видов — `-`/`–`/`—`, матчить все) · **A8** (в контроле
|
||||
> полноты «ПОТЕРЯНО: 881» = смена ФОРМЫ записи при схлопывании D16, реальных потерь 0 —
|
||||
> сверять НОВОЕ значение, а не пару `old,new`). Полные формулировки — ниже.
|
||||
> полноты «ПОТЕРЯНО: 881» = смена ФОРМЫ записи при схлопывании D16, реальных потерь 0 — сверять
|
||||
> НОВОЕ значение, а не пару `old,new`). Полные формулировки — ниже.
|
||||
|
||||
> ⚠️ **Обновлён (сессия 18-доп):** правила **D24** (число ЗАПИСЕЙ диффа ≠ число ПРАВОК:
|
||||
> три базы счёта `7861 / 371 / 2768` нельзя смешивать) и **D25** (`albumartist` в диффе почти
|
||||
> весь — из-за ПОЯВЛЕНИЯ колонки, `old_38='<КОЛОНКИ НЕ БЫЛО>'`, ср. D3). Инвентарь
|
||||
> актуального диффа — `personal/plans/music-artist-albumartist-repair.md` §СЕССИЯ 18-ДОП.
|
||||
|
||||
## 📁 Артефакты проекта
|
||||
|
||||
@@ -1312,7 +1317,32 @@ Alex дал ответы на все четыре вопроса аудита с
|
||||
отсутствие лучшего источника данных. «Нашёл дефект» без проверки фактов = ложная тревога,
|
||||
которая стоит сессию времени.
|
||||
|
||||
## ⚪ Что НЕ является багом
|
||||
### 🔴 D24 — число ЗАПИСЕЙ диффа ≠ число ПРАВОК; три базы счёта нельзя смешивать
|
||||
|
||||
Три разных числа описывают «сколько изменится», и их нельзя путать в отчёте:
|
||||
|
||||
| База счёта | Число | Что это |
|
||||
|---|---:|---|
|
||||
| Строк в `APPLY-PLAN.csv` | 7861 | вся библиотека |
|
||||
| Строк плана, изменённых в сессии | **371** (306+58+12) | «мои правки этого дня» |
|
||||
| **Записей в диффе** (`DIFF-new-vs-38-v2.csv`) | **2768** | дельта плана против 38-го прогона |
|
||||
|
||||
Alex спрашивает «где диф с 371 правкой», а в диффе **371 нет вообще**. Если ответить
|
||||
«371 — это не число правок» — он читает как «не услышал» (см. правила счёта в этом же доке).
|
||||
**Правильная формулировка:** «371 строка плана изменена в этой сессии; в диффе 2768 записей,
|
||||
из них `album` 164 и `albumartist` 634».
|
||||
|
||||
### 🔴 D25 — `albumartist` в диффе почти весь — из-за ПОЯВЛЕНИЯ колонки
|
||||
|
||||
В `DIFF-new-vs-38-v2.csv` из 2768 записей `albumartist` = **634**, и у подавляющего большинства
|
||||
`old_38 = '<КОЛОНКИ НЕ БЫЛО>'`. Это прямое следствие **D3**: колонки в 38-м прогоне не
|
||||
существовало, значит тег **впервые будет записан** — и это правка, а не перенос данных.
|
||||
Не путать с реальной сменой значения (`old` = конкретное имя артиста → новое).
|
||||
|
||||
Прочие поля того же диффа (для калибровки масштаба): `genre` 911 · `track` 883 · `album` 164 ·
|
||||
`artist` 134 · `title` 42. Разбивка правок: `ПАПКА` 1501 + `ТРЕК` 1267 = 2768.
|
||||
|
||||
### ⚪ Что НЕ является багом
|
||||
|
||||
- **Рукописная транслитерация:** `КняZz`, `EMINЭM`, `Flёur`, `изBESTняк`, `Скаzки`, `Глюкоzа`,
|
||||
`Cо`, `WWWаленки`, `Закoлебал` — оригинальное написание 2000-х / реальные псевдонимы.
|
||||
|
||||
Reference in new issue
Block a user