[2026-09-26] eagle: personal/tech/music-tags-final-review.md personal/tech/music-tags-repair-truenas.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-26 20:16:28 +06:00
1 parent e4fad5b356
commit d7a3e90631
2 files changed
+120 -4

No files matched your search

+32 -3
View File
@@ -18,9 +18,11 @@ related:
_Обновлено: 2026-09-26. Источник: `~/Downloads/music-tags/tag-fix-plan.csv`._
> ## ✅ ГОТОВО К АППРУВУ
> ## ✅ ГОТОВО К АППРУВУ (28-я волна)
> **Построчное чтение завершено: 1–7906 (100%).** 27-я волна закрыла блок 6402–7906.
> 28-я волна добавила **сквозную нумерацию треков по дискам** (9 многодисковых альбомов).
> Все проверки пройдены. Жду слово Alex («go») для бэкапа и применения тегов.
> ⚠️ Открытый вопрос: 104 дубля `(album, track)` — копии релизов в разных папках (дедупликация).
> Полный контекст волн — `personal/tech/music-tags-repair-truenas.md`.
## Состав файлов
@@ -28,10 +30,12 @@ _Обновлено: 2026-09-26. Источник: `~/Downloads/music-tags/tag-f
| Файл | Строк | Что это |
|---|---|---|
| `tag-fix-plan.csv` | 7906 | Главный план правок, 11 колонок |
| `artists-single-track.csv` | 3223 | Разбивка: треки БЕЗ номера (artist/title/album/path) |
| `artists-multi-track.csv` | 4667 | Разбивка: треки С номером (artist/album/track/title/path) |
| `artists-single-track.csv` | 3196 | Разбивка: треки БЕЗ номера (artist/title/album/path) |
| `artists-multi-track.csv` | 4694 | Разбивка: треки С номером (artist/album/track/title/path) |
| | **7890** | = сумма сводок (16 строк отфильтрованы: 15 skip + 1 намеренно пустая) |
_Сводки пересобраны в 28-й волне после сквозной нумерации (`rebuild_summaries.py`)._
## Действия
| action | строк | смысл |
@@ -81,3 +85,28 @@ _Обновлено: 2026-09-26. Источник: `~/Downloads/music-tags/tag-f
- `ty_49` / `пакет.mp3` (`!Radio/y OOF/`) — оставлен.
- 46 уникальных альбомов после снятия года — с официальными треклистами не сверялись
(кроме Pushnoy, где регрессия найдена и исправлена).
## Сквозная нумерация по дискам (28-я волна)
9 многодисковых альбомов перенумерованы непрерывно (Диск N = offset от суммы треков
предыдущих дисков). Все — без дыр и дублей:
| Album | Итог | Треков |
|---|---|---:|
| `Final Fantasy VI: Balance and Ruin` | 1–74 | 74 |
| `изBESTняк` | 1–40 | 40 |
| `Алиса в Стране Чудес` (2 диска + транслит-папка) | 1–34 | 34 |
| `Трое из Простоквашино` | 1–20 | 20 |
| `Лунапарк` | 1–19 | 19 |
| `Live Aus Berlin [Limited Edition]` | 1–18 | 18 |
| `Принц и нищий` | 1–14 | 14 |
| `Малыш и Карлсон` | 1–6 | 6 |
| `Остров сокровищ` | 1–6 | 6 |
## ⚠️ Открытый вопрос: 104 дубля `(album, track)`
Это **не диски**, а одни и те же релизы, лежащие в двух папках на диске
(`Город дорог` 15, `Мат без электричества` 13, `Живая коллекция` 13,
`Второй Магаданский` 11, `Lies For The Liars` 11, `Ч\Б` 8,
`Аристократия помойки 1–4`, `Война и мир`, `Ветер в голове`, `SMS`, `MCMXC A.D.` и др.).
Решаются **дедупликацией файлов**, не нумерацией. Нужно решение Alex.
+88 -1
View File
@@ -4,7 +4,7 @@ created: '2026-09-26'
updated: '2026-09-26'
type: tech
namespace: personal
wave: 27
wave: 28
tags:
- music
- jellyfin
@@ -20,6 +20,93 @@ related:
# Music Tags Repair — TrueNAS (7906 файлов)
> ## ✅ ДВАДЦАТЬ ВОСЬМАЯ ВОЛНА (2026-09-26) — СКВОЗНАЯ НУМЕРАЦИЯ ТРЕКОВ ПО ДИСКАМ
>
> Триггер: Alex — «там где ты убрал номера дисков из альбомов (сказки) теперь треки дублированы,
> нужно для вторых дисков сквозную нумерацию».
>
> ### Суть проблемы
> В волнах 23–26 из `new_album` снимались год-префиксы и диск-суффиксы
> (`Трое из Простоквашино (Диск 2)` → `Трое из Простоквашино`). Для многодисковых релизов это
> **склеило разные диски в один album**: у Диска 1 и Диска 2 остались одинаковые `new_track`
> (1, 2, 3 …). В Jellyfin это выглядит как дубликаты треков.
>
> ### Решение: сквозная нумерация
> Диск N получает offset = сумма числа треков всех дисков с меньшим номером.
> Порядок внутри диска — по номеру из имени файла (не по текущему `new_track`).
>
> ### Итог — 9 альбомов (119+ треков), все непрерывны без дыр и дублей
>
> | Album | Диски (исходные папки) | Кол-во треков | Итог |
> |---|---|---:|---|
> | `Final Fantasy VI: Balance and Ruin` | Disc 1–5 (`Mc 5 - Bonus`) | 17/17/16/10/14 | **1–74** |
> | `Алиса в Стране Чудес` | `(Диск1)`,`(Диск2)`,`Alisa v strane chudes` | 13/13/8 | **1–34** |
> | `изBESTняк` | `CD 1`,`CD 2` | 20/20 | **1–40** |
> | `Лунапарк` | `CD1`,`CD2` | 12/7 | **1–19** |
> | `Live Aus Berlin [Limited Edition]` | `…CD1`,`…CD2` | 12/6 | **1–18** |
> | `Принц и нищий` | `(Диск 1)`,`(Диск 2)` | 7/7 | **1–14** |
> | `Трое из Простоквашино` | `(Диск 1)`,`(Диск 2)` | 9/11 | **1–20** |
> | `Малыш и Карлсон` | `(Диск 1)`,`(Диск 2)` | 3/3 | **1–6** |
> | `Остров сокровищ` | `(Диск 1)`,`(Диск 2)` | 4/2 | **1–6** |
>
> ### 🔴 ГЛАВНЫЙ УРОК ВОЛНЫ: НЕИДЕМПОТЕНТНЫЙ СКРИПТ
> Первая версия (`fix_disc_auto.py`) читала **текущий** `new_track` и прибавляла offset.
> Повторный прогон прибавил offset **второй раз** (Disc 4: 10 → 60 → 110).
> Alex получил бы молча испорченный файл, если бы скрипт по ошибке запустили дважды.
> **Правило:** любой скрипт, меняющий номер, обязан считать цель **от исходного значения
> (номер из имени файла), а не от текущего**. Второй прогон должен давать «nothing».
> Финальный `fix_disc_final.py` — идемпотентен, проверено вторым прогоном (0 изменений).
> Откат делался из `bak-*-disc` (состояние ДО всех disc-правок).
>
> ### 🔴 ВТОРОЙ УРОК: Unicode-нормализация имён папок
> Папка `Принц и нищий (Диск 2)` существовала в **двух разных формах**: NFC и NFD
> (combining breve `U+0306` в слове «нищий»). `csv`/`os` их не различают визуально,
> поэтому album разъехался на `Принц и нищий` и `Принц и нищий`, а номера — на 1-7 / 9-14 / 8.
> Лечение: `unicodedata.normalize("NFC", …)` перед любыми сравнениями имён папок/альбомов.
> **При склейке альбомов всегда нормализовать Unicode.**
>
> ### 🔴 ТРЕТИЙ УРОК: транслит-папка = ещё один диск
> `Alisa v strane chudes` (латиница, 8 треков) — это **третий диск** того же релиза, не отдельный
> альбом. Распознаётся по совпадению набора треков с кириллическими папками. Не группировать
> по признаку «кириллица/латиница в имени папки» — группировать по совпадению содержимого.
>
> ### ⚠️ ОСТАЛОСЬ (НЕ диски — отдельная задача)
> 104 пары `(album, track)` дублируются, но это **одни и те же релизы в двух папках на диске**,
> а не диски: `Город дорог` (15), `Мат без электричества` (13), `Живая коллекция` (13),
> `Второй Магаданский` (11), `Lies For The Liars` (11), `Ч\Б` (8), `Аристократия помойки 1–4`,
> `Война и мир`, `Ветер в голове`, `SMS`, `MCMXC A.D.`, `Oblivion`-синглы и др.
> Решаются **дедупликацией файлов**, не нумерацией. Ждут решения Alex.
>
> ### 📊 ФИНАЛЬНОЕ СОСТОЯНИЕ (28-я волна)
>
> | Показатель | Значение |
> |---|---:|
> | `tag-fix-plan.csv` | **7906 строк, 0 битых** |
> | `fix` / `no_change` / `skip` | **6934 / 957 / 15** |
> | `artists-single-track.csv` | **3196** |
> | `artists-multi-track.csv` | **4694** |
> | Сумма сводок | **7890** |
> | Многодисковых альбомов со сквозной нумерацией | **9** |
> | Остаточных дублей `(album, track)` | **104** (копии релизов в разных папках) |
>
> ### 🛠 СКРИПТЫ ВОЛНЫ (все по схеме tmp + валидация + `os.replace`)
> - `fix_disc_auto.py` — ❌ **отозван**, неидемпотентен (накапливает offset).
> - `fix_disc_tracks.py` / `_2` / `_3` — промежуточные, тоже отозваны.
> - `fix_disc_final.py` — ✅ **рабочий**: сквозная нумерация 8 альбомов, идемпотентен.
> - `fix_disc_fixup.py` — выравнивание album `Принц и нищий` (+ Лунапарк из имён файлов).
> - `fix_alisa3.py` — транслит-папка как 3-й диск (`+26`).
>
> ⏭ **СЛЕДУЮЩИЙ ШАГ (ждёт слова Alex):**
> 1. Решение по 104 дублям релизов: разбирать (дедупликация) или принять как есть.
> 2. Alex глазами проверяет `artists-single-track.csv` / `artists-multi-track.csv` → **аппрув**.
> 3. После аппрува: бэкап в `Music/backup/` → применение → приёмка в UI Jellyfin →
> `rm -rf Music/backup/` → создание Music-библиотеки.
>
> **Бэкапы 28-й волны:** `bak-*-disc`, `bak-*-disc2`, `bak-*-disc3`, `bak-*-discauto`,
> `bak-*-broken-double`, `bak-*-discfinal`, `bak-*-fixup`, `bak-*-alisa3`, `bak-*-disclast`.
>
> ---
>
> ## ✅ ДВАДЦАТЬ СЕДЬМАЯ ВОЛНА (2026-09-26) — ПОСТРОЧНОЕ ЧТЕНИЕ ЗАВЕРШЕНО: 1–7906 (100%)
>
> **Весь файл прочитан глазами построчно. Готов к аппруву Alex.** Триггер: Alex —