[2026-09-27] eagle: family/plans/music-jellyfin-lidarr-taiga.md personal/plans/music-artist-albumartist-repair.md personal/tech/id3-tag-repair-skill.md
This commit is contained in:
1 parent
4fa2be424f
commit
68a13317cf
3 files changed
+362
-34
No files matched your search
@@ -37,10 +37,35 @@ related:
|
||||
| Summary CSVs | инвариант суммы: `single + multi + skip == total` (теряли 562, потом 335 строк) |
|
||||
| Sentinel | группировать по КОРНЮ сборника, не по ближайшей папке (165 файлов в 9 фальшивых «артистов») |
|
||||
| 🆕 **Genre normalization** | 🔴 **G1–G5**, см. ниже |
|
||||
| 🆕 **Junk tag cleanup** | 🔴 **J1–J4**, см. ниже |
|
||||
|
||||
## 🆕 Junk tag cleanup (J1–J4) — вычистка мусора из тегов
|
||||
|
||||
**Контекст:** перед применением плана — аудит всех полей на мусор. Найдено и вычищено 10 классов
|
||||
(спам-URL 51, `P@X@Tu*HCK*u` 6, мойибаке в `album` 20 + `title` 1, заглушки genre 325,
|
||||
битые байты 2, `title` пуст 7).
|
||||
|
||||
| # | Правило |
|
||||
|---|---|
|
||||
| **J1** | **URL-подобные НАЗВАНИЯ песен не чистить.** `god@pisem.net`, `K@к@ In`, `И тебя уже.net` — реальные треки Пилота/Ленинграда/N1NT3NDO. Regex по подстроке вычищает их ошибочно. Фильтр — **точное совпадение значения целиком** со списком спама (`SPAM_EXACT`), не подстрока. |
|
||||
| **J2** | **Мойибаке — во ВСЕХ пяти полях.** Декодер прогонять по `title`/`artist`/`album`/`albumartist`/`genre`, не только по «проблемным». Пропуск дал 20 мойибаке в `album` (`Íåèçâåñòíîå íàçâàíèå`, `(Ìóììèé Òðîëëü)` ×7). |
|
||||
| **J3** | **`date`/`track` — числа, НЕ мусор.** Regex `^\d+$` дал 4475 ложных по `date` и 6310 по `track`. Исключать поля-числа из аудита мусора. |
|
||||
| **J4** | **Валидатор писать ДО объявления готовности.** `validate_final.py` (обязательные поля + спам + мойибаке + class↔albumartist) поймал 21 пропущенное значение. Проверка: все счётчики = 0. |
|
||||
|
||||
### Симптомы мусора в тегах (что искать)
|
||||
|
||||
```
|
||||
спам-URL в album/album_artist [muzmo.ru], http://butt-head.ru, www.mp3arena.ru, Mp3-Az.com
|
||||
имя тегировщика в genre/album P@X@Tu*HCK*u (не жанр! → по артисту)
|
||||
битые байты 刀甀猀戀愀爀搀猀 (иероглифы), Variйtй (смешанная кодировка)
|
||||
заглушки Other, Unknown, Неизвестный, Разное, Наши, genre, various, (N)
|
||||
мойибаке в album Íåèçâåñòíîå íàçâàíèå, (Ìóììèé Òðîëëü)
|
||||
```
|
||||
|
||||
|
||||
## 🆕 Genre normalization (G1–G5) — квинтэссенция
|
||||
|
||||
**Контекст:** 7861 файл, было **154 уникальных жанра**, 2950 пустых. Стало **82 / 51**.
|
||||
**Контекст:** 7861 файл, было **154 уникальных жанра**, 2950 пустых. Стало **65 / 0**.
|
||||
|
||||
| # | Правило |
|
||||
|---|---|
|
||||
@@ -48,7 +73,7 @@ related:
|
||||
| **G2** | **Гомоглифы — оба варианта в словарь явно.** `Å` (U+00C5, латиница) vs `Е` (U+0415, кириллица) выглядят одинаково; `lower()` их не схлопывает, а `.encode('latin-1')` падает на кириллической → декодер мойибаке **молча пропускает половину строк**. |
|
||||
| **G3** | **Мусорный жанр может быть мисридом поля.** `(17)` = все 32 файла **ДДТ** (номер плейлиста в кадре жанра); `General Rock` = все 31 **Ленинград**. Признак: `Counter(genre) → set(artist)` даёт **1:1** = это не жанр. Alex: «каждую смотри конкретно, не батчем по папке». |
|
||||
| **G4** | **Заполнять по артисту, порядок specific → general.** Таблица `подстрока → жанр` по `folder + artist`, первое совпадение выигрывает. Правила артистов **перед** папкой-ловушкой, иначе `!rock&folk` съест всех внутри. |
|
||||
| **G5** | **Незаполнимое — оставить ПУСТЫМ.** `unknown`/`неизвестно`/`разное`/`наши`/`(12)` не несут информации; подстановка по папке = **выдумывание метаданных**. 51 пустой — осознанное решение. |
|
||||
| **G5** | **Незаполнимое — оставить ПУСТЫМ** … но Alex потребовал **«Добей вручную пустые»** → 51 значение разобрано по артисту вручную (`Martin Solveig`→`Electro House`, `Chemical Brothers`→`Electronic`, `Eminem`→`Hip-Hop`, `Madonna`→`Pop`). **Итог: 0 пустых.** Правило G5 верно как дефолт, но Alex вправе потребовать ручной добив. |
|
||||
|
||||
### Порядок работ по жанрам (7 шагов)
|
||||
|
||||
@@ -66,13 +91,31 @@ related:
|
||||
|
||||
```
|
||||
/Users/admin/milestones/music-csv-2026-09-26/
|
||||
├── genre-plan-FINAL.csv ⭐ 7861 стр, 82 жанра, 51 пусто
|
||||
├── APPLY-PLAN-FINAL.csv ⭐⭐ 7861 стр — ЕДИНЫЙ ПЛАН НА ПРИМЕНЕНИЕ (14 колонок, 7628 изменений)
|
||||
├── fix-plan-FINAL.csv ⭐ 7861 стр, план artist/albumartist/album
|
||||
├── genre-plan-FINAL.csv ⭐ 7861 стр, 65 жанров, 0 пусто
|
||||
├── genre-junk.csv 365 строк мусора
|
||||
├── bad-genres.csv 3315 (мусор + пустые)
|
||||
└── check_genres.py → split_genres.py → normalize_genres.py →
|
||||
fill_genres.py → clean_genres.py → final_genres.py
|
||||
└── check_genres.py → split_genres.py → normalize_genres.py → fill_genres.py →
|
||||
clean_genres.py → final_genres.py → find_junk.py → find_junk2.py →
|
||||
clean_junk_tags.py → final_clean.py → final_clean2.py → fix_paxatu.py →
|
||||
final_touch.py → fix_moji_album.py → build_unified.py → validate_final.py
|
||||
```
|
||||
|
||||
**Единый план собирается сведением** `fix-plan-FINAL.csv` + `genre-plan-FINAL.csv` по ключу
|
||||
`path` (`build_unified.py`). Колонки результата:
|
||||
|
||||
```
|
||||
path, folder, class,
|
||||
cur_title, cur_artist, cur_albumartist, cur_album, cur_genre,
|
||||
new_title, new_artist, new_albumartist, new_album, new_genre, changed
|
||||
```
|
||||
|
||||
**Правило:** в одном файле держать и `cur_*` (что на диске), и `new_*` (что записать) —
|
||||
скрипт-писатель сравнивает их сам, а человек видит дельту глазами.
|
||||
|
||||
**Питфолл пайплайна:** `clean_genres.py` чистит **по списку**, а не до сходимости — после
|
||||
прогона на выходе тут же обнаружились новые остатки. Понадобился третий проход
|
||||
(`final_genres.py`: + детектор мойибаке + ещё 453 синонима). **Правило G1 выведено отсюда.**
|
||||
То же повторилось на мусоре: чистка пропустила 21 мойибаке в `album` — поймал только
|
||||
`validate_final.py`. **Правило J4 выведено отсюда.**
|
||||
Reference in new issue
Block a user