[2026-09-27] eagle: personal/plans/music-artist-albumartist-repair.md personal/tech/music-tags-repair-truenas.md personal/tech/scripts/find_aa_hijack.py

This commit is contained in:
Alexey Martemyanov committed 2026-09-27 14:09:06 +06:00
1 parent 042cac0216
commit c0a76a56c9
3 files changed
+341 -6

No files matched your search

@@ -4,7 +4,7 @@ created: '2026-09-27'
updated: '2026-09-27'
type: plan
namespace: personal
status: session4-done-diff-rebuilt-4864-rows-0-losses
status: session6-open-7-albumartist-hijack-folders
tags:
- music
- metadata
@@ -23,6 +23,30 @@ related:
# Music `artist` + `albumartist` Repair — правила Alex и ход работ
> ## 🔴 АКТУАЛЬНО НА КОНЕЦ СЕССИИ 6 (2026-09-27)
>
> ```
> APPLY-PLAN.csv 7861 строка md5 c8d43cc56d82cd35a67a0efe8173cd4b
> DIFF-new-vs-38.csv 4864 строки md5 3ebc67c9d6abe5fce2d927fcc7726808
> tag-fix-plan.csv не тронут (база 38-го, источник истины для диффа)
> ```
>
> **Пустых полей в плане — 0** (`new_album` / `new_albumartist` / `new_artist` / `new_title` / `new_genre`).
> Дифф проверен: `ПОТЕРЯНО 0 · ЛИШНИХ 0 · ИТОГ: ПОТЕРЬ НЕТ, дифф ПОЛНЫЙ`.
>
> 🔴 **ОТКРЫТО, ЖДЁТ «go» (главное сессии 6):** класс дефекта **«`albumartist` размножен от чужого
> файла в корне папки»** — найдено **7 папок** (`The Prodigy`→`DJ Feel`, `Банд Эрос`→`VIP77`,
> `Дискотека Авария`, `Жуки`, `Потап & Каменских`, `Король и Шут`, `Ленинград`). Детали и
> детектор-скрипт — в разделе **«🔷 СЕССИЯ 6»** в конце документа.
>
> **Формат `album` для папок `!Radio/*` ИЗМЕНЁН (сессия 5):** `Radio - <имя>`
> (`Radio - OOF`, `Radio - Старое`, `Radio - Df1`) — **вытесняет** прежние `OOF Radio` /
> `Старое Radio` / `RADIO 1 DRIVE`. Упоминания старого формата ниже по тексту — устарели.
>
> **Всё остальное о формате `album` в старых разделах ниже — историческое.** Хронология
> сессий 1-5 и все разобранные питфоллы — в разделах «🔷 СЕССИЯ N» в конце документа.
> **Свежие правила всегда в последнем разделе.**
>
> ## 🔴 ПУТИ ПЕРЕЕХАЛИ (2026-09-27, вечер) — `~/milestones` БОЛЬШЕ НЕТ
>
> Alex: «какой блядь ~/milestones?! мы блядь работаем в `/Users/admin/Downloads/music-tags/`!
@@ -2317,5 +2341,255 @@ python3 verify_diff_completeness.py # exit 0 = чисто
не нужна, а в диффе строка есть. Пользователь обозначил принцип: **в диффе только то,
что реально поменяется.**
---
## 🔷 СЕССИЯ 5 (2026-09-27): ЗАКРЫТИЕ ПУСТЫХ ПОЛЕЙ + РУЧНЫЕ ПРАВКИ `album`/`albumartist`
### Задача Alex
> «блядь поправь пустые!»
> «OOF Radio -> Radio - OOF / Старое Radio -> Radio - Старое / Df1 -> Radio - Df1 /
> Infected Mushroom - Other Track's -> Other Tracks»
> «!Rock&Folk/Rammstein — треки в корне тоже кстати Rammstein - misc сделай»
> «Benassi Bros/2003 Hypnotica Bonus — albumartist Various Artists исправь» → «ну ставь benassi bros»
> «!Pop, Club, Любэ/Dj Tiesto — там не Tiesto должен быть разве albumartist?»
### 1️⃣ ЗАКРЫТЫ ВСЕ ПУСТЫЕ ПОЛЯ (0 пустых)
| # | Файл | Поле | Было | Стало |
|---|---|---|---|---|
| 1 | `z Другое, Enigma, Ленинград/Красная плесень - На дискотеку сельскую.mp3` | `album` | пусто | `Сосни попса` |
| 2 | `z Другое, Enigma, Ленинград/Красная Плесень - Заебал мой кот.mp3` | `album` | пусто | `Сосни попса` |
| 3 | `!Pop, Club, Любэ/!Radio/t 2009-07 c6Or_NICK/10 Boom (Bimbo Jones Mix).mp3` | `artist` | мусор `ÿþd` (UTF-16-обрывок) | `Bimbo Jones` |
Файлы №1-2 лежали **в корне папки-КАТЕГОРИИ** `z Другое, Enigma, Ленинград` (внутри —
подпапки `Красная Плесень`, `Ленинград`, `Сектор Газа`, `Enigma`, `Саундтреки` и др.).
Имя папки-категории в `album` — мусор; оба файла принадлежат альбому `Сосни попса`
(в дереве есть `Красная Плесень/Сосни попса/`, 16 файлов).
**Итог: пустых `new_album` / `new_albumartist` / `new_artist` / `new_title` / `new_genre` = 0.**
### 🔴 ПИТФОЛЛ: поиск мусора по точному значению промахивается
Я искал битый `artist` по литералу `'ÿþd'` — **не нашёл**, файл проскочил. Значение реально
было **пустой строкой** после нормализации. Правильный фильтр — не по литералу, а **по
свойствам**: `if not s.strip() or not s.isprintable() or any(ord(c) < 32 for c in s)`.
**Мораль:** искать мусор по списку известных значений = гарантированный пропуск.
Искать по предикату свойства.
### 🔴 ЧЕСТНОСТЬ В ОТЧЁТЕ: я сказал «пустого `new_artist` нет» — это была неправда
Первый ответ был «empty=1, сейчас назову» → затем «моя ошибка, значение есть, просто мусорное».
Alex отреагировал резко («шо??»). **Нельзя объявлять «0 пустых», не перепроверив все поля
по предикату.** Потеря доверия к отчёту дороже, чем задержка на проверку.
### 2️⃣ РУЧНЫЕ ПРАВКИ `album` — 61 файл (команда Alex)
| Папка | Файлов | Было | Стало |
|---|---:|---|---|
| `!Radio/y OOF` | 29 | `OOF Radio` | **`Radio - OOF`** |
| `!Radio/z Старое` (корень) | 16 | `Старое Radio` | **`Radio - Старое`** |
| `Df1` | 12 | `Df1` | **`Radio - Df1`** |
| `Infected Mushroom - Other Track's` | 2 | `Infected Mushroom - Other Track's` | **`Other Tracks`** |
| `!Rock&Folk/Rammstein` (корень) | 2 | `Rammstein` | **`Rammstein - misc`** |
**Принцип формат-имени: `Radio - <имя>`** — вытесняет прежний суффиксный `OOF Radio` /
прежний префиксный `RADIO 1 DRIVE`. 🔴 Актуальный формат папок `!Radio/*` снизу —
`Radio - OOF`, `Radio - Старое`, `Radio - Df1` (не `OOF Radio`).
**Не тронуто (осознанно — это НЕ имя папки, а реальные альбомы):**
- `Df1/My CD` (`Vino Vino Vinyl`, `Nachtschicht Vol 24 CD1`, `FR0NT0700510`…) — 4 файла
- `Rammstein/Rammstein - Kokain.mp3` — уже `Das Modell`
- 21 файл в `Other Track's` со своими альбомами (`Unreleased Tracks` 14, `Magnet`, `Voom…`)
- реальные альбомы внутри `y OOF` / `z Старое` (`Вспышка Сверхновой 2007 Club`, `Borat`, `Bucovina`…)
> 🔴 **Питфолл точности:** «Infected Mushroom — Other Track's» переименовывалось **только там,
> где `new_album` буквально равен имени папки**. Слепой заменой по папке было бы испорчено
> 21 файл с настоящими альбомами. Правило: править по совпадению `new_album == имя_папки`,
> а не по предикату «файл лежит в папке X».
### 3️⃣ `albumartist` Benassi Bros — 20 файлов
| Папка | Файлов | Было | Стало |
|---|---:|---|---|
| `Benassi Bros/2003 Hypnotica Bonus` | 5 | `Various Artists` | **`Benassi Bros`** |
| `Benassi Bros/Re Sfaction` | 15 | `Various Artists` | **`Benassi Bros`** |
Alex выбрал `Benassi Bros` (не `Benny Benassi`). Оба — **АЛЬБОМЫ с гостевыми фитами**, не сборники
(`Re Sfaction`: In-Grid, Sonique, Electric Six, Ann Lee, KMC Feat. Sandy, Gambafreaks).
> ⏳ **Обнаружена несогласованность внутри группы `Benassi Bros/`:** часть папок
> `Benny Benassi` (`2003 Hypnotica`, `2004 Puphonia`, `2008 Rock N Rave`, `2003 MegaMix`,
> `2003 Satisfaction*`, `2003 Pres_the_Biz…`), часть `Benassi Bros` (`2005 Phobia` + эти две).
> Alex не подтвердил приведение к одному имени — **не трогать без указания**.
### 4️⃣ `Dj Tiesto` — ВОПРОС ОТКРЫТ (ждёт ответа Alex)
`!Pop, Club, Любэ/Dj Tiesto` — 14 файлов, все `new_albumartist = 'Various Artists'`.
| Файлов | `new_album` | Состав |
|---:|---|---|
| 13 | `In Search of Sunrise 3` | компиляция-микс Tiesto: Nalin & Kane, Andain, Way Out West, Solar Stone, Choir… |
| 1 | `PoW - Team PoW - 2oo4` | `artist = Tiesto`, чужой сборник, в дереве альбома нет |
**Предложено (НЕ применено):** `In Search of Sunrise 3` → `albumartist = Tiesto`
(DJ-микс серии, автор компиляции — диджей; `artist` каждого трека остаётся свой),
`PoW` — оставить `Various Artists`. **Ждём «go».**
---
### 📊 АКТУАЛЬНЫЕ АРТЕФАКТЫ (конец сессии 5)
```
APPLY-PLAN.csv 7861 строка md5 87ab8406509fb99651762886645e35e8
DIFF-new-vs-38.csv 4864 строки md5 6852b25fd36fe14e97eb7788cdfa844a
tag-fix-plan.csv не тронут (база 38-го, источник истины для диффа)
```
**Цепочка MD5 `APPLY-PLAN.csv` (сессия 5):**
```
bb724716… начало сессии 5 (0 пустых, до ручных правок)
88e1059c… + 61 файл Radio-формат / Other Tracks / Rammstein - misc
87ab8406… ⬅ ТЕКУЩИЙ, + Benassi Bros albumartist (20 файлов)
```
**Цепочка MD5 `DIFF-new-vs-38.csv` (сессия 5):**
```
0d7a31ca… начало сессии 5
a0a52be9… + 61 файл Radio-формат / Other Tracks / Rammstein - misc
6852b25f… ⬅ ТЕКУЩИЙ, + Benassi Bros albumartist
```
**Проверка после каждой правки (оба скрипта, выход):**
```
diff_new_vs_38.py: ВСЕГО правок 18558, assert OK: потерь нет
verify_diff_completeness.py: ПОТЕРЯНО 0 · ЛИШНИХ 0
НЕТ-В-38 41=41 · ТОЛЬКО-В-38 85=85
ИТОГ: ПОТЕРЬ НЕТ, дифф ПОЛНЫЙ
```
> 🔴 **Рабочий цикл правки CSV (установлен, повторять):**
> 1. `shutil.copy2(p, p + '.bak-before-<тема>-' + ts)` — бэкап **до** правки;
> 2. правка скриптом из **файла** (`write_file` в `/tmp`), не инлайном;
> 3. `python3 diff_new_vs_38.py > /tmp/log 2>&1` (**не через пайп**);
> 4. `python3 verify_diff_completeness.py` → `exit 0`;
> 5. отчёт Alex: «Готово, проверяй» + что изменено + **MD5 до/после**.
Бэкапы сессии 5: `.bak-before-finalempty-20260927-134959`, `.bak-before-artistempty-20260927-135034`,
`.bak-before-radiofix-20260927-140315`, `.bak-before-benassi-20260927-140435`.
---
### ⏳ НЕ ЗАКРЫТО (актуализировано, конец сессии 6)
| # | Вопрос | Статус |
|---|---|---|
| 1 | 🔴 **`albumartist`-перехват чужим файлом — 7 папок** (`The Prodigy`→`The Prodigy`, `Банд Эрос`→`Банд'Эрос`, `Дискотека Авария`→`Дискотека Авария`, `Жуки`→`Жуки`, `Потап & Каменских`→`Потап и Настя Каменских`, `Король и Шут`→`Король и Шут`, `Ленинград` корень → `Ленинград` ×3 + `Сергей Шнуров` ×1) | 🔴 план предложен, **ждёт «go» Alex** |
| 2 | `Benassi Bros/` — свести `Benny Benassi` и `Benassi Bros` к одному имени? | ⏳ Alex не подтвердил |
| 3 | `track = '238'` у 56 файлов (`Красная Плесень/Золушка`) | ⏳ верное значение неизвестно |
| 4 | `track` пуст у 1438, из них **9 с непустым `cur_track`** → тег `TRCK` будет УДАЛЁН | ⏳ решение Alex |
| 5 | `changed = 'no'` у 213 строк (50 файлов / 61 строка в диффе) | ⏳ уточнить трактовку |
| 6 | Боевой прогон `--apply --verify` | 🔴 не запущен |
| 7 | Контейнер `snapcur` на NAS (только чтение, `:ro`) | ⏳ не убран — Alex не подтвердил |
| 8 | Глазами пройти `field=album` (305 строк) в диффе | ⏳ следующий шаг по указанию Alex |
| 9 | `ДДТ/2008 L'Echoppe` — `ДДТ` (2 файла `ДДТ`) vs 10 файлов `Юрий Шевчук & Константин Казански` | ✅ вердикт: **НЕ порча**, дуэт-альбом, не трогать |
---
# 🔷 СЕССИЯ 6 (2026-09-27, вечер) — `albumartist`-ПЕРЕХВАТ ЧУЖИМ ФАЙЛОМ ПАПКИ
Триггер: Alex по очереди указывал корневые папки — «`Dj Tiesto` — там не Tiesto должен быть
разве albumartist?», «`Банд Эрос` — че за VIP77?», «`The Prodigy` — почему dj feel?».
## 🔴 ГЛАВНАЯ НАХОДКА: класс дефекта «`albumartist` размножен от чужого файла в корне»
**Механизм.** Правило «у корневых файлов папки `albumartist` = имя артиста папки» брало значение
**от первого попавшегося файла в корне**. Если в корень папки артиста затесался ОДИН файл чужого
исполнителя (из сборника), его `albumartist` **расходился на все файлы** папки.
**Проявления (подтверждено фактом, найдено Alex):**
```
The Prodigy DJ Feel ← из трека DJ Feel (Trancemission Vol.9) — 3 файла Prodigy испорчены
Банд Эрос VIP77 ← из трека VIP77 (Russian R'n'B vol.1) — 6 файлов испорчены
```
> ⚠️ **Это не гипотеза — порча видна в `cur_albumartist`**: у `Prodigy/Hotride [EP].mp3`
> и `Prodigy/Record Super Chart (15.08.09).mp3` было `cur_albumartist = 'The Prodigy'`,
> а план ставил `DJ Feel` — **прямое затирание верного значения**.
## 🔧 ДЕТЕКТОР КЛАССА (обязателен после каждой пакетной правки `albumartist`)
📄 **Скрипт сохранён в vault: `personal/tech/scripts/find_aa_hijack.py`**
(копия также в `/tmp/find_aa_hijack.py` — `/tmp` очищается!).
Алгоритм: для каждой папки, где `new_albumartist` **один на всю
папку**, сравнить его с `new_artist` файлов. Признак порчи:
```
new_albumartist не совпадает с top-артистом папки
И не совпадает с именем папки
И совпадает с МИНОРИТАРНЫМ артистом папки
→ ПОДОЗРЕВАЕМЫЙ
```
**Результат прогона: 11 подозреваемых папок.** Разбор:
| Папка | `albumartist` (у скольких) | Должен быть (у скольких) | Вердикт |
|---|---|---|---|
| `The Prodigy` | `DJ Feel` (1) | `The Prodigy` (3) | 🔴 порча |
| `Банд Эрос` | `VIP77` (1) | `Банд'Эрос` (6) | 🔴 порча |
| `Дискотека Авария` | `ДА и Меньшиков` (1) | `Дискотека Авария` (6) | 🔴 порча |
| `Жуки` | `Виктор Жуков` (1) | `Жуки` (10) | 🔴 порча |
| `Потап & Каменских` | `Мика Ньютон` (1) | `Потап и Настя Каменских` (7) | 🔴 порча |
| `Король и Шут` | `КняZz` (1) | `Король и Шут` (3) | 🔴 порча |
| `Ленинград` (корень) | `Бумер` (1) | `Ленинград` (3) + `Сергей Шнуров` (1) | 🔴 порча |
| `ДДТ/2008 L'Echoppe` | `ДДТ` (2) | — | ✅ НЕ порча: `ДДТ` — верный albumartist, 10 файлов = дуэт Шевчук+Казански |
| `Benassi Bros/Re Sfaction` | `Benassi Bros` (3) | — | ✅ решение Alex (сессия 5) |
| `IM/S Is Here (Yahel Mix)` | `Infected Mushroom` (1) | — | ✅ решение Alex (сессия 6) |
| `Детские/Сборка/L` | `Детские песни` (4) | — | ✅ сборник, верно |
**СЕССИЯ 6 ЗАКОНЧИЛАСЬ НА ЭТОМ СПИСКЕ — 7 папок ожидают «go» Alex.**
## ✅ ПРИМЕНЕНО В СЕССИИ 6 (19 файлов)
| Папка | Файлов | Было | Стало | Основание |
|---|---:|---|---|---|
| `Dj Tiesto` | 14 | `Various Artists` | **`Tiesto`** | Alex: «тоже» (13 `In Search of Sunrise 3` + 1 `PoW`) |
| `IM/Life System … Electro Panic … -2016` | 2 | `Various Artists` | **`Infected Mushroom`** | Alex — папка внутри IM |
| `IM/Unreleased/Remixes, Mixes/(2001) … S Is Here (Yahel Mix)` | 3 | `Various Artists` | **`Infected Mushroom`** | Alex: «то же» |
```
MD5 до: 6852b25fd36fe14e97eb7788cdfa844a (DIFF) / 87ab8406509fb99651762886645e35e8 (PLAN)
MD5 после: 3ebc67c9d6abe5fce2d927fcc7726808 (DIFF) / c8d43cc56d82cd35a67a0efe8173cd4b (PLAN)
```
Бэкап: `.bak-before-aa-tiesto-im-20260927-140556`.
Проверка: `ВСЕГО правок 18558 · assert OK · ПОТЕРЯНО 0 · ЛИШНИХ 0 · дифф ПОЛНЫЙ`.
## 📋 КОНТРОЛЬНАЯ ПРОВЕРКА «ЗАТИРАНИЙ» `cur_albumartist` (765 строк)
Скрипт `/tmp/check_aa_overwrite.py`: `cur_albumartist` непуст **и** `new_albumartist != cur_albumartist`
→ **765 строк**. ⚠️ **Почти все — ЗАКОННЫЕ**, это нормализация:
| Класс | Пример | Объём |
|---|---|---|
| CP1251-мойибаке → кириллица | `Èëüÿ ×åðò` → `Илья Чёрт` | ~основная масса |
| Транслит → кириллица | `Vladimir Vysockij` → `Владимир Высоцкий`, `Nautilus Pompilius` → `Наутилус Помпилиус` | — |
| Регистр/пунктуация | `ДИСКОТЕКА АВАРИЯ` → `Дискотека Авария`, `Ногу свело!` → `Ногу Свело!` | — |
| Смена артиста по решению | `OverClocked ReMix` → `Various Artists` (Final Fantasy VI) | 64 |
> 🔴 **Урок: счётчик «765 затираний» — ШУМ, а не список дефектов.** Реальные порчи —
> только те, где значение взято **от чужого файла той же папки** (детектор из раздела выше,
> нашёл 11 подозреваемых из 765). Не рапортовать число 765 как «проблему».
## 🔴 ПРАВИЛО, ВЫВЕДЕННОЕ В СЕССИИ 6
`albumartist` трека = **его собственный артист**, если альбом не сборник.
Значение `albumartist` **НИКОГДА** не размножается на файлы других исполнителей внутри папки.
Если в корне папки артиста лежат треки разных исполнителей — **у каждого свой `albumartist`**
(например, `КняZz` у 1 файла, `Король и Шут` у 3; `Бумер` у 1, `Ленинград` у 3,
`Сергей Шнуров` у 1).
+10 -5
View File
@@ -23,19 +23,24 @@ related:
# Music Tags Repair — TrueNAS (7906 → 7905 файлов)
> ### 🔴 АКТУАЛЬНОЕ СОСТОЯНИЕ (2026-09-27) — ЧИТАЙ ЭТО ПЕРВЫМ
> ## 🔴 АКТУАЛЬНОЕ СОСТОЯНИЕ (2026-09-27, конец сессии 6) — ЧИТАЙ ЭТО ПЕРВЫМ
>
> **Этот файл — исторический лог волны 38 (завершена). Актуальная работа идёт здесь:**
>
> | Документ | О чём |
> |---|---|
> | **[[personal/plans/tagwriter-container]]** | ⭐ скрипт-писатель `apply_tags_v2.py` (566 стр): логика полей, ID3v1-снос, тесты, 18 питфоллов, запуск |
> | **[[personal/plans/music-artist-albumartist-repair]]** | правила формирования плана, сборка `APPLY-PLAN-FINAL2.csv` |
> | **[[personal/plans/music-artist-albumartist-repair]]** | ⭐ **правила формирования плана, `APPLY-PLAN.csv`, дифф `DIFF-new-vs-38.csv`, сессии 1-6** |
> | **[[personal/tech/music-broken-toload]]** | 29 битых/DRM файлов на перезагрузку |
>
> **Состояние:** скрипт готов и протестирован, **боевой прогон НЕ запущен — ждёт «go» от Alex.**
> Боевой вход: `~/Downloads/music-tags/APPLY-PLAN-FINAL2.csv` (7861 строка).
> Скрипты: `~/Automation/music-tags/`.
> **Состояние:** план `APPLY-PLAN.csv` доведён до **0 пустых полей** и проверенного диффа
> (`ПОТЕРЯНО 0 · ЛИШНИХ 0`). **Боевой прогон НЕ запущен — ждёт «go» от Alex.**
> 🔴 Открыт класс дефекта **«`albumartist` размножен от чужого файла в корне папки»** (7 папок) —
> см. сессию 6 в [[personal/plans/music-artist-albumartist-repair]].
>
> Боевой вход: `/Users/admin/Downloads/music-tags/APPLY-PLAN.csv` (**7861 строка**,
> md5 `c8d43cc56d82cd35a67a0efe8173cd4b`). Рабочая папка — **`~/Downloads/music-tags/`**
> (`~/milestones/` больше НЕ существует). Скрипты: `~/Automation/music-tags/`.
>
> ⚠️ Волна 38 (TIT2/TPE1/TALB/TRCK, 7041 файл) — **завершена**, описывается ниже как история.
> Её дефекты (`apply_tags.py` испортил 16 не-MP3, `fix40.py` убил 40 MP3) разобраны в
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Детектор класса «albumartist размножен от чужого файла в корне папки».
Сессия 6, 2026-09-27. Нашёл 7 испорченных папок из 11 подозреваемых
(The Prodigy->DJ Feel, Банд Эрос->VIP77, Дискотека Авария, Жуки,
Потап & Каменских, Король и Шут, Ленинград).
ПРИЗНАК ПОРЧИ:
для папки, где new_albumartist ОДИН на всю папку:
он не совпадает с top-артистом папки
И не совпадает с именем папки
И совпадает с МИНОРИТАРНЫМ артистом папки
-> ПОДОЗРЕВАЕМЫЙ
ЗАПУСК: python3 find_aa_hijack.py
Не меняет файлы. Только печатает.
"""
import csv
import collections
import os
P = '/Users/admin/Downloads/music-tags/APPLY-PLAN.csv'
rows = list(csv.DictReader(open(P, encoding='utf-8-sig', newline='')))
def s(v):
return (v or '').strip()
by_folder = collections.defaultdict(list)
for r in rows:
by_folder[r['folder']].append(r)
suspects = []
for folder, rs in sorted(by_folder.items()):
aa_vals = collections.Counter(s(r['new_albumartist']) for r in rs if s(r['new_albumartist']))
if len(aa_vals) != 1:
continue # смешанные папки — отдельный случай
aa = next(iter(aa_vals))
art = collections.Counter(s(r['new_artist']) for r in rs if s(r['new_artist']))
if not art:
continue
top_artist, top_n = art.most_common(1)[0]
folder_name = os.path.basename(folder)
if aa != top_artist and aa != folder_name and aa in art:
minority = art[aa]
if minority < top_n:
suspects.append((folder, aa, top_artist, top_n, minority, len(rs)))
print(f"ПОДОЗРЕВАЕМЫХ ПАПОК: {len(suspects)}")
print()
for folder, aa, top, tn, mn, tot in suspects:
print(f" albumartist={aa!r} (у {mn} из {tot})")
print(f" должен быть {top!r} (у {tn})")
print(f" {folder}")