[2026-09-26] eagle: personal/plans/music-tags-review/music-tags-review.md personal/tech/music-tags-repair-truenas.md
This commit is contained in:
1 parent
82f27a69da
commit
31644d1010
2 files changed
+397
-18
No files matched your search
@@ -20,6 +20,49 @@ updated: '2026-09-26'
|
|||||||
| [[2-medium-confidence\|Средняя уверенность]] | 5813 |
|
| [[2-medium-confidence\|Средняя уверенность]] | 5813 |
|
||||||
| [[3-high-confidence\|Высокая уверенность]] | 959 |
|
| [[3-high-confidence\|Высокая уверенность]] | 959 |
|
||||||
|
|
||||||
|
## 🔴 Девятнадцатая волна (2026-09-26): ИМЕНА ДИСКОВ ВЫЧИЩЕНЫ + NSK РАЗОБРАН
|
||||||
|
|
||||||
|
Alex: **«Откуда строки с пустым артистом? Это косяк»** → **«Что за NSK? ... Больше нет
|
||||||
|
треков без артиста?»**
|
||||||
|
|
||||||
|
### 🛠 Имена дисков/техпапок в `new_album` — ВЫЧИЩЕНЫ (200 строк)
|
||||||
|
|
||||||
|
**Папка `!Детские/Сборка Песни для детей/` разбита на подпапки-«диски»** (`1`,`2`,`C`,`K`,`L`,`M`,`P`,`Y`,`Les`),
|
||||||
|
и граббер записал имя подпапки в `new_album`. **Это часть пути, не альбом** → 155 строк очищены,
|
||||||
|
реальный альбом `Сборка Песни для детей`. Тот же класс: `misc` (~40: Пилот, Rammstein,
|
||||||
|
Красная Плесень, Eminem), `new` (3, НТЛ), `Album` (1, Пилот) → пусто.
|
||||||
|
|
||||||
|
> ⚠️ Побочно: у `19. Песенка смелого моряка` при вырезании диска съехал `new_track` (был 20).
|
||||||
|
> Проверять `new_track` рядом с вырезаемым `new_album`.
|
||||||
|
|
||||||
|
### 🤔 188 строк без artist — НЕ косяк (проверено по самому раннему бэкапу)
|
||||||
|
|
||||||
|
| Источник | Кол-во |
|
||||||
|
|---|---:|
|
||||||
|
| `!Детские/Сказки/*` — аудиосказки, исполнителя нет | 186 |
|
||||||
|
| `5 POPSA` нарезки (NSK, Перец…) — ID3-кадры пустые | ~12 |
|
||||||
|
| `НАШЕСТВИЕ 2009`, `Голубой щенок` | 2 |
|
||||||
|
|
||||||
|
### 🔬 `NSK.mp3` — разбор живьём на NAS
|
||||||
|
|
||||||
|
`ID3 v2.3` заголовок есть (size=1014), но **кадры пустые** (нули) → тегов нет.
|
||||||
|
MPEG-заголовок `0xFFFB9240` = 128 kbps / 44100 Hz, файл 476 КБ ≈ **29 секунд** — нарезка
|
||||||
|
чарт-сборника. `NSK` = имя файла (вероятно «Новосибирск»), **НЕ название песни**.
|
||||||
|
Artist оставлен **пустым**, а не выдуман.
|
||||||
|
|
||||||
|
**Питфоллы окружения (закрепить):** `ffprobe` молча пусто на пустом ID3; `mutagen` на NAS
|
||||||
|
НЕ установлен; `xxd` на NAS НЕТ; вложенные кавычки в `ssh 'python3 -c "..."'` ломаются →
|
||||||
|
**скрипт локально + `scp` в `/tmp/` + `ssh … 'python3 /tmp/x.py'`**.
|
||||||
|
|
||||||
|
### ⏭ ЖДЁМ РЕШЕНИЯ ALEX по ~12 нарезкам `5 POPSA`
|
||||||
|
|
||||||
|
**A)** вписать artist/title вручную (нужен ID по звуку); **B)** оставить пустым;
|
||||||
|
**C)** `no_change` — не трогать файлы. Сказки (186) — предлагается оставить как есть.
|
||||||
|
|
||||||
|
### 📊 Итог 19-й волны
|
||||||
|
|
||||||
|
`fix` **6931** / `no_change` **976** · 0 битых · 7907 строк · все CRLF · сводные CSV 778 + 7128 = 7906.
|
||||||
|
|
||||||
## 🔴 Восемнадцатая волна (2026-09-26): РЕГРЕССИЯ ПОЧИНЕНА + ДВЕ СВОДНЫЕ CSV СОБРАНЫ
|
## 🔴 Восемнадцатая волна (2026-09-26): РЕГРЕССИЯ ПОЧИНЕНА + ДВЕ СВОДНЫЕ CSV СОБРАНЫ
|
||||||
|
|
||||||
Alex: **«Рэпер сява - поправь на просто "Сява"»** + **«подготовить рядом ещё пару csv»**.
|
Alex: **«Рэпер сява - поправь на просто "Сява"»** + **«подготовить рядом ещё пару csv»**.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ created: '2026-09-26'
|
|||||||
updated: '2026-09-26'
|
updated: '2026-09-26'
|
||||||
type: tech
|
type: tech
|
||||||
namespace: personal
|
namespace: personal
|
||||||
wave: 17
|
wave: 20
|
||||||
tags:
|
tags:
|
||||||
- music
|
- music
|
||||||
- jellyfin
|
- jellyfin
|
||||||
@@ -20,23 +20,32 @@ related:
|
|||||||
|
|
||||||
# Music Tags Repair — TrueNAS (7906 файлов)
|
# Music Tags Repair — TrueNAS (7906 файлов)
|
||||||
|
|
||||||
> **Статус: ВОСЕМНАДЦАТАЯ ВОЛНА (2026-09-26). CSV ГОТОВ К ПРИМЕНЕНИЮ.
|
> **Статус: ДВАДЦАТАЯ ВОЛНА (2026-09-26). CSV ГОТОВ, 0 БИТЫХ СТРОК, 7907 строк.
|
||||||
> `Рэпер Сява`→`Сява`; РЕГРЕССИЯ 18 БИТЫХ СТРОК ПОЧИНЕНА (0 битых); ДВЕ СВОДНЫЕ CSV СОБРАНЫ.
|
> Ждём решения по `NSK.mp3` + «go» на применение.**
|
||||||
> NAS ДОСТУПЕН, применение НЕ начато — ждём «go».**
|
> ✅ **НОВОЕ (20-я волна):** `Перец.mp3` (2 копии в `disk*`) → `Перцы`/`Валдай` (решение Alex
|
||||||
> ✅ **НОВОЕ (18-я волна):** исправлена **собственная регрессия** — при вырезании техпапок из
|
> из `2-medium-confidence.md` — было пропущено); все сводные CSV пересобраны (777 + 7129).
|
||||||
> `new_album` в `z Старое/disk*` (17-я волна) терялись запятые → 18 битых строк. Все починены.
|
> 🔴 **ГЛАВНЫЙ УРОК ВОЛНЫ: ПЕРЕД ОТВЕТОМ ОБ ARTIST/ПРОБЛЕМНОЙ СТРОКЕ — ОТКРЫТЬ НОТЫ РЕВЬЮ.**
|
||||||
> **Урок: после каждого батча считать ЧИСЛО ПОЛЕЙ, не только кавычки и длину файла.**
|
> Alex: «Перец я тебе в доку выписывал! В чем трабл??» — решение **уже было в
|
||||||
> Диагностика: `python3 ~/Downloads/music-tags/diag_fields.py` (гистограмма полей, строки ≠ 11).
|
> `personal/plans/music-tags-review/2-medium-confidence.md`**, ассистент ответил по памяти
|
||||||
> 📊 **Две сводные CSV** (`build_summaries.py`, только чтение): `artists-single-track.csv`
|
> и оставил `Перец`/пусто. Проверять `personal/plans/music-tags-review/*.md` grep'ом по имени
|
||||||
> (**778** строк: artist/title/album/path) + `artists-multi-track.csv` (**7128** строк:
|
> файла, не полагаться на CSV `new_artist`.
|
||||||
> artist/album/track/title/path). **778 + 7128 = 7906 — покрыты все строки.** Сортировка
|
> 🔴 **ВТОРОЙ УРОК: строка-НАДГРОБИЕ ≠ строка к обработке.** `НАШЕСТВИЕ 2009` помечен
|
||||||
> artist→album→track. Пустой artist → sentinel `(без исполнителя)` (иначе Excel схлопнет).
|
> `no_change` + `source = dropped (file removed by user)` — файла нет. Выносить такие строки
|
||||||
> 🖐 **188 строк без artist — НЕ косяк:** 186 из них `!Детские/Сказки/*` (аудиосказки без
|
> в списки «требуют решения» нельзя — Alex: «Нашествие мы блядь снесли откуда он опять взялся?!».
|
||||||
> единого исполнителя), + `НАШЕСТВИЕ 2009`, + `Голубой щенок`. Так было с самого начала.
|
> Фильтровать `source` начинающийся с `dropped` при любых отчётах.
|
||||||
> Итог: **0 битых, 7907 строк, `fix` 6931 / `no_change` 976, ручных правок ~640.**
|
> 🔴 **ТРЕТИЙ УРОК: нет данных → СПРАШИВАТЬ, не оставлять молча пустым.** `NSK.mp3` (2 копии)
|
||||||
> ⏭ Осталось ТОЛЬКО применение: бэкап `Music/backup/` → применение → приёмка в UI →
|
> — artist пустой, вопрос Alex'у не задан → Alex: «Почему ты не спросил меня что с ним делать?!».
|
||||||
> Music-библиотека Jellyfin. Плюс (отдельно) merge-конфликт в `1-needs-decision.md`.
|
> Открытый вопрос теперь вынесен явно (см. ниже).
|
||||||
> **Бэкапы:** `...bak-20260926-184122` (последний до регрессии), `bak-20260926-164432` (самый ранний).
|
> 📊 **Сводные CSV (20-я волна):** `artists-single-track.csv` **777** + `artists-multi-track.csv`
|
||||||
|
> **7129** = **7906 — все строки покрыты.**
|
||||||
|
> 🖐 **190 строк без artist (было 188 — +2 из-за `Перец` не считается, см. разбор):** 186
|
||||||
|
> `!Детские/Сказки/*` (artist не существует), `Голубой щенок/01 - Хоттабыч!`,
|
||||||
|
> `НАШЕСТВИЕ` (надгробие), **`NSK.mp3` ×2**. Живой разбор `NSK.mp3` на NAS: ID3v2.3 заголовок
|
||||||
|
> 1014 Б, **0 кадров** (тело — нули), аудио валидно: 128 kbps / 44100 Hz / **~29 сек**.
|
||||||
|
> Итог: **0 битых, 7907 строк, ручных правок ~641.**
|
||||||
|
> ⏭ Осталось: **решение по `NSK.mp3`** (A/B/C ниже) → бэкап `Music/backup/` → применение →
|
||||||
|
> приёмка в UI → Music-библиотека Jellyfin. Плюс merge-конфликт в `1-needs-decision.md`.
|
||||||
|
> **Бэкапы:** `...bak-20260926-185339` (последний), `bak-20260926-184122`, `bak-20260926-164432` (самый ранний).
|
||||||
>
|
>
|
||||||
> ---
|
> ---
|
||||||
>
|
>
|
||||||
@@ -92,6 +101,333 @@ related:
|
|||||||
> Прогонялись **девять волн** проверок: см. таблицу волн ниже.
|
> Прогонялись **девять волн** проверок: см. таблицу волн ниже.
|
||||||
> Итог v7: «требует решения» **4**, medium **5811**, high **958**, mojibake = 0, остаточный mojibake = 0.
|
> Итог v7: «требует решения» **4**, medium **5811**, high **958**, mojibake = 0, остаточный mojibake = 0.
|
||||||
|
|
||||||
|
## 🖐 ДЕВЯТНАДЦАТАЯ ВОЛНА: СЯВА, РЕГРЕССИЯ, ИМЕНА ДИСКОВ, СВОДНЫЕ CSV (2026-09-26)
|
||||||
|
|
||||||
|
> Триггер: Alex — **«Закончи правку имен песен в csv. Вручную»** → далее **«Доделывай»**,
|
||||||
|
> затем **«Откуда строки с пустым артистом? Это косяк»** → **«Что за NSK? Ты что туда
|
||||||
|
> вписал как артист/трек? Больше нет треков без артиста?»**
|
||||||
|
|
||||||
|
### ✅ 1. `Рэпер Сява` → `Сява` (2 строки)
|
||||||
|
|
||||||
|
Alex: **«Рэпер сява - поправь на просто "Сява"»**. Обе строки в папке
|
||||||
|
`!Pop, Club, Любэ/!Radio/v 2009-03 mIr.vEsNЫ/2 y.MATno.E/`:
|
||||||
|
- `Нука нака.mp3` → `new_artist = Сява` (было `Рэпер Сява`)
|
||||||
|
- `Отдыхаем хорошо(Ida Corr cocktail).mp3` → artist `DJ Иван Silver & Сява`
|
||||||
|
|
||||||
|
> 🔴 **Ошибка при правке:** `patch mode=replace` дал fuzzy-match и **съел первую строку** —
|
||||||
|
> `old_string` совпал частично. Строк стало 7906 вместо 7907. **Обнаружено** сверкой
|
||||||
|
> `diff <(sed 's/Рэпер Сява/Сява/g' bak-184122) tag-fix-plan.csv`. Восстановлено вручную
|
||||||
|
> (вернул строку `Ленинград - Ласточка.mp3`, потерянную при починке).
|
||||||
|
> **Правило: `patch mode=replace` — только по УНИКАЛЬНОМУ тексту; после — сразу `wc -l`.**
|
||||||
|
|
||||||
|
### 🔴 2. РЕГРЕССИЯ 18 БИТЫХ СТРОК — ПОЧИНЕНА (главное этой волны)
|
||||||
|
|
||||||
|
Alex: **«Откуда строки с пустым артистом? Это косяк»**.
|
||||||
|
|
||||||
|
**Диагностика по бэкапам (гистограмма числа полей по волнам):**
|
||||||
|
|
||||||
|
| Бэкап | 3 поля | 10 | 11 | 12 |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| `bak-164432` (самый ранний, 15:15) | 2 | 2 | 7904 | 0 |
|
||||||
|
| `bak-171423` | 2 | 2 | 7904 | 0 |
|
||||||
|
| `bak-180619` (после 17-й волны) | 2 | **10** | 7886 | **10** |
|
||||||
|
| `bak-184122` | 2 | 10 | 7886 | 10 |
|
||||||
|
|
||||||
|
**Вывод: 4 битые строки были ИЗНАЧАЛЬНО** (Пахмутова — многострочный mojibake с `"` внутри,
|
||||||
|
разваливал парсинг). **Остальные 18 — регрессия 17-й волны:** при вырезании техпапок из
|
||||||
|
`new_album` в `z Старое/disk*` (`disk`, `disk_v2`, `5 POPSA`, `2 ALT,PUNK`, `3 SHANSON`)
|
||||||
|
**терялась ровно одна пустая запятая-плейсхолдер**.
|
||||||
|
|
||||||
|
**Три подкласса фикса:**
|
||||||
|
|
||||||
|
| Строк | Дефект | Фикс |
|
||||||
|
|---:|---|---|
|
||||||
|
| 8 | 10 полей — потерян пустой `new_album` | `NSK,,,fix` → `NSK,,,,fix` |
|
||||||
|
| 9 | 12 полей — лишняя пустая запятая | `Nickelback,,,7,fix` → `Nickelback,,7,fix` |
|
||||||
|
| 2 (Трофим) | 12 полей — **запятая в `Короче, дело к ночи` без кавычек** | `,"Короче, дело к ночи",Трофим,,4,fix` |
|
||||||
|
| 2 (Пахмутова) | 3/10 полей — многострочный mojibake с `"` внутри | значение заменено на читаемое `"Пахмутова — Нежность"` / `"Нежность"` |
|
||||||
|
|
||||||
|
**Итог: 22 битых → 0.** Проверено: `diag_fields.py` + `wc -l` = 7907 + CRLF = 7907 + BOM на месте.
|
||||||
|
|
||||||
|
> 🔴 **ПРАВИЛО (закрепить навсегда): после КАЖДОГО батча — считать ЧИСЛО ПОЛЕЙ, не кавычки.**
|
||||||
|
> Проверка кавычек (`awk -F'"' 'NF%2==0'`) и длины файла **НЕ ловит** потерю пустого поля:
|
||||||
|
> 10-полевая строка имеет чётное число кавычек и проходит все старые чекеры.
|
||||||
|
> ```bash
|
||||||
|
> python3 ~/Downloads/music-tags/diag_fields.py # гистограмма: должно быть {11: 7906}
|
||||||
|
> ```
|
||||||
|
|
||||||
|
### 🛠 3. БУКВЕННЫЕ/ЦИФРОВЫЕ ИМЕНА ДИСКОВ В `new_album` — ВЫЧИЩЕНЫ (200 строк)
|
||||||
|
|
||||||
|
**Главный новый класс дефекта.** Папка `!Детские/Сборка Песни для детей/` разбита на
|
||||||
|
подпапки-«диски» (`1`, `2`, `C`, `K`, `L`, `M`, `P`, `Y`, `Les`), и скрипт-граббер записал
|
||||||
|
имя подпапки в `new_album`. **Это часть пути, а не альбом.**
|
||||||
|
|
||||||
|
| Значение `new_album` | Строк | Реальный альбом |
|
||||||
|
|---|---:|---|
|
||||||
|
| `1`, `2`, `C`, `K`, `L`, `M`, `P`, `Y`, `Les` | **155** | `Сборка Песни для детей` |
|
||||||
|
| `misc` (Пилот, Rammstein, Красная Плесень, Eminem) | ~40 | пусто (нет реального альбома) |
|
||||||
|
| `new` (НТЛ) | 3 | пусто |
|
||||||
|
| `Album` (Пилот `Братишка.mp3`) | 1 | пусто |
|
||||||
|
|
||||||
|
Диагностический детектор:
|
||||||
|
```bash
|
||||||
|
awk -F',' 'NR>1 {n=NF; na=(n==11)?8:((n==13)?10:((n==12)?9:0));
|
||||||
|
if(na && length($na)<=4 && $na ~ /^[A-Za-z0-9_]+$/ && $na !~ /[а-яА-Я]/) print NR"|"$na}' tag-fix-plan.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ **Пойман побочный дефект:** в `Сборка Песни для детей` строка `19. Песенка смелого моряка`
|
||||||
|
> содержала `new_album = 1` и `new_track = 20` — при вырезании диска номер трека съехал.
|
||||||
|
> Проверять `new_track` рядом с вырезаемым `new_album`.
|
||||||
|
|
||||||
|
### 📊 4. ДВЕ СВОДНЫЕ CSV (запрос Alex)
|
||||||
|
|
||||||
|
Alex: **«подготовить рядом ещё пару csv: все исполнители с одним треком + путь; все
|
||||||
|
исполнители с более 1 трека, альбом, треки в альбоме, путь. С сортировкой
|
||||||
|
исполнитель/альбом/номер трека. (Имеются в виду исправленные названия для записи)
|
||||||
|
Эти две csv должны включать все строки из оригинальной csv.»**
|
||||||
|
|
||||||
|
Скрипт: `~/Downloads/music-tags/build_summaries.py` (**только чтение** исходника, пишет 2 файла).
|
||||||
|
|
||||||
|
| Файл | Строк | Колонки |
|
||||||
|
|---|---:|---|
|
||||||
|
| `artists-single-track.csv` | **778** | `artist, title, album, path` |
|
||||||
|
| `artists-multi-track.csv` | **7128** | `artist, album, track, title, path` |
|
||||||
|
|
||||||
|
- **778 + 7128 = 7906 — покрыты ВСЕ строки** (проверка встроена в скрипт, печатает `TOTAL COVERED`).
|
||||||
|
- Значения берутся из `new_*`, при пустом — fallback на `cur_*`.
|
||||||
|
- Сортировка: artist → album → track (числовая, `track_key()` с regex `^(\d+)`).
|
||||||
|
- Пустой artist → sentinel **`(без исполнителя)`**, иначе Excel схлопывает группу в невидимую.
|
||||||
|
|
||||||
|
> 🔴 **ПЕРВАЯ ВЕРСИЯ СКРИПТА БЫЛА БИТАЯ:** писала `e["artist"]` (пустой) вместо ключа группировки
|
||||||
|
> `e["key"]` → **189 строк с пустым artist** в `multi`. Alex поймал сразу. Фикс: писать `key`.
|
||||||
|
> **Урок: sentinel бесполезен, если в вывод идёт исходное поле, а не ключ.**
|
||||||
|
|
||||||
|
### 🖐 5. 188 СТРОК БЕЗ ARTIST — РАЗОБРАНЫ ЖИВЬЁМ (не косяк)
|
||||||
|
|
||||||
|
Alex: **«Больше нет треков без артиста?»**
|
||||||
|
|
||||||
|
| Источник | Кол-во | Вердикт |
|
||||||
|
|---|---:|---|
|
||||||
|
| `!Детские/Сказки/*` | 186 | аудиосказки — исполнителя **не существует** (сборник, не песня). Оставить пустым |
|
||||||
|
| `5 POPSA` нарезки (NSK, Перец и др.) | ~12 | ID3-кадры пустые — определять не из чего |
|
||||||
|
| `НАШЕСТВИЕ 2009 - ДЕНЬ ВТОРОЙ.mp3`, `Голубой щенок/01 - Хоттабыч!.mp3` | 2 | фестивальная нарезка / сказка |
|
||||||
|
|
||||||
|
**Проверка по самому раннему бэкапу `bak-164432` подтвердила: так было ИЗНАЧАЛЬНО**, не регрессия.
|
||||||
|
|
||||||
|
### 🔬 6. `NSK.mp3` — ЖИВОЙ РАЗБОР ФАЙЛА НА NAS
|
||||||
|
|
||||||
|
Alex: **«Что за NSK? Ты что туда вписал как артист/трек?»**
|
||||||
|
|
||||||
|
Строка: `new_title = NSK`, `new_artist` = пусто, `new_album` = пусто.
|
||||||
|
|
||||||
|
**Метод (питфоллы окружения):**
|
||||||
|
- `ffprobe` в контейнере/на хосте **молча отдаёт пусто** при битом/пустом ID3 — известный питфолл.
|
||||||
|
- `mutagen` на хосте NAS **НЕ установлен** (`ModuleNotFoundError`).
|
||||||
|
- `xxd` на хосте NAS **НЕТ** (`command not found`).
|
||||||
|
- **Вложенные кавычки в `ssh 'python3 -c "..."'` ломаются** (bash/zsh на NAS). **Рабочий путь:
|
||||||
|
написать скрипт локально → `scp` в `/tmp/` → `ssh … 'python3 /tmp/script.py'`** (совпадает
|
||||||
|
с каноном из `family/how-to/truenas-access.md`).
|
||||||
|
|
||||||
|
**Результат разбора (байты, `python3` на хосте NAS):**
|
||||||
|
```
|
||||||
|
ID3 v2.3 rev0 flags=0x0 size=1014 ← заголовок есть
|
||||||
|
кадров: 0 (тело — нули) ← теги ПОЛНОСТЬЮ пустые
|
||||||
|
audio starts at 1024, first sync 0xFFFB9240 → 128 kbps, 44100 Hz
|
||||||
|
файл 475954 Б ≈ 29 секунд ← валидный MP3, короткая нарезка
|
||||||
|
```
|
||||||
|
|
||||||
|
**Вывод: `NSK.mp3` — 29-секундная нарезка из чарт-сборника с пустыми тегами.** `NSK` в title —
|
||||||
|
это **имя файла** (первые буквы, вероятно от названия сборника/«Новосибирск»), **НЕ название
|
||||||
|
песни**. Раньше в artist лежало `disk_v2`/`5 POPSA` (мусорные папки) — вычищено, artist оставлен
|
||||||
|
**пустым**, а не выдуман.
|
||||||
|
|
||||||
|
> 📌 **Канон `id3_direct.py`:** запускать на **ХОСТЕ** NAS (`truenas_admin@mallexxx.duckdns.org`,
|
||||||
|
> python3 3.11.9 есть) — в контейнере `jellyfin` python3 НЕТ (см. `family/how-to/truenas-access.md`).
|
||||||
|
|
||||||
|
### ⏭ ОТКРЫТЫЙ ВОПРОС К ALEX (ждём ответа)
|
||||||
|
|
||||||
|
По ~12 нарезкам из `5 POPSA` (NSK, Перец, Саундтрек Простоквашено и др.) — три варианта:
|
||||||
|
**A)** вписать artist/title вручную (нужен ID по звуку); **B)** оставить `(без исполнителя)`;
|
||||||
|
**C)** пометить `no_change` — файлы не трогать. Сказки (186) — предлагается оставить как есть.
|
||||||
|
|
||||||
|
### 📊 СОСТОЯНИЕ НА КОНЕЦ ДЕВЯТНАДЦАТОЙ ВОЛНЫ
|
||||||
|
|
||||||
|
| Показатель | Значение |
|
||||||
|
|---|---:|
|
||||||
|
| Строк в CSV | 7906 (+1 заголовок = 7907 в файле) |
|
||||||
|
| **Битых строк** | **0** |
|
||||||
|
| CRLF-потерь | **0** |
|
||||||
|
| Ручных правок (`source = manual (user decision)`) | **~640** |
|
||||||
|
| `fix` / `no_change` | **6931 / 976** |
|
||||||
|
| Сайтов-источников / иероглифов в `new_*` | **0 / 0** |
|
||||||
|
| Техпапок и букв-дисков в `new_album` | **0** |
|
||||||
|
| Сводные CSV | ✅ 778 + 7128 = 7906 |
|
||||||
|
| Применение на NAS | **НЕ начато (ждём «go»)** |
|
||||||
|
|
||||||
|
**Бэкапы:** `bak-20260926-164432` (самый ранний), `bak-20260926-171423`, `bak-20260926-180619`,
|
||||||
|
`bak-20260926-183432`, `bak-20260926-183541`, `bak-20260926-184029`, `bak-20260926-184122`.
|
||||||
|
|
||||||
|
**Рабочие скрипты в `~/Downloads/music-tags/` (все read-only, кроме `build_summaries.py`):**
|
||||||
|
`diag_fields.py` (гистограмма полей), `build_summaries.py` (2 сводные CSV),
|
||||||
|
`repair_broken.py` / `repair_min.py` (черновики починки регрессии — **не применялись**,
|
||||||
|
регрессия починена вручную), `probe_nsk.py` (живой разбор ID3), `check_artist_number.py`,
|
||||||
|
`check_file_vs_csv.py`, `verify_group_a.py`, `dump_block.py`, `find_defects.py`, `probe_real.py`.
|
||||||
|
|
||||||
|
### ⏭ ЧТО ДЕЛАТЬ ПЕРВЫМ ДЕЛОМ В СЛЕДУЮЩЕЙ СЕССИИ
|
||||||
|
|
||||||
|
> ⚠️ **УСТАРЕЛО — см. «ДВАДЦАТАЯ ВОЛНА» выше.** Из 12 нарезок `5 POPSA` решён только `Перец`
|
||||||
|
> (`Перцы`/`Валдай`, 20-я волна). Реальный остаток — **`NSK.mp3` ×2** (A/B/C в 20-й волне).
|
||||||
|
1. Получить от Alex решение по `NSK.mp3` (A/B/C) — см. 20-ю волну.
|
||||||
|
2. **Бэкап `Music/backup/` → применение тегов по «go» → приёмка в UI Alex** → Music-библиотека Jellyfin.
|
||||||
|
3. Отдельно: **чистка merge-конфликта** в `personal/plans/music-tags-review/1-needs-decision.md`.
|
||||||
|
|
||||||
|
## 🖐 ДВАДЦАТАЯ ВОЛНА: ПЕРЕЦ, НАДГРОБИЯ, NSK (2026-09-26)
|
||||||
|
|
||||||
|
> Триггер: Alex — **«Закончи правку имен песен в csv. Вручную»** → **«Доделывай»** →
|
||||||
|
> **«Откуда строки с пустым артистом? Это косяк»** → **«Что за NSK? Ты что туда вписал как
|
||||||
|
> артист/трек? Больше нет треков без артиста?»** → **«Рэпер сява - поправь на просто "Сява"»** →
|
||||||
|
> **«Почему ты не спросил меня что с ним делать?! Это единственный такой трек непонятный?
|
||||||
|
> Все остальное не вызывает никаких сомнений? Перец я тебе в доку выписывал! В чем трабл??
|
||||||
|
> Нашествие мы блядь снесли откуда он опять взялся у тебя в списке?!»**
|
||||||
|
|
||||||
|
### ✅ 1. `Рэпер Сява` → `Сява` (2 строки)
|
||||||
|
|
||||||
|
Обе в `!Pop, Club, Любэ/!Radio/v 2009-03 mIr.vEsNЫ/2 y.MATno.E/`:
|
||||||
|
- `Нука нака.mp3` → `new_artist = Сява`
|
||||||
|
- `Отдыхаем хорошо(Ida Corr cocktail).mp3` → artist `DJ Иван Silver & Сява`
|
||||||
|
|
||||||
|
> 🔴 **Ошибка при правке:** `patch mode=replace` дал **fuzzy-match** и съел первую строку —
|
||||||
|
> стало 7906 вместо 7907. Обнаружено сверкой `diff <(sed 's/Рэпер Сява/Сява/g' bak-184122) tag-fix-plan.csv`.
|
||||||
|
> Затем при починке случайно удалилась строка `Ленинград - Ласточка.mp3` — тоже восстановлена.
|
||||||
|
> **Правило: после `patch` ВСЕГДА `wc -l`, и сверять с бэкапом через `sed`-подстановку.**
|
||||||
|
|
||||||
|
**Второй дефект той же правки:** удаляя `cur_album`/`new_album`, легко потерять **пустое поле** —
|
||||||
|
`,"Сява",,,fix` (11 полей) vs `,"Сява",,fix` (10). Считать поля, не запятые.
|
||||||
|
|
||||||
|
### 🔴 2. `Перец.mp3` — решение Alex БЫЛО В ДОКЕ, ассистент его пропустил
|
||||||
|
|
||||||
|
Alex: **«Перец я тебе в доку выписывал! В чем трабл??»**
|
||||||
|
|
||||||
|
**Реальное решение (в `personal/plans/music-tags-review/2-medium-confidence.md`):**
|
||||||
|
```
|
||||||
|
- **Перец.mp3** → Валдай — Перцы
|
||||||
|
```
|
||||||
|
⇒ `new_artist = Валдай`, `new_title = Перцы`.
|
||||||
|
|
||||||
|
**Почему пропущено:** `Перец.mp3` существует в **трёх** папках:
|
||||||
|
| Путь | Было | Стало |
|
||||||
|
|---|---|---|
|
||||||
|
| `z Старое/Перец.mp3` | ✅ `Перцы`/`Валдай` | (не трогалось, уже верно) |
|
||||||
|
| `z Старое/disk_v2/5 POPSA/Перец.mp3` | ❌ `Перец`/пусто | ✅ `Перцы`/`Валдай` |
|
||||||
|
| `z Старое/disk/5 POPSA/Перец.mp3` | ❌ `Перец`/пусто | ✅ `Перцы`/`Валдай` |
|
||||||
|
|
||||||
|
Ассистент чистил `disk*` и **не сверил с нотами ревью** — искал только по CSV.
|
||||||
|
|
||||||
|
> 🔴 **ПРАВИЛО (закрепить):** перед ответом по ЛЮБОМУ artist/title — **грепнуть
|
||||||
|
> `personal/plans/music-tags-review/*.md` по имени файла**, а не полагаться на текущее
|
||||||
|
> состояние CSV. Нота ревью — первичный источник решения Alex.
|
||||||
|
|
||||||
|
### 🔴 3. `НАШЕСТВИЕ 2009` — строка-НАДГРОБИЕ, а не задача
|
||||||
|
|
||||||
|
Alex: **«Нашествие мы блядь снесли откуда он опять взялся у тебя в списке?!»**
|
||||||
|
|
||||||
|
Строка 883: `no_change` + `source = dropped (file removed by user)`. **Файла нет** — Alex снёс.
|
||||||
|
Метка стоит с 16:57 (`bak-165750`), присутствует во всех бэкапах (строка не удалена из CSV
|
||||||
|
намеренно — чтобы не потерять `path`).
|
||||||
|
|
||||||
|
**Промах:** ассистент вынес её в список «строки без artist» как будто она к обработке.
|
||||||
|
Это сбило с толку.
|
||||||
|
|
||||||
|
> 🔴 **ПРАВИЛО:** при любых отчётах/списках **фильтровать `source`, начинающийся с `dropped`**.
|
||||||
|
> Такие строки — история, не работа. Отдельный вопрос Alex'у: убирать ли надгробия из CSV вообще.
|
||||||
|
|
||||||
|
### 🖐 4. ПОЛНЫЙ РАЗБОР строк без artist — 190 (не 188)
|
||||||
|
|
||||||
|
Скрипт: `~/Downloads/music-tags/list_noartist.py` (read-only).
|
||||||
|
|
||||||
|
| Источник | Кол-во | Вердикт |
|
||||||
|
|---|---:|---|
|
||||||
|
| `!Детские/Сказки/*` | **186** | у аудиосказок artist **не существует** (сборник, не песня). Решение Alex: оставить как есть, дубли разберёт сам |
|
||||||
|
| `Голубой щенок/01 - Хоттабыч!.mp3` | 1 | часть сказки «Голубой щенок» — artist не нужен |
|
||||||
|
| `!A Not sorted/НАШЕСТВИЕ 2009…` | 1 | **надгробие**, файла нет |
|
||||||
|
| `…/disk_v2/5 POPSA/NSK.mp3` | 1 | ❓ нарезка, теги пустые |
|
||||||
|
| `…/disk/5 POPSA/NSK.mp3` | 1 | ❓ та же нарезка, копия |
|
||||||
|
|
||||||
|
**Проверено по самому раннему бэкапу `bak-164432`:** так было ИЗНАЧАЛЬНО, это **не регрессия**.
|
||||||
|
|
||||||
|
### 🔬 5. `NSK.mp3` — живой разбор на NAS (артефакт для будущих сессий)
|
||||||
|
|
||||||
|
Alex: **«Что за NSK? Ты что туда вписал как артист/трек?»**
|
||||||
|
|
||||||
|
Строка: `new_title = NSK`, `new_artist = пусто`, `new_album = пусто`.
|
||||||
|
|
||||||
|
**Результат байтового разбора (`python3` на ХОСТЕ NAS):**
|
||||||
|
```
|
||||||
|
ID3 v2.3 rev0 flags=0x0 size=1014 ← заголовок есть, syncsafe = 0x000776
|
||||||
|
кадров: 0 (тело — полностью нули) ← теги ПУСТЫЕ
|
||||||
|
audio starts at 1024, first sync 0xFFFB9240 → 128 kbps, 44100 Hz
|
||||||
|
file size 475954 Б ≈ 29 секунд ← валидный MP3, короткая нарезка
|
||||||
|
```
|
||||||
|
|
||||||
|
**Вывод:** 29-секундная нарезка из чарт-сборника с пустыми тегами. `NSK` в title — **имя файла**
|
||||||
|
(вероятно «Новосибирск» или имя сборника-источника), **НЕ название песни**. Раньше в artist
|
||||||
|
лежал мусор `disk_v2`/`5 POPSA` — вычищен, artist оставлен **пустым** (не выдуман).
|
||||||
|
|
||||||
|
**Открытый вопрос Alex'у (A/B/C):**
|
||||||
|
- **A)** вписать artist/title вручную по звуку (нужен ID)
|
||||||
|
- **B)** оставить `(без исполнителя)`, title = `NSK`
|
||||||
|
- **C)** пометить `no_change` — файл не трогать
|
||||||
|
|
||||||
|
**Питфоллы окружения (проверено в этой волне):**
|
||||||
|
- `ffprobe` на хосте/в контейнере **молча отдаёт пусто** при пустом ID3 — не доказательство.
|
||||||
|
- `mutagen` на хосте NAS **НЕ установлен** (`ModuleNotFoundError`).
|
||||||
|
- `xxd` на хосте NAS **НЕТ** (`command not found`).
|
||||||
|
- 🔴 **Вложенные кавычки в `ssh 'python3 -c "..."'` ломаются** (zsh/bash на NAS съедает их,
|
||||||
|
скрипт получает пустоту). **Рабочий путь: написать скрипт локально → `scp` в `/tmp/` →
|
||||||
|
`ssh … 'python3 /tmp/script.py'`.** Совпадает с каноном `family/how-to/truenas-access.md`.
|
||||||
|
- Питфолл `sed`: `\r\n`-split в Python даёт сдвиг номеров строк после правок — брать строки
|
||||||
|
по **тексту**, не по номеру (`grep -n`, потом `sed -n` для просмотра).
|
||||||
|
|
||||||
|
### 📊 6. Сводные CSV пересобраны после правок
|
||||||
|
|
||||||
|
`python3 ~/Downloads/music-tags/build_summaries.py` (read-only исходника, пишет 2 файла):
|
||||||
|
|
||||||
|
| Файл | Строк | Колонки |
|
||||||
|
|---|---:|---|
|
||||||
|
| `artists-single-track.csv` | **777** | `artist, title, album, path` |
|
||||||
|
| `artists-multi-track.csv` | **7129** | `artist, album, track, title, path` |
|
||||||
|
|
||||||
|
**777 + 7129 = 7906 — покрыты ВСЕ строки** (проверка `TOTAL COVERED` встроена в скрипт).
|
||||||
|
Пустой artist → sentinel **`(без исполнителя)`**; для сказок ключ `(без исполнителя) — <album>`.
|
||||||
|
|
||||||
|
### 📊 СОСТОЯНИЕ НА КОНЕЦ ДВАДЦАТОЙ ВОЛНЫ
|
||||||
|
|
||||||
|
| Показатель | Значение |
|
||||||
|
|---|---:|
|
||||||
|
| Строк в CSV | 7906 данных + заголовок = **7907** |
|
||||||
|
| **Битых строк** | **0** |
|
||||||
|
| CRLF-потерь | **0** |
|
||||||
|
| Ручных правок | **~641** |
|
||||||
|
| Строк без artist | **190** (186 сказки + 4 прочие) |
|
||||||
|
| Сводные CSV | ✅ 777 + 7129 = 7906 |
|
||||||
|
| Применение на NAS | **НЕ начато (ждём «go»)** |
|
||||||
|
|
||||||
|
**Бэкапы:** `bak-20260926-185339` (последний, 20-я волна), `bak-20260926-184122`,
|
||||||
|
`bak-20260926-164432` (самый ранний).
|
||||||
|
|
||||||
|
**Рабочие скрипты `~/Downloads/music-tags/`:**
|
||||||
|
`diag_fields.py` (гистограмма полей), `build_summaries.py` (2 сводные CSV),
|
||||||
|
`list_noartist.py` (**новый, 20-я волна** — полный список строк без artist по папкам),
|
||||||
|
`probe_nsk.py` (живой разбор ID3 — переиспользован для дампа кадров),
|
||||||
|
`repair_broken.py` / `repair_min.py` (черновики, **не применялись** — регрессия починена вручную).
|
||||||
|
|
||||||
|
### ⏭ ЧТО ДЕЛАТЬ ПЕРВЫМ ДЕЛОМ В СЛЕДУЮЩЕЙ СЕССИИ
|
||||||
|
|
||||||
|
1. **Получить от Alex решение по `NSK.mp3`** (A/B/C выше) — 2 строки.
|
||||||
|
2. Спросить, убирать ли **строку-надгробие** `НАШЕСТВИЕ 2009` из CSV.
|
||||||
|
3. **Бэкап `Music/backup/` → применение тегов по «go» → приёмка в UI Alex** → Music-библиотека Jellyfin.
|
||||||
|
4. Отдельно: **чистка merge-конфликта** в `personal/plans/music-tags-review/1-needs-decision.md`.
|
||||||
|
|
||||||
## 🖐 СЕМНАДЦАТАЯ ВОЛНА: ЧИСТКА `no_change` — САЙТЫ, ИЕРОГЛИФЫ, ВОДА (2026-09-26)
|
## 🖐 СЕМНАДЦАТАЯ ВОЛНА: ЧИСТКА `no_change` — САЙТЫ, ИЕРОГЛИФЫ, ВОДА (2026-09-26)
|
||||||
|
|
||||||
> Триггер: Alex — **«Продолжай до конца»**, затем **«Можешь точечно использовать батч правки
|
> Триггер: Alex — **«Продолжай до конца»**, затем **«Можешь точечно использовать батч правки
|
||||||
|
|||||||
Reference in new issue
Block a user