[2026-09-27] eagle: family/how-to/navidrome-truenas-android.md personal/plans/music-artist-albumartist-repair.md personal/plans/tagwriter-container.md
This commit is contained in:
1 parent
d520e6331d
commit
9f62092089
3 files changed
+157
-25
No files matched your search
@@ -79,10 +79,18 @@ Navidrome поднялся и просканировал **8043 трека**. П
|
||||
| Реальный скобочный мусор | **306 строк / 15 папок** |
|
||||
|
||||
**Итог:** 306 строк исправлены (скобочный мусор → 0), затем **ещё 58 строк по 3 дефектам**
|
||||
(склейка артист+год, чужой `albumartist`, `album`=название песни) → сгенерирован новый дифф
|
||||
`DIFF-new-vs-38-v2.csv` (⏭ устарел после правки 58 строк, требует перегенерации).
|
||||
(склейка артист+год, чужой `albumartist`, `album`=название песни), затем **+12** (`Шнуров`→`Ленинград`,
|
||||
`NONSONS - zvezda`→`zvezda`). **Всего 371 строка.** Дифф **`DIFF-new-vs-38-v2.csv` перегенерирован**
|
||||
(164 album-строки, полнота 18/18 + 6/6 проверена).
|
||||
Полный разбор — [[personal/plans/music-artist-albumartist-repair]] §СЕССИЯ 18.
|
||||
|
||||
> 🔴 **ПРИЁМКА NAVDROME ДАЛА ДВОЙНОЙ РЕЗУЛЬТАТ — оба важны:**
|
||||
> 1. **Движок подтверждён на живых данных** — теги читаются, папки игнорируются, бага Jellyfin нет.
|
||||
> 2. **Вскрыт дефект ВХОДНОГО ПЛАНА**, который не видел ни один валидатор и ни один дифф:
|
||||
> мусор, унаследованный из источника, присутствует в **обеих** версиях плана → дифф показывает
|
||||
> «совпало». **Открывать данные в UI-потребителе = самый эффективный способ найти мусор в тегах,
|
||||
> который не ловится сверкой файлов.**
|
||||
|
||||
## 🔴 УРОК: разброс значений в папке ≠ дефект (метод-урок сессии 18)
|
||||
|
||||
При проверке «один ли `album`/`albumartist` в папке» получено **96 папок с разными `album`
|
||||
|
||||
@@ -19,7 +19,7 @@ related:
|
||||
- '[[personal/tech/music-tags-repair-truenas]]'
|
||||
- '[[personal/plans/tagwriter-container]]'
|
||||
- '[[family/how-to/navidrome-truenas-android]]'
|
||||
status: session18-complete-waiting-apply-step2
|
||||
status: session18-step2-done-dryrun-ok-awaiting-apply-go
|
||||
# Music `artist` + `albumartist` Repair — правила Alex и ход работ
|
||||
|
||||
## 🟣 СЕССИЯ 18 (2026-09-27) — NAVIDROME РАЗВЁРНУТ, ДЕФЕКТ-КЛАСС ВСКРЫТ, ПРАВИЛА ВОССТАНОВЛЕНЫ ИЗ ZULIP, 306 СТРОК ИСПРАВЛЕНЫ, НОВЫЙ ДИФФ ГОТОВ
|
||||
@@ -35,9 +35,13 @@ status: session18-complete-waiting-apply-step2
|
||||
> ✅ Дифф **`DIFF-new-vs-38-v2.csv` ПЕРЕГЕНЕРИРОВАН** (164 album-строки, +12), полнота проверена —
|
||||
> все 18 целевых `album` и 6 `albumartist` внутри. Старый дифф **не тронут**.
|
||||
> Alex дал команду **«применяй»** → **ШАГ 1 (сверка артефактов) ПРОЙДЕН**: найдено 2 расхождения
|
||||
> (скрипт на NAS и план на NAS — оба старые). ⏭ **ШАГ 2 не начат — ждёт «шаг 2» от Alex.**
|
||||
> (скрипт на NAS и план на NAS — оба старые). **ШАГ 2 ТОЖЕ ВЫПОЛНЕН:** артефакты залиты,
|
||||
> MD5 сверены, **dry-run `exit=0` — 7651 к обработке, не найдено 0**. По ходу найден и закрыт
|
||||
> дефект: 3 файла `Green Apelsin` имели изменённый `new_album` при старом флаге `changed=no`
|
||||
> → пересчёт `changed` по всем 7861, контроль `0`. ⏭ **ШАГ 3 (`--apply --verify`) ждёт «go».**
|
||||
> Канонический раннер: `~/Automation/music-tags/run_tagwriter.sh`.
|
||||
> См. §ПРАВКА 3 ДЕФЕКТОВ, §КАЛИБРОВКА ДЕТЕКТОРОВ, §СДЕЛАНО: правка 306 строк, §НОВЫЙ ДИФФ,
|
||||
> §СВЕРКА АРТЕФАКТОВ ШАГ 1.
|
||||
> §СВЕРКА АРТЕФАКТОВ ШАГ 1, §ШАГ 2 ВЫПОЛНЕН.
|
||||
|
||||
> **Контекст:** Navidrome поднят и просканировал библиотеку (8043 трека). Alex открыл UI и
|
||||
> спросил: «**Откуда альбомы в скобках взялись?** Типа `Дискотека Авария` — для корня,
|
||||
@@ -533,18 +537,29 @@ Alex: «**Отлично, применяй**». Прогон **НЕ запуще
|
||||
> CMD ["python3", "/app/apply_tags_v2.py", "--dry-run"] ← нет ENTRYPOINT, нет USER
|
||||
> ```
|
||||
|
||||
### ⏭ ШАГ 2 (НЕ ВЫПОЛНЕН — ждёт «шаг 2» от Alex)
|
||||
### ✅ ШАГ 2 ВЫПОЛНЕН — ЗАЛИВКА, DRY-RUN, ДЕФЕКТ `changed` ЗАКРЫТ
|
||||
|
||||
1. `docker cp` актуального `apply_tags_v2.py` (Mac) → контейнер `/app/apply_tags_v2.py`
|
||||
2. Залить актуальный `APPLY-PLAN.csv` (Mac) → NAS `/mnt/RED_2TB/docker/arr/tagwriter/apply-plan.csv`
|
||||
3. Сверить MD5 обоих на NAS после заливки
|
||||
4. `--dry-run` → сверить счётчики
|
||||
5. **Только после «go»** — `--apply --verify`
|
||||
1. ✅ `apply_tags_v2.py` (Mac) → NAS `/mnt/RED_2TB/docker/arr/tagwriter/` — MD5 `c7a2bc14…` совпал
|
||||
2. ✅ `APPLY-PLAN.csv` (Mac) → NAS `apply-plan.csv` — MD5 `bc20f2a4…` совпал
|
||||
3. ✅ Dry-run `exit=0`: **7651 к обработке**, `не найдено 0`
|
||||
|
||||
> 🔴 **Найден и закрыт дефект:** 3 файла `Green Apelsin` имели изменившийся `new_album`,
|
||||
> но **старый флаг `changed=no`** → скрипт их бы пропустил. Пересчёт `changed` по всем 7861
|
||||
> (`/tmp/recalc_changed.py`) → **контроль: расхождений 0**. Детали —
|
||||
> [[personal/plans/tagwriter-container]] §СЕССИЯ 18.
|
||||
|
||||
> 🔴 **Правило шага 1:** **перед необратимым прогоном сверять MD5 скрипта (Mac / образ / NAS)
|
||||
> и плана (Mac / NAS).** В этой сессии расхождения нашлись в ДВУХ местах из двух проверенных —
|
||||
> без сверки прогон пошёл бы **по старому плану без 371 правки**.
|
||||
|
||||
### ⏭ ШАГ 3 (НЕ ВЫПОЛНЕН — ждёт «go» от Alex)
|
||||
|
||||
```bash
|
||||
bash ~/Automation/music-tags/run_tagwriter.sh apply # 7651 файл, --apply --verify
|
||||
```
|
||||
Канонический раннер — [[personal/plans/tagwriter-container]] §СЕССИЯ 18.
|
||||
Бэкап `Music/backup` (50 ГБ) на месте, без него `cmd_apply()` → `exit 2`.
|
||||
|
||||
### ✅ Артефакты сессии 18
|
||||
|
||||
| Файл | Что |
|
||||
|
||||
@@ -4,7 +4,7 @@ created: '2026-09-26'
|
||||
updated: '2026-09-27'
|
||||
type: plan
|
||||
namespace: personal
|
||||
status: session17-image-built-deployed-dryrun-ok-awaiting-apply-go
|
||||
status: session18-artifacts-uploaded-dryrun-ok-awaiting-apply-go
|
||||
tags:
|
||||
- music
|
||||
- truenas
|
||||
@@ -20,7 +20,114 @@ related:
|
||||
---
|
||||
# tagwriter — применение тегов к MP3 (TrueNAS)
|
||||
|
||||
## 🔴 СЕССИЯ 17: АУДИТ APPLY-СКРИПТА ПЕРЕД БОЕВЫМ ПРОГОНОМ — ЧИТАТЬ ПЕРВЫМ
|
||||
## 🟢 СЕССИЯ 18: КАНОНИЧЕСКИЙ РАННЕР, ЗАЛИВКА АРТЕФАКТОВ, DRY-RUN OK — ЖДЁТ «GO»
|
||||
|
||||
> **СОСТОЯНИЕ:** артефакты залиты на NAS, MD5 сверены, dry-run `exit=0`.
|
||||
> **Осталось: боевой `--apply --verify` (7651 файл) — ждёт команды Alex.**
|
||||
|
||||
### ⭐ КАНОНИЧЕСКИЙ РАННЕР: `~/Automation/music-tags/run_tagwriter.sh`
|
||||
|
||||
Единая точка входа. Зафиксированная последовательность вместо ручных шагов
|
||||
(жалоба Alex: «**почему у тебя каждый раз хуйня выходит при прогонах? У тебя записана
|
||||
чёткая последовательность действий для прогона?**»).
|
||||
|
||||
```bash
|
||||
bash ~/Automation/music-tags/run_tagwriter.sh dry # сухой прогон (Music :ro)
|
||||
bash ~/Automation/music-tags/run_tagwriter.sh apply # боевой (Music rw, --apply --verify)
|
||||
bash ~/Automation/music-tags/run_tagwriter.sh readback # сверка без записи
|
||||
```
|
||||
|
||||
Скрипт сам: печатает MD5 (Mac скрипт/план + NAS скрипт/план) → `docker create` →
|
||||
`docker start -a` → `docker rm -f`. **Механизм `create`+`start -a` не требует апрува**
|
||||
(`docker run` — требует).
|
||||
|
||||
### 🔴 МЕХАНИЗМ ЗАПУСКА — восстановлен из базы Zulip (дока врала)
|
||||
|
||||
Предыдущая версия доки предписывала `docker cp` и образ `tagwriter:v2` — **оба неверны**.
|
||||
Фактическая команда (из Zulip, сообщения 126978, 126989, 127135):
|
||||
|
||||
```bash
|
||||
ssh truenas_admin@mallexxx.duckdns.org '
|
||||
docker create --name twdry --entrypoint python3 \
|
||||
-v /mnt/RED_2TB/docker/arr/tagwriter:/app/data \
|
||||
-v /mnt/RED_2TB/storage/Music:/music:ro \
|
||||
tagwriter:latest /app/data/apply_tags_v2.py --dry-run
|
||||
docker start -a twdry; docker rm -f twdry
|
||||
'
|
||||
```
|
||||
|
||||
| Что | Правильно | Дока говорила |
|
||||
|---|---|---|
|
||||
| Образ | **`tagwriter:latest`** | ❌ `tagwriter:v2` (устаревший) |
|
||||
| Скрипт | **монтируется** через `--entrypoint python3 /app/data/apply_tags_v2.py` | ❌ «нужен `docker cp`» |
|
||||
| Музыка (боевой) | `/music` **без** `:ro` | ✅ верно |
|
||||
| Музыка (сухой) | `/music:ro` | ✅ верно |
|
||||
| `save(v1=0)` | ⚠️ ID3v1-комментарий **уцелел** в тесте | ❌ «сносит ID3v1 всегда» |
|
||||
|
||||
### ✅ РЕЗУЛЬТАТ ЗАЛИВКИ И DRY-RUN (факт, конец сессии 18)
|
||||
|
||||
**MD5 после заливки (Mac ↔ NAS сверены):**
|
||||
```
|
||||
скрипт apply_tags_v2.py c7a2bc143e38820f2050310cbe01b799 (Mac = NAS = образ latest)
|
||||
план apply-plan.csv bc20f2a49e364ecd5ed57d9fc97bfbcb (Mac = NAS)
|
||||
```
|
||||
|
||||
**Сухой прогон по актуальному плану (7651 файл):**
|
||||
```
|
||||
строк в плане: 7861
|
||||
changed=yes требующих правки, но помеченных no: 0 ✅
|
||||
changed=no без расхождений, но помеченных yes: 0 ✅
|
||||
mp3 на диске: 7861 пропущено не-mp3: 561
|
||||
пропущено changed=no: 210
|
||||
не найдено на диске: 0
|
||||
к обработке: 7651
|
||||
exit=0
|
||||
```
|
||||
|
||||
> 🔑 **Инвариант `_check_changed_consistency()` пройден:** оба счётчика расхождений `= 0`.
|
||||
> Перед этим было `7648 к обработке`; стало **7651** (+3 = файлы `Green Apelsin`, см. ниже).
|
||||
|
||||
### 🔴 ДЕФЕКТ ПРАВКИ ПЛАНА: `changed` не пересчитывался после смены `new_album`
|
||||
|
||||
**Класс дефекта:** правка `new_album` в плане **не обновляет** колонку `changed`.
|
||||
Если у файла до правки `cur_album == new_album` (флаг `no` стоял корректно), после правки
|
||||
значения расходятся — **а флаг остаётся `no`. Скрипт такой файл ПРОПУСТИТ.**
|
||||
|
||||
Найдено **3 файла** (все `Green Apelsin`) — правка `album` → `Северный ветер` не применилась бы:
|
||||
```
|
||||
!Pop, Club, Любэ/Green Apelsin/В пасти смерти.mp3 'В пасти смерти' -> 'Северный ветер' changed=no ❌
|
||||
!Pop, Club, Любэ/Green Apelsin/Кукловод.mp3 'Сердце не бьётся'-> 'Северный ветер' changed=no ❌
|
||||
!Pop, Club, Любэ/Green Apelsin/Лес.mp3 'Лес' -> 'Северный ветер' changed=no ❌
|
||||
```
|
||||
Плюс встречный: 1 файл `changed=yes` **без** расхождений —
|
||||
`The Prodigy/The Prodigy - Girls (Rex The Dog Remix).mp3` (лишний флаг, известен с сессии 17).
|
||||
|
||||
**Фикс** (`/tmp/recalc_changed.py`): `changed = "yes" if любой cur_* != new_* else "no"`, по всем 7861.
|
||||
|
||||
```
|
||||
ДО: yes 7649 · no 212
|
||||
ПОСЛЕ: yes 7651 · no 210 переключено 4
|
||||
КОНТРОЛЬ: расхождений changed осталось 0
|
||||
```
|
||||
Бэкап: `APPLY-PLAN.csv.bak-before-changed-recalc-20260927-174900`.
|
||||
|
||||
> 🔴 **ПРАВИЛО ПАЙПЛАЙНА: любая правка `new_*` в плане ОБЯЗАНА пересчитывать `changed`.
|
||||
> Скрипт-писатель читает флаг, а не сравнивает значения сам.**
|
||||
|
||||
### 🔴 ГЛАВНЫЙ ПИТФОЛЛ: `Dockerfile.v2` на Mac — УСТАРЕВШАЯ СПРАВОЧНАЯ КОПИЯ
|
||||
|
||||
В нём **нет** `ENTRYPOINT` и `USER 950:950`, хотя дока описывает их как фиксы.
|
||||
Боевой образ `tagwriter:latest` собран **с** фиксами (проверено `docker inspect` + `id`).
|
||||
**Не пересобирать из этого файла — потеряешь фиксы.**
|
||||
|
||||
### 🔴 ПИТФОЛЛ: `tagwriter:v2` — старая версия, НЕ ИСПОЛЬЗОВАТЬ
|
||||
|
||||
`tagwriter:v2` = `e5e2437a2fda90cb6b06d6daa6330cb` (скрипт старый).
|
||||
`tagwriter:latest` = `c7a2bc14…` ✅. Оба образа сосуществуют — легко промахнуться.
|
||||
|
||||
---
|
||||
|
||||
## 🔴 СЕССИЯ 17: АУДИТ APPLY-СКРИПТА ПЕРЕД БОЕВЫМ ПРОГОНОМ
|
||||
|
||||
> Alex: «**Проверяй ещё раз руками apply script. Скажи алгоритм которым он будет применять
|
||||
> правки и найди если есть какие-то проблемы.**»
|
||||
@@ -610,18 +717,20 @@ Alex: «**Отлично, применяй**» → прогон **не запу
|
||||
**Шаг 2 (не выполнен, ждёт Alex):** `docker cp` скрипта + заливка актуального плана → MD5-сверка →
|
||||
`--dry-run` → `--apply --verify` только после «go».
|
||||
|
||||
### 🔴 ОТКРЫТЫЙ ДЕФЕКТ (требует проверки): `!Rock&Folk/Rammstein/misc`
|
||||
### 📜 ИСТОРИЧЕСКАЯ ЗАПИСЬ (НЕДЕЙСТВИТЕЛЬНА — см. §ЗАКРЫТО выше)
|
||||
|
||||
Alex: «**`!Rock&Folk/Rammstein/misc` - album - rammstein - неправильно**».
|
||||
|
||||
```
|
||||
ПАПКА album '' -> Rammstein ← ❌ имя АРТИСТА в поле альбома (3 файла с пустым cur_album)
|
||||
ПАПКА albumartist <КОЛОНКИ НЕ БЫЛО> -> Puhdys ← ❌ чужая группа на всю папку Rammstein
|
||||
```
|
||||
Папка: 18 файлов. Остальные альбомы корректны: `The remix album 2002` (7), `Singles '99` (4),
|
||||
`Live Aus Russland`, `Wilder Freiden`, `Demo`, `Golden Collection 2001`.
|
||||
Файлы с пустым `cur_album`: `Pet Sematary.mp3`, `Песня о тревожной молодости.mp3` + 1.
|
||||
⏳ Решение не получено.
|
||||
> ~~### 🔴 ОТКРЫТЫЙ ДЕФЕКТ: `!Rock&Folk/Rammstein/misc`~~
|
||||
>
|
||||
> ~~Alex: «`!Rock&Folk/Rammstein/misc` - album - rammstein - неправильно».~~
|
||||
>
|
||||
> ```
|
||||
> ПАПКА album '' -> Rammstein ← ❌ имя АРТИСТА в поле альбома
|
||||
> ПАПКА albumartist <КОЛОНКИ НЕ БЫЛО> -> Puhdys ← ❌ чужая группа на всю папку
|
||||
> ```
|
||||
> ~~Папка: 18 файлов. Решение не получено.~~
|
||||
>
|
||||
> ✅ **ЗАКРЫТО в сессии 18:** факт по файлу — `album='misc'`, `albumartist='Rammstein'`.
|
||||
> Дефекта нет, запись была снимком ДО правок. Детали — §ЗАКРЫТО выше.
|
||||
|
||||
### 🔴 ПИТФОЛЛ: `grep` по ИМЕНИ ПАПКИ ≠ проверка ЗНАЧЕНИЯ
|
||||
|
||||
@@ -778,7 +887,7 @@ docker start -a tw && docker rm -f tw
|
||||
| 0d | `Филипок` / `Маленький_Мук` — `album='Сказочный сборник'` / транслит | ⏳ войдёт в 0c |
|
||||
| 0e | **12 строк `changed=yes` без реальных правок** — снять флаг? | ⏳ **вопрос сессии 17** |
|
||||
| 0f | **`track` с ведущим нулём** (`01`, `03/12`) — канонизировать в `1`/`3/12`? 11 файлов | ⏳ **вопрос сессии 17** |
|
||||
| 1 | Боевой `--apply --verify` по 7861 | 🔴 **ЖДЁТ «go»** (после 0, 0a–0f) |
|
||||
| 1 | Боевой `--apply --verify` по 7861 | 🔴 **ЖДЁТ шаг 2** (сверка артефактов пройдена, см. §СВЕРКА АРТЕФАКТОВ) |
|
||||
| 2 | Приёмка Alex в UI (Navidrome/Jellyfin) | ⏳ |
|
||||
| 3 | Откат 40 из `backup_conv40/` | ⏳ |
|
||||
| 4 | Удаление 29 битых/DRM ([[personal/tech/music-broken-toload]]) | ⏳ |
|
||||
|
||||
Reference in new issue
Block a user