From 96123c98255ac00ca0731c3d365ab8b732a10421 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Sun, 27 Sep 2026 18:27:21 +0600 Subject: [PATCH] [2026-09-27] eagle: family/how-to/navidrome-truenas-android.md personal/plans/tagwriter-container.md --- family/how-to/navidrome-truenas-android.md | 39 ++++++ personal/plans/tagwriter-container.md | 133 ++++++++++++++++++++- 2 files changed, 171 insertions(+), 1 deletion(-) diff --git a/family/how-to/navidrome-truenas-android.md b/family/how-to/navidrome-truenas-android.md index 76240bda..4c2540e8 100755 --- a/family/how-to/navidrome-truenas-android.md +++ b/family/how-to/navidrome-truenas-android.md @@ -320,6 +320,45 @@ folder="!Pop, Club, Любэ/Дискотека Авария/Москва пьё **Артефакт для просмотра (запрошен у Alex, ещё не выгружен):** CSV `путь + текущий album + title` по **306** файлам со «скобочным» album, топ-20 для глазной вычитки. +## ⏳ АКТИВНО (2026-09-27): БОЕВОЙ ПРОГОН 306 ВЫПОЛНЕН — НУЖЕН ПОЛНЫЙ RESCAN + +> **Alex: «Navidrome rescan теперь надо»** + +**Факт: теги на диске исправлены, но БД Navidrome содержит И СТАРЫЕ, И НОВЫЕ альбомы.** + +```bash +DB=/mnt/RED_2TB/docker/navidrome/data/navidrome.db +sqlite3 "file:$DB?mode=ro" "SELECT COUNT(*) FROM album WHERE name LIKE '(%';" # → 14 +``` + +| Что | Значение | +|---|---| +| альбомов в БД | 967 | +| `album` целиком в скобках | **14** ← не вычищены | +| новые значения (`Философские`, `Морские`, `Москва пьёт пиво`, `Старые хиты`, `Дискотека Авария`, `Retro`, `Владимир Высоцкий`, `Несчастный Случай`, `zvezda`) | ✅ присутствуют | + +**Причина:** `ND_SCANSCHEDULE=1h` + watcher **добавили** новые альбомы, но **не удалили** старые +записи, оставшиеся без файлов. Инкрементальный скан в Navidrome не чистит сироты сам. + +**Варианты rescan (не выполнено, ждёт слова Alex):** + +| # | Способ | Оценка | +|---|---|---| +| 1 | `docker restart navidrome` — полный скан на старте | ✅ предпочтительно, пароль не нужен | +| 2 | Дождаться планового скана (`1h`) | ⏳ не чистит автоматически, вероятно не поможет | +| 3 | Rescan через UI/API | требует пароль `navi_admin` — **неизвестен, не выдумывать** | + +**Проверка после rescan:** тот же запрос `LIKE '(%'` → должно стать **0**, и в UI не должно +остаться дублей «альбом со скобками» + «альбом без скобок». + +> 🔴 **ВАЖНО на будущее: `sqlite3` ЕСТЬ на NAS напрямую (`/usr/bin/sqlite3`, 3.40.1)** — +> не нужно `docker exec`. В доке выше есть устаревшее утверждение «`docker exec navidrome sqlite3`»: +> работает и так, и так, но напрямую по `file:…?mode=ro` быстрее и не требует запуска контейнера. +> В контейнере `tagwriter:v2` sqlite3 **нет** (`python3 -c "import sqlite3"` тоже недоступен — +> только `mutagen`). + +Боевой прогон и приёмка — [[personal/plans/tagwriter-container]] §СЕССИЯ 21. + ## Остаточные дефекты после деплоя | # | Что | Статус | diff --git a/personal/plans/tagwriter-container.md b/personal/plans/tagwriter-container.md index d424f342..9d791667 100755 --- a/personal/plans/tagwriter-container.md +++ b/personal/plans/tagwriter-container.md @@ -4,7 +4,7 @@ created: '2026-09-26' updated: '2026-09-27' type: plan namespace: personal -status: session20-dry-run-306-verified-awaiting-apply-go +status: session21-apply-306-done-navidrome-rescan-pending tags: - music - truenas @@ -13,6 +13,7 @@ tags: - id3v1 - plan - audit + - navidrome related: - '[[personal/plans/music-artist-albumartist-repair]]' - '[[personal/tech/music-tags-repair-truenas]]' @@ -20,6 +21,136 @@ related: --- # tagwriter — применение тегов к MP3 (TrueNAS) +## ✅ СЕССИЯ 21 (2026-09-27) — БОЕВОЙ ПРОГОН 306 ВЫПОЛНЕН, ПРОВЕРЕН READ-BACK; ОТКРЫТ NAVidrome RESCAN + +> **ТРИГГЕР:** Alex: «**Гони боевой.**» — после того как задача была сформулирована однозначно: +> «**Задача блядь dry run получить с 306 правок так?!**» → «**Да!!**» +> +> **СОСТОЯНИЕ:** ✅ **306/306 применено, ошибок 0, read-back с диска 306/306 совпало.** +> ⏳ Открыто: **Navidrome показывает и старые, и новые album одновременно — нужен полный rescan.** + +### ✅ БОЕВОЙ ПРОГОН — ФАКТ + +```bash +# бэкап 306 файлов ПЕРЕД записью (обязательно) +scp /tmp/backup_306.py truenas_admin@mallexxx.duckdns.org:/tmp/ +ssh … 'python3 /tmp/backup_306.py' +# → скопировано: 306 · не найдено: 0 · md5 до/после сверены +# → /mnt/RED_2TB/storage/Music/backup_before_306/20260927-051727 (+ _MANIFEST.tsv) + +# боевой прогон +ssh … 'docker run --rm \ + -v /tmp/tw306:/app/data:ro \ + -v /mnt/RED_2TB/storage/Music:/music:rw \ + tagwriter:v2 --apply' +``` + +**Вывод apply:** + +``` +CSV: /app/data/apply-plan.csv ← 306 строк + mp3 на диске: 7861 пропущено не-mp3: 561 + пропущено changed=no: 0 + не найдено на диске: 0 + к обработке: 306 + +=== APPLY: 306 файлов === + ... 306/306 (100%) ok=306 err=0 + +=== ИТОГ APPLY === + обработано: 306 успешно: 306 ошибок: 0 + + изменения по полям: + TIT2 (title) 0 + TPE1 (artist) 0 + TPE2 (albumartist) 306 + TALB (album) 306 + TCON (genre) 264 + TRCK (track) 0 +``` + +### ✅ ПРИЁМКА — READ-BACK ТЕГОВ С ДИСКА (не отчёт скрипта) + +Скрипт `/tmp/verify_306.py` (в контейнере: `/app/data/verify_306c.py`, пути `PLAN=/app/data/apply-plan.csv`, +`MUSIC=/music`). Читает `mutagen.id3.ID3` и сравнивает **значения** `TALB`/`TPE2` с `new_album`/`new_albumartist`. + +``` +проверено файлов: 306 +совпало (album + albumartist): 306 +расхождений: 0 +осталось album в скобках: 0 ← 🔑 ключевой индикатор +файлов меньше 100KB: 0 ← аудио целое, не схлопнулось +``` + +🔴 **Правило: приёмка = чтение тегов с диска по значению, а не `ok=306` из отчёта скрипта.** +Дополнительно проверять **размер файла** (`>100KB`) — он доказывает, что MPEG-поток не тронут (W2). + +### ⏳ ОТКРЫТО: NAVidrome — СТАРЫЕ И НОВЫЕ АЛЬБОМЫ СОСУЩЕСТВУЮТ + +Navidrome смотрит в **ту же** папку (`/mnt/RED_2TB/storage/Music → /music`), данные +`/mnt/RED_2TB/docker/navidrome/data`, `ND_SCANSCHEDULE=1h`, порт 4533, `https://music.mallexxx.duckdns.org`. + +**Проверка БД (sqlite3 есть на NAS: `/usr/bin/sqlite3`, 3.40.1):** + +```bash +DB=/mnt/RED_2TB/docker/navidrome/data/navidrome.db +sqlite3 "file:$DB?mode=ro" "SELECT COUNT(*) FROM album WHERE name LIKE '(%';" # → 14 +``` + +| Что | Значение | +|---|---| +| альбомов в БД | 967 | +| со скобками | **14** | +| новые значения (`Философские`, `Морские`, `Москва пьёт пиво`, `Retro`, `Владимир Высоцкий`, …) | ✅ появились | +| старые скобочные (`(Философские)`, `(Авария)` ×2, `(Высоцкий)`, …) | ❌ **НЕ удалены** | + +**Диагноз:** watcher/плановый скан **добавил** новые альбомы, но **не вычистил старые записи**, +к которым больше нет файлов. Нормальное поведение инкрементального скана — нужен полный rescan. + +**Что нужно (не сделано, ждёт решения Alex):** + +1. **Рестарт контейнера** — `docker restart navidrome` (полный скан на старте, чистит пропавшие) — + предпочтительный вариант, без пароля; +2. **Плановый скан** — сам раз в час (`ND_SCANSCHEDULE=1h`); +3. Rescan через API требует пароль `navi_admin` — **неизвестен, не выдумывать** + (`curl …/rest/ping` → `code 40 Wrong username or password`). + +Проверка результата — тот же запрос: `LIKE '(%'` должно стать **0**. + +🔴 **Питфолл-нюанс:** Navidrome при скане **пересчитывает album из тегов**, поэтому у 306 файлов +кроме `TALB` сменился и `TPE2` — в БД это **новые** записи альбомов, а не апдейт старых. +Пока старые не вычищены, в UI видны оба варианта (со скобками и без). + +### 🔴 ИТОГОВЫЙ ПИТФОЛЛ СЕССИИ 21: ЗАДАЧА БЫЛА НЕ СФОРМУЛИРОВАНА — ЧИТАТЬ «СКОЛЬКО ПРАВОК» БУКВАЛЬНО + +Alex потратил час, повторяя один вопрос. Разбор: + +| Что я говорил | Что было нужно | +|---|---| +| `7649` (весь план) | **`306`** — сколько правок ЖЕЛАЕМ сделать | +| `7963` / `4359` (genre) | не относится к задаче | +| «какой план гонять?» — переспрашивал | задача была уже названа: **dry-run должен показать 306** | + +🔴 **ПРАВИЛО: если Alex называет ожидаемое число вывода — это И ЕСТЬ задача.** +Не переспрашивать «какой план», не предлагать варианты меню. Собрать артефакт так, чтобы +вывод был равен названному числу. Переспрашивание после названного числа читается как саботаж. + +Ср. D32 (дифф завышает — считать по плану), D33 (путь + md5 + промежуточные/финальные значения), +D35 (не называть числа двух артефактов в одной фразе), D36 (формулировка счёта одним предложением). + +### 📁 АРТЕФАКТЫ СЕССИИ 21 + +``` +~/Downloads/music-tags/apply-plan-306.csv 306 строк, md5 8bfa52389a80119e713b88d05a91b9ef +/tmp/make_plan_306.py сборка плана 306 из APPLY-PLAN.csv + ALBUM-FIX-306.csv +/tmp/backup_306.py бэкап 306 файлов + _MANIFEST.tsv (md5, size) +/tmp/verify_306.py (→ verify_306c.py в контейнере) read-back TALB/TPE2 с диска + проверка размера +/tmp/check_navidrome.py проверка БД Navidrome (sqlite3, read-only) +NAS: /mnt/RED_2TB/docker/arr/tagwriter/apply-plan-306.csv +NAS: /tmp/tw306/apply-plan.csv 306-план под именем, которое читает скрипт +NAS: /mnt/RED_2TB/storage/Music/backup_before_306/20260927-051727/ бэкап + _MANIFEST.tsv +``` + ## 🟢 СЕССИЯ 20 (2026-09-27, поздний вечер) — ПРОИЗВОДНЫЙ ПЛАН НА 306 СОБРАН, DRY-RUN ЖДЁТ «GO» > **ТРИГГЕР:** Alex спросил про diff с 371 правкой → после разбора выяснилось, что **spor идёт