[2026-09-27] eagle: personal/plans/music-artist-albumartist-repair.md personal/tech/id3-tag-repair.md
This commit is contained in:
1 parent
6576b53834
commit
85f0f009dd
2 files changed
+171
-21
No files matched your search
@@ -4,7 +4,7 @@ created: '2026-09-27'
|
||||
updated: '2026-09-27'
|
||||
type: plan
|
||||
namespace: personal
|
||||
status: session13-trackscroll-rollback-genres-fixed-8-album-questions-open
|
||||
status: session13-collapse-fixed-radio-album-fixed-disk-naming-open
|
||||
tags:
|
||||
- music
|
||||
- metadata
|
||||
@@ -58,15 +58,94 @@ related:
|
||||
## 🟢 АКТУАЛЬНО НА КОНЕЦ СЕССИИ 13 (2026-09-27) — читать это первым
|
||||
>
|
||||
> ```
|
||||
> APPLY-PLAN.csv 7861 строка md5 ced5078ebf9b06f25e8bcc2d4ae6fec9
|
||||
> DIFF-new-vs-38.csv 4996 строк md5 1884b1429e5e9e9f08ecd6abd772fc7c
|
||||
> APPLY-PLAN.csv 7861 строка md5 a6e440511e195668af2cee785e547fce
|
||||
> DIFF-new-vs-38.csv 2864 строки md5 b4f5c9f23f52df4dd314f5210f3adfd6
|
||||
> tag-fix-plan.csv 7861 строка md5 203726ebfd2814e2328636df31337238 (НЕ ПРАВИТЬ)
|
||||
> ```
|
||||
>
|
||||
> **Состав диффа:** `ПАПКА` 1123 · `ТРЕК` 3747 · `НЕТ-В-38` 41 · `ТОЛЬКО-В-38` 85.
|
||||
> Полнота: `ВСЕГО правок 18639 · OK: потерь нет`.
|
||||
> **Состав диффа:** `ПАПКА` 1485 · `ТРЕК` 1253 · `НЕТ-В-38` 41 · `ТОЛЬКО-В-38` 85.
|
||||
> Полнота: `ВСЕГО правок 18841 · OK: потерь нет`.
|
||||
|
||||
### ✅ СДЕЛАНО в сессии 13
|
||||
### ✅ СДЕЛАНО в сессии 13 (продолжение — после вопросов)
|
||||
|
||||
**4. 🔴 СХЛОПЫВАНИЕ ДИФФА ПЕРЕДЕЛАНО — ключ группировки `(папка, поле, НОВОЕ ЗНАЧЕНИЕ)`.**
|
||||
Было: 4996 строк, схлопывание `combos = set((ov, nv))` требовало совпадения **И `old`, И `new`**
|
||||
у всех файлов — поэтому не срабатывало почти никогда. Стало: 2864 строки.
|
||||
|
||||
Alex: «схлопывание по `field+value` делается, а не по `old` — очевидно что он блядь у всех разный!»
|
||||
|
||||
```python
|
||||
# было (неверно):
|
||||
combos = set((ov, nv) for _, ov, nv in lst)
|
||||
if len(combos) == 1 and len(lst) > 1: ... # старые значения почти всегда разные -> построчно
|
||||
|
||||
# стало:
|
||||
groups = defaultdict(list)
|
||||
for rel, ov, nv in lst:
|
||||
groups[nv].append((rel, ov)) # группируем по НОВОМУ значению
|
||||
for nv, members in groups.items():
|
||||
if len(members) > 1:
|
||||
olds = sorted({ov for _, ov in members})
|
||||
label = olds[0] if len(olds) == 1 else f"<{len(olds)} разных>"
|
||||
collapse_lines.append((fld, fname, label, nv, len(members)))
|
||||
else:
|
||||
rel, ov = members[0]
|
||||
file_lines.append((fld, rel, fname, ov, nv))
|
||||
```
|
||||
Проверка на папке Alex: `!Radio/t 2009-07 c6Or_NICK`, `field=album` — было **43 строки**, стало **1**:
|
||||
`[ПАПКА] '<7 разных>' -> '2009-07 c6Or_NICK'`. В `old_38` пишу `<N разных>`, если старых
|
||||
значений больше одного (подставлять одно из семи = врать в отчёте).
|
||||
Контроль полноты не изменился: `ВСЕГО правок 18841 · OK: потерь нет` — правки не потеряны, а сгруппированы.
|
||||
|
||||
**5. `album` для подборок `!Radio` — 203 строки, 18 папок.**
|
||||
Корень дефекта: план копирует `cur_album` из старого тега, хотя для подборок `!Radio`
|
||||
`album` = **имя папки-подборки** (правило сессии 7). Показательный случай — трек «Теряю свет»:
|
||||
```
|
||||
!Radio/t 2009-07 c6Or_NICK/plux/Би-2 и Агата Кристи - Теряю свет.mp3
|
||||
cur_album='Нечетный воин 2' → new_album='Нечётный Воин 2' ❌ (для подборки альбом не при чём)
|
||||
правильное: '2009-07 c6Or_NICK'
|
||||
```
|
||||
Тот же трек в папке-альбоме `!Rock&Folk/Би-2/Нечетный Воин/2008 Проект…` — **оставлен верным**
|
||||
(`class='АЛЬБОМ'`, `albumartist='Би-2'`, `album='Нечётный Воин 2'`).
|
||||
|
||||
| Что | строк | скрипт | бэкап |
|
||||
|---|---|---|---|
|
||||
| `plux` (28 ф.) → `2009-07 c6Or_NICK` | 18 | `/tmp/fix_plux.py` | `.bak-plux-…144514` |
|
||||
| 17 папок `!Radio` с разнобоем → имя подборки | 185 | `/tmp/fix_radio_album.py` | `.bak-radioalb-…144543` |
|
||||
|
||||
Целевое имя берётся как значение, которое **уже стоит у большинства** файлов папки (значит
|
||||
оно и есть имя подборки, проставленное ранее), + требование `cnt >= 2`.
|
||||
**Пропущены намеренно:** `disk/3 SHANSON/Трофим` и `disk_v2/3 SHANSON/Трофим` — там лежат
|
||||
альбомы Трофима (`class='АЛЬБОМ'`), имя папки не подборка.
|
||||
Детектор разнобоя: `/tmp/audit_radio_album.py` → после фикса осталось **2 папки** (обе `Трофим`).
|
||||
|
||||
**6. Проверено и НЕ подтверждено — откат не нужен.** Alex заподозрил, что «слетели альбомы»
|
||||
(`Benassi Bros` и др.). Факт: в `APPLY-PLAN.csv` **`new_album` заполнен у 7861 из 7861**.
|
||||
Слетевшими выглядели строки вида `'' -> 'КняZz'` в диффе — но `''` это `old_38` (в 38-м
|
||||
прогоне `album` не заполнялся вовсе). Откат вернул бы пустые альбомы, т.е. сломал бы.
|
||||
Отдельно по `Benassi Bros`: во **всех 45 бэкапах** корень = `'Benassi Bros'` только у **4 из 15** —
|
||||
состояние, которое искал Alex, в бэкапах `APPLY-PLAN.csv.*` отсутствует.
|
||||
|
||||
### ❓ ОТКРЫТЫЕ ВОПРОСЫ К ALEX (заданы, ответа нет — НЕ править)
|
||||
|
||||
**🔴 `z Старое/disk*` — именование `RADIO N NAME`.** Показал факты, решения нет:
|
||||
```
|
||||
disk/1 DRIVE 43 ф. → RADIO 1 DRIVE ✅
|
||||
disk/2 ALT,PUNK 11 ф. → RADIO 2 ALT,PUNK ✅
|
||||
disk/4 INSTRUMENTAL 1 ф. → RADIO 4 INSTRUMENTAL ✅
|
||||
disk/5 POPSA 15 ф. → RADIO 5 POPSA ✅
|
||||
disk/3 SHANSON/Трофим 25 ф. → альбомы Трофима ❌ нет 'RADIO 3 SHANSON'
|
||||
disk_v2/2 ALT,PUNK/HARD 6 ф. → 'Megamix 2002' ❌ нет 'RADIO 2 ALT,PUNK'
|
||||
```
|
||||
Причина по `3 SHANSON`: в папке нет **своих** файлов (только подпапка `Трофим`), а имя
|
||||
берётся от папки, где лежит файл. `HARD` — третий уровень вложенности.
|
||||
Моё предположение (брать имя ближайшей нумерованной папки-родителя) **отклонено**:
|
||||
Alex: «нет, не надо блядь выдумывать. делай че я говорю». Последнее показанное состояние:
|
||||
`3 SHANSON/Трофим` — `class='АЛЬБОМ'`, альбомы Трофима, но **один файл сбит**:
|
||||
`#2_04_Koroche delo k nochi.mp3 → 'Трофим'` (должен быть `Аристократия помойки 2`).
|
||||
`disk_v2/2 ALT,PUNK/HARD` — `class='СБОРНИК'`, все 6 файлов `'Megamix 2002'`.
|
||||
|
||||
### ✅ СДЕЛАНО в сессии 13 (начало)
|
||||
|
||||
**1. ⚠️ ОТКАТ дефекта из сессии 12: сквозная нумерация многодисковых изданий УНИЧТОЖЕНА мной, восстановлена.**
|
||||
Класс A из `fix_track_bugs.py` (269 строк) сбрасывал `14..26 → 1..13` и т.п. — это **было неверно**.
|
||||
@@ -111,30 +190,31 @@ Alex: «НС - это рок», «очевидноъ». Все файлы — `c
|
||||
> ✅ 51 строка `Psychedelic` у IM — **корректна**, не трогать (IM = психоделик-транс).
|
||||
> Там же план исправляет опечатку `Psychadelic` → `Psychedelic` — это плюс.
|
||||
|
||||
### ❓ ВОПРОСЫ К ALEX — ОТКРЫТЫ (заданы в конце сессии 13, ответа нет)
|
||||
### ❓ ВОПРОСЫ К ALEX — СТАТУС (сессия 13)
|
||||
|
||||
Задан ручной проход по всему `album`-блоку диффа. Найдены классы подозрительного `new_album`.
|
||||
**Ничего не правил — жду ответа.** Ключевой спор:
|
||||
|
||||
🔴 **«Куда слетели альбомы?»** Alex: «мы с тобой ставили album в соответствие названию
|
||||
корня папки — ищи этот apply-plan backup!» Про **`Benassi Bros`**: ожидает `album='Benassi Bros'`
|
||||
для 15 файлов корня. **Проверено — НЕ подтвердилось:** во **всех 45 бэкапах**
|
||||
`APPLY-PLAN.csv.*` корень Benassi Bros = `'Benassi Bros'` только у **4 из 15**, остальные 11
|
||||
несут значения из тегов (`Phobia`, `Rock N Rave`, `Hypnotica`, `Techno 2003`,
|
||||
`Miami Sampler 2002 CDS`, `Energy New Release CD`, `Loneliness Promo_Vinyl`,
|
||||
`Loveparade Compilation 2003`, `I Love My Sex VINYL`, `Pumphonia`, `Non spécifié`, `NULL`).
|
||||
Скрипт поиска `/tmp/find_benassi2.py` (важно: фильтр по `.csv` **отсекает** бэкапы
|
||||
🔴 **«Куда слетели альбомы?» — РАЗОБРАНО, откат НЕ нужен.** Alex: «мы с тобой ставили album
|
||||
в соответствие названию корня папки — ищи этот apply-plan backup!» Про **`Benassi Bros`**:
|
||||
ожидает `album='Benassi Bros'` для 15 файлов корня.
|
||||
**Проверено — НЕ подтвердилось** (см. п.6 в разделе «СДЕЛАНО»): в текущем плане `new_album`
|
||||
заполнен у всех 7861 строк; во **всех 45 бэкапах** `APPLY-PLAN.csv.*` корень Benassi Bros =
|
||||
`'Benassi Bros'` только у **4 из 15**, остальные 11 несут значения из тегов (`Phobia`,
|
||||
`Rock N Rave`, `Hypnotica`, `Techno 2003`, `Miami Sampler 2002 CDS`, `Energy New Release CD`,
|
||||
`Loneliness Promo_Vinyl`, `Loveparade Compilation 2003`, `I Love My Sex VINYL`, `Pumphonia`,
|
||||
`Non spécifié`, `NULL`).
|
||||
Скрипт поиска `/tmp/find_benassi2.py` (важно: фильтр `p.endswith(".csv")` **отсекает** бэкапы
|
||||
`APPLY-PLAN.csv.bak-*` — сначала я на этом ошибся и получил «всего 1 файл»).
|
||||
➡️ **Искать источник нужно в другом файле:** `tag-inventory3.csv`, `APPLY-PLAN-RAW.csv`,
|
||||
➡️ Если источник всё же существует — искать в: `tag-inventory3.csv`, `APPLY-PLAN-RAW.csv`,
|
||||
`archive/*`, `milestones/music-csv-2026-09-26/`.
|
||||
|
||||
Остальные вопросы (прочитаны строки `album/ПАПКА` 1-75 и `album/ТРЕК` 76-319):
|
||||
Остальные вопросы (прочитаны строки `album/ПАПКА` 1-75 и `album/ТРЕК` 76-319).
|
||||
**Статус:** п.3 (разнобой `!Radio`) и п.7 (корень артиста) — **частично закрыты** п.5 сессии 13;
|
||||
пп.1, 2, 4, 5, 6, 8 — **открыты**, решения нет.
|
||||
|
||||
| # | Что | Пример |
|
||||
|---|---|---|
|
||||
| 1 | **Мусор в `album`** | `Non spécifié`, `NULL`, `no title`, `Album`, `2005`, `Неизвестное название`, `melody.az - КняZz - Корсар`, `(Муммий Тролль)` ×8 (скобки в названии) |
|
||||
| 2 | **`album` = название песни** | `Алексин/Алексин - Шалавы.mp3 → 'Шалавы'`; `Дискотека Авария/Песенка разбойников.mp3 → 'Песенка разбойников'` |
|
||||
| 3 | **`album` = имя подпапки** (правило сессии 7, но список длинный) | `!Radio/z Старое/disk/2 ALT,PUNK/* → 'RADIO 2 ALT,PUNK'`; `Rammstein → 'misc'`; `Красная Плесень/misc → 'Красная Плесень'`; `Пилот/misc/Про гитару → 'Сказка'`; `Пилот/misc/Хана человечки → 'Война'` |
|
||||
| 3 | **`album` = имя подпапки** (правило сессии 7; разнобой `!Radio` закрыт в п.5) | `!Radio/z Старое/disk/2 ALT,PUNK/* → 'RADIO 2 ALT,PUNK'`; `Rammstein → 'misc'`; `Красная Плесень/misc → 'Красная Плесень'`; `Пилот/misc/Про гитару → 'Сказка'`; `Пилот/misc/Хана человечки → 'Война'` |
|
||||
| 4 | 🔴 **4 разных формата `album` внутри одной `!Radio`** | `'Radio - OOF'` / `'Radio - Старое'` (префикс ✅) · `'RADIO 1 DRIVE'`, `'RADIO 5 POPSA'` (без префикса) · `'2009-04 Radio'`, `'2008-07 Radio'`, `'2008-04 Radio'` (суффикс!) · `'2009-10 Oktoberfest'` (без Radio вообще) |
|
||||
| 5 | `z Другое, Enigma, Ленинград` корень → `'Сосни попса'` | это точно альбом? |
|
||||
| 6 | `album` из ниоткуда | `detskiy_hor_benassi_satisfaction.mp3 → 'Горячие Синглы 2004'`; `Бутусов & Ю-Питер/Девушка По Городу.mp3 → 'Горячие синглы - июнь 2004'` |
|
||||
@@ -155,6 +235,10 @@ Alex: «НС - это рок», «очевидноъ». Все файлы — `c
|
||||
`find_lost_track.py` (потери `track`) · `classify_track.py` (привязан/сирота) ·
|
||||
`show_remaining51.py` · `rollback_track_fix.py` · `walk_diff.py` (полный ручной проход → `/tmp/diff_full_walk.txt`) ·
|
||||
`compare_backups_album.py` · `find_benassi2.py` · `check_*` детекторы жанров.
|
||||
Дописано во второй половине сессии 13: `/tmp/check_c6or_collapse.py` (проверка схлопывания) ·
|
||||
`/tmp/audit_radio_album.py` (разнобой `new_album` в `!Radio`) · `/tmp/check_plux.py` ·
|
||||
`/tmp/fix_plux.py`, `/tmp/fix_radio_album.py` (правки `album`) · `/tmp/show_current_album.py` ·
|
||||
`/tmp/check_disk_name.py` (именование `disk*/N NAME`) · `/tmp/verify_diff_order.py`.
|
||||
|
||||
## 🔴 АКТУАЛЬНО НА КОНЕЦ СЕССИИ 12 (2026-09-27) — ИСТОРИЧЕСКОЕ (частично ОТКАЧЕНО)
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ related:
|
||||
> раздельных циклах бесполезна); **D11** (`new_track` теряется при пустом `cur_track`);
|
||||
> **D12** (`new_track` «ни к чему не привязан» → сдвинутый ряд пересчитать, иначе убрать).
|
||||
>
|
||||
> ⚠️ **Обновлён до v1.8.0 (сессия 13, вторая половина):** **D16** (схлопывание диффа: ключ
|
||||
> `(папка, поле, НОВОЕ значение)`, `old` в ключ не входит), **D17** (`album` унаследован от
|
||||
> `cur_album` для подборок `!Radio` — 203 строки; метод: имя подборки = значение большинства).
|
||||
>
|
||||
> ⚠️ **Обновлён до v1.7.0 (сессия 13):** **D12 ОТКАЧЕН** — см. **D12-R** ниже (сквозная
|
||||
> нумерация многодисковых изданий НЕ трогать). Добавлены **D13** (жанр унаследован от
|
||||
> `cur_genre` без проверки), **D14** (статус «привязан/сирота» для `track`), **D15** (поиск
|
||||
@@ -531,6 +535,68 @@ lost = [r for r in rows if r["field"] == "track"
|
||||
|
||||
Скрипт: `/tmp/classify_track.py`.
|
||||
|
||||
### 🔴 D16 — схлопывание диффа: ключ `(папка, поле, НОВОЕ значение)`, НЕ `old` (сессия 13)
|
||||
|
||||
Первая версия схлопывала только когда у **всех** файлов папки совпадал **и `old`, и `new`**:
|
||||
```python
|
||||
combos = set((ov, nv) for _, ov, nv in lst)
|
||||
if len(combos) == 1 and len(lst) > 1: collapse...
|
||||
else: для каждого файла отдельная строка
|
||||
```
|
||||
Это **почти никогда не срабатывало**: `old_38` у каждого файла свой (`'Дискотека Арлекина 2009'`,
|
||||
`'Record Super Chart ¹ 90 (30.05.2009)'`, `''`, `'Ticker / Sensor'` …). Папка из 43 файлов
|
||||
давала 43 строки при **одном** новом значении.
|
||||
|
||||
Alex: «схлопывание по `field+value` делается, а не по `old` — очевидно что он блядь у всех разный!»
|
||||
|
||||
**Правильно — группировать по новому значению внутри `(папка, поле)`:**
|
||||
```python
|
||||
groups = defaultdict(list)
|
||||
for rel, ov, nv in lst:
|
||||
groups[nv].append((rel, ov)) # ключ НЕ включает old
|
||||
for nv, members in groups.items():
|
||||
if len(members) > 1:
|
||||
olds = sorted({ov for _, ov in members})
|
||||
label = olds[0] if len(olds) == 1 else f"<{len(olds)} разных>"
|
||||
collapse_lines.append((fld, fname, label, nv, len(members)))
|
||||
else:
|
||||
rel, ov = members[0]
|
||||
file_lines.append((fld, rel, fname, ov, nv))
|
||||
```
|
||||
|
||||
🔴 **Питфолл отчёта:** в колонку `old_38` схлопнутой строки **нельзя** подставлять одно из
|
||||
нескольких старых значений — это враньё в отчёте. Если старых значений больше одного, писать
|
||||
`<N разных>`.
|
||||
|
||||
**Эффект:** `!Radio/t 2009-07 c6Or_NICK` `field=album` — 43 строки → 1 (`'<7 разных>' -> '2009-07 c6Or_NICK'`).
|
||||
Дифф целиком 4996 → 2864 строк (`ПАПКА` 1123→1485 · `ТРЕК` 3747→1253).
|
||||
Контроль полноты на трек-уровне не меняется (`assert covered + len(file_lines) == sum(field_counts)`).
|
||||
|
||||
### 🔴 D17 — `album` унаследован от `cur_album` для подборок `!Radio` (сессия 13, 203 строки)
|
||||
|
||||
Тот же корень, что и **D13**: план копирует значение из тега файла, не проверяя, уместно ли оно.
|
||||
Здесь — `new_album` ← `cur_album`. Для подборок `!Radio` **`album` = имя папки-подборки**
|
||||
(правило сессии 7), а не альбом, из которого трек взят.
|
||||
|
||||
```
|
||||
!Radio/t 2009-07 c6Or_NICK/plux/Би-2 и Агата Кристи - Теряю свет.mp3
|
||||
cur_album='Нечетный воин 2' → new_album='Нечётный Воин 2' ❌
|
||||
правильно: '2009-07 c6Or_NICK'
|
||||
```
|
||||
Один и тот же трек, но в **папке-альбоме** `!Rock&Folk/Би-2/Нечетный Воин/2008 Проект…`
|
||||
(`class='АЛЬБОМ'`) — там `album='Нечётный Воин 2'` и `albumartist='Би-2'` **верны**.
|
||||
|
||||
**Метод фикса (без выдумывания значений):** целевое имя папки-подборки берётся как значение,
|
||||
которое **уже стоит у большинства** файлов папки (значит оно проставлено ранее правилом), плюс
|
||||
требование `cnt >= 2`. Папки, где такого большинства нет либо `class='АЛЬБОМ'` — **пропускать**.
|
||||
|
||||
**Детектор разнобоя:** для каждой папки `Counter(new_album)`; `len(vals) > 1` = дефект.
|
||||
Скрипты: `/tmp/audit_radio_album.py` (поиск), `/tmp/fix_radio_album.py` (правка, сухой прогон по умолчанию).
|
||||
До: 19 папок / 469 строк. После: 2 папки (обе `3 SHANSON/Трофим` — там альбомы Трофима, пропущены намеренно).
|
||||
|
||||
🔴 **Не путать с правильными случаями:** `z Старое/disk/N NAME` → `'RADIO N NAME'` — это
|
||||
**одно** значение на папку и оно верно; дефект только там, где значения разные.
|
||||
|
||||
### 🔴 D15 — поиск по бэкапам: фильтр `.csv` отсекает `APPLY-PLAN.csv.bak-*` (сессия 13)
|
||||
|
||||
`glob(f"{B}/APPLY-PLAN.csv*")` + условие `p.endswith(".csv")` **выбрасывает все бэкапы**,
|
||||
|
||||
Reference in new issue
Block a user