diff --git a/family/how-to/navidrome-truenas-android.md b/family/how-to/navidrome-truenas-android.md index 7b532a86..dcb7fcb1 100755 --- a/family/how-to/navidrome-truenas-android.md +++ b/family/how-to/navidrome-truenas-android.md @@ -1,9 +1,10 @@ # Музыкальный плеер с TrueNAS на Android -**Статус:** ✅ **РАЗВЁРНУТ 2026-09-27** — Navidrome на TrueNAS, работает, скан завершён (8043 трека). -🔴 **2026-09-27 (сессия 22):** теги 306 исправлены ✅, но **rescan НЕ помог** — в БД остались **14 сирот** `album` в скобках. `restart` и **пересоздание контейнера** дают `fullScan=false`, теги не перечитываются. Следующий шаг: **`touch` 306 файлов** (mtime) → полный скан. +**Статус:** ✅ **РАЗВЁРНУТ 2026-09-27** — Navidrome на TrueNAS, работает. +✅ **2026-09-27 (сессия 22):** теги 306 исправлены, **БД Navidrome снесена и построена заново**, скобочных сирот **0**, треков **8167**. +🔴 **Ни `restart`, ни пересоздание контейнера НЕ дают полного скана** (`fullScan=false`) — теги не перечитываются. Рабочий способ: **снести `navidrome.db`** (тогда старт → `fullScan=true`). **Дата:** 2026-05-10 -**Обновлено:** 2026-09-27 (v6 — rescan не помог, 14 сирот, путь через mtime) +**Обновлено:** 2026-09-27 (v7 — БД пересоздана, 0 сирот, треков 8167) --- @@ -321,23 +322,17 @@ folder="!Pop, Club, Любэ/Дискотека Авария/Москва пьё **Артефакт для просмотра (запрошен у Alex, ещё не выгружен):** CSV `путь + текущий album + title` по **306** файлам со «скобочным» album, топ-20 для глазной вычитки. -## 🔴 АКТИВНО (2026-09-27, сессия 22): RESCAN НЕ ПОМОГ — 14 СИРОТ ОСТАЛИСЬ +## ✅ РЕШЕНО (2026-09-27, сессия 22): СНОС БД → ПОЛНЫЙ СКАН → 0 СИРОТ -> **Alex: «Navidrome rescan теперь надо»** → затем **«Просто контейнер пересоздай»** +> **Alex: «Navidrome rescan теперь надо»** → **«Просто контейнер пересоздай»** → **«Сука базу блядь снеси руками!!!»** -**Факт: теги на диске исправлены, но БД Navidrome содержит И СТАРЫЕ, И НОВЫЕ альбомы.** +**Проблема:** теги на диске исправлены, но БД Navidrome содержала И СТАРЫЕ, И НОВЫЕ альбомы — **14 сирот**. ```bash DB=/mnt/RED_2TB/docker/navidrome/data/navidrome.db -sqlite3 "file:$DB?mode=ro" "SELECT COUNT(*) FROM album WHERE name LIKE '(%';" # → 14 (до и после) +sqlite3 "file:$DB?mode=ro" "SELECT COUNT(*) FROM album WHERE name LIKE '(%';" # → 14 (до и после попыток rescan) ``` -| Что | Значение | -|---|---| -| альбомов в БД | 967 | -| `album` целиком в скобках | **14** ← не вычищены (число НЕ изменилось от rescan) | -| новые значения (`Философские`, `Морские`, `Москва пьёт пиво`, `Старые хиты`, `Дискотека Авария`, `Retro`, `Владимир Высоцкий`, `Несчастный Случай`, `zvezda`) | ✅ присутствуют | - ### ❌ ЧТО ПРОБОВАЛОСЬ И НЕ ПОМОГЛО (факт) | # | Способ | Результат | @@ -354,27 +349,47 @@ sqlite3 "file:$DB?mode=ro" "SELECT COUNT(*) FROM album WHERE name LIKE '(%';" (скан их не помечает missing). Причина: album = пара `(name, album_artist)`; теги сменились → Navidrome **создал новые** альбомы, **старые не удалил** (быстрый скан файлы не перечитывает). -### 🔑 СЛЕДУЮЩИЙ ШАГ (не сделан): перечитать `mtime` файлов → полный скан +### ✅ СНОС БД — РАБОЧИЙ СПОСОБ (выполнен) -Единственный надёжный путь без пароля: **`touch` 306 файлов** (меняет только `mtime`, содержимое -и аудио не трогает) → Navidrome увидит «изменённые» файлы → перечитает теги → сироты уйдут. -Либо через UI Navidrome: `Скан` с галкой **«Full scan»** (пароль `navi_admin` неизвестен — -спрашивать у Alex, не выдумывать; `curl /rest/ping` → `code 40 Wrong username or password`). +```bash +D=/mnt/RED_2TB/docker/navidrome/data +mkdir -p "$D/navidrome.db.bak-$(date +%Y%m%d-%H%M%S)" # копия ПЕРЕД сносом (обязательно) +cp "$D"/navidrome.db* "$D/navidrome.db.bak-"/ +cd /mnt/RED_2TB/docker/navidrome && docker compose stop +rm -v "$D/navidrome.db" "$D/navidrome.db-shm" "$D/navidrome.db-wal" +docker compose up -d # старт → Full scan required after migration +``` -**Проверка после:** тот же запрос `LIKE '(%'` → должно стать **0**, в UI не должно быть дублей -«альбом со скобками» + «альбом без скобок». +**Лог на старте:** `Full scan required after migration` → `Scanner: Starting scan fullScan=true` ✅ -> 🔴 **ПИТФОЛЛ (важно на будущее): `docker restart` и `docker compose down/up` для Navidrome -> НЕ вызывают полный скан.** В логе всегда `fullScan=false`. Navidrome читает только новые/изменённые -> файлы. Для принудительного перечитывания тегов нужно менять `mtime` файлов или использовать -> UI-скан с `Full scan`. Полный скан на старте — `ND_SCANONSTARTUP` + `ND_SCANONSTARTUP` force -> (**не проверено**, в ENV отсутствует; проверять, если `touch` не поможет). +**Результат (факт по `sqlite3`):** + +| Метрика | До сноса | После | +|---|---:|---:| +| `album` целиком в скобках | **14** | **0** ✅ | +| треков (`media_file`) | 7861 | **8167** | +| альбомов (`album`) | 967 | **837** | + +Все целевые значения присутствуют по одному разу: `Философские` · `Морские` · `Блатные` · +`Спортивные` · `Из Сказок` · `Разное` · `Москва пьёт пиво` · `Старые хиты` · `Дискотека Авария`(2) · +`Красивые, богатые` · `Retro` · `Вилли Токарев` · `Владимир Высоцкий` · `Несчастный Случай` · `zvezda`. + +**Проверка после:** `sqlite3 "file:$DB?mode=ro" "SELECT COUNT(*) FROM album WHERE name LIKE '(%';"` → **0**. + +⚠️ **Что теряется при сносе БД:** плейлисты, избранное, счётчики проигрываний, оценки, пользователи +Navidrome (пароль задаётся заново в UI). **Что НЕ теряется:** музыка и теги — они на диске. +**Бэкап `navidrome.db.bak-/` обязателен** — единственный путь к откату метаданных Navidrome. + +> 🔴 **ПИТФОЛЛ (главный, метод): НИ `docker restart`, НИ `docker compose down/up` не дают полного +> скана Navidrome** — в логе всегда `fullScan=false` (`duration≈3s`). Массовая смена тегов без смены +> `mtime` не подхватывается: Navidrome **добавляет** новые альбомы и **не удаляет** старые → дубли +> «скобочный + чистый». `ND_SCANSCHEDULE=1h` тоже не помогает. **Единственный проверенный способ — +> снести `navidrome.db`** (старт форсирует `fullScan=true`). Альтернатива без сноса — `touch` файлов +> (меняет `mtime`, не содержимое) + полный скан; в этой сессии не применялась. > 🔴 **ВАЖНО на будущее: `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`). +> не нужно `docker exec`. Быстрее и не требует запуска контейнера. В контейнере `tagwriter:v2` +> `sqlite3` **нет** (только `mutagen`). Боевой прогон и приёмка — [[personal/plans/tagwriter-container]] §СЕССИЯ 21. diff --git a/personal/plans/music-artist-albumartist-repair.md b/personal/plans/music-artist-albumartist-repair.md index 390c2a3b..524f8bcb 100755 --- a/personal/plans/music-artist-albumartist-repair.md +++ b/personal/plans/music-artist-albumartist-repair.md @@ -4,7 +4,7 @@ created: '2026-09-27' updated: '2026-09-27' type: plan namespace: personal -status: session20-dry-run-306-verified-awaiting-apply-go +status: session20-APPLY-306-done-nav.md-REBUILT tags: - music - metadata @@ -363,6 +363,89 @@ Alex: «**это 4359 правки?**» про таблицу из 16 пар. ** > 🔴 Ловушка: `/mnt/RED_2TB/Music` **пуста** — первый прогон смонтировал её и дал `к правке: 0`. > Подробности и два питфолла — `[[personal/plans/tagwriter-container]]` §СЕССИЯ 20. +### ✅ БОЕВОЙ ПРОГОН 306 — ВЫПОЛНЕН И ПРИНЯТ ПО ДИСКУ (сессия 20, вечер) + +Alex: «**Гони боевой**» → «**Navidrome rescan теперь надо**» → «**Просто контейнер пересоздай**» +→ «**Сука базу блядь снеси руками!!!**» + +| Шаг | Факт | +|---|---| +| Бэкап ДО правки | `/mnt/RED_2TB/storage/Music/backup_before_306/20260927-051727` — **306 файлов + `_MANIFEST.tsv`** (md5 каждого до/после копии, расхождений 0). Скрипт `/tmp/backup_306.py` | +| План на NAS | `/tmp/tw306/apply-plan.csv`, md5 `8bfa52389a80119e713b88d05a91b9ef` = локальному ✅ | +| **APPLY** | ✅ **306/306, ошибок 0** | +| Изменения по полям | `TALB` 306 · `TPE2` 306 · `TCON` 264 · `TIT2`/`TPE1`/`TRCK` **0** (не тронуты) | +| **READ-BACK с диска** (не отчёт скрипта) | ✅ проверено 306 · **совпало 306** · расхождений **0** · **album в скобках — 0** · файлов < 100 КБ — **0** (аудио целое). Скрипт `/tmp/verify_306c.py` (пути внутри контейнера: `/app/data`, `/music`) | + +> 🔴 **МЕТОД-УРОК (приёмка):** `--apply` печатает «306/306, 0 ошибок» — это **не приёмка** +> (ср. W2: «40/40 записано» при уничтоженном аудио). Приёмка = **перечитать теги с диска** +> своим скриптом и проверить ЗНАЧЕНИЕ + размер файла. Здесь это дало `совпало 306 / расхождений 0`. + +### 🔴 NAVIDROME: СКАН НЕ ПЕРЕЧИТЫВАЕТ ТЕГИ — ЛЕЧИТСЯ ТОЛЬКО СНОСОМ БД + +Хронология (каждый шаг **проверен запросом к БД**, а не на словах): + +| Действие | Результат | +|---|---| +| `docker restart navidrome` | `fullScan=false`, `Scan completed` за 3 с → **в БД те же 14 альбомов со скобками** | +| `docker compose down && up -d` (пересоздание) | снова `fullScan=false` → **те же 14**. БД лежит на диске (том `/data`), пересоздание контейнера её не трогает | +| ✅ **Снос БД руками** | бэкап `data/navidrome.db.bak-20260927-053238/` → `rm navidrome.db{,-shm,-wal}` → старт → `Full scan required after migration`, **`fullScan=true`** | + +**Финал (факт по `sqlite3`):** + +``` +БЫЛО: album со скобками 14 | треков 7861 +СТАЛО: album со скобками 0 | альбомов 837 | треков 8167 +``` + +Целевые значения в БД: `Философские` 1 · `Морские` 1 · `Блатные` 1 · `Спортивные` 1 · +`Из Сказок` 1 · `Разное` 1 · `Москва пьёт пиво` 1 · `Старые хиты` 1 · `Дискотека Авария` 2 · +`Красивые, богатые` 1 · `Retro` 1 · `Вилли Токарев` 1 · `Володимир Высоцкий`→`Владимир Высоцкий` 1 · +`Несчастный Случай` 1 · `zvezda` 1. **Скобочных дублей — 0.** + +> 🔴 **МЕТОД-УРОК (Navidrome):** обычный скан (`fullScan=false`) сверяет **`mtime`/путь**, а не теги. +> Массовая правка тегов **не видна** быстрому скану: Navidrome добавляет **новые** альбомы, +> старые **не удаляет** → дубли «скобочный + чистый». Рестарт и пересоздание контейнера +> **не помогают** (`ND_SCANSCHEDULE=1h` тоже). Рабочий способ — **снести `navidrome.db`**, +> тогда старт даёт `fullScan=true` и база строится заново. Перед сносом — копия `navidrome.db*`. +> **Теряется:** плейлисты/избранное/счётчики Navidrome. **Не теряется:** музыка и теги (на диске). +> Проверочные запросы: `sqlite3 "file:.../navidrome.db?mode=ro" "SELECT COUNT(*) FROM album WHERE name LIKE \"(%\";"`. + +### 🗄 ИНФРАСТРУКТУРА (уточнения сессии 20) + +| Факт | Значение | +|---|---| +| **Библиотека музыки на NAS** | **`/mnt/RED_2TB/storage/Music`** (100 ГБ, 15 929 mp3). `/mnt/RED_2TB/Music` — **пустая обманка** | +| Карта путей | план хранит `/storage/Music/...`; в контейнере это `/music`; на хосте `/mnt/RED_2TB/storage/Music` | +| Navidrome | контейнер `navidrome`, образ `deluan/navidrome:latest` (0.64.2), порт 4533, `ND_SCANSCHEDULE=1h` | +| Compose Navidrome | `/mnt/RED_2TB/docker/navidrome/docker-compose.yml` (бэкап `.bak-20260927-052857`), том `/mnt/RED_2TB/storage/Music:/music:rw` | +| `tagwriter:v2` | `CSV_IN = "/app/data/apply-plan.csv"` — путь **зашит константой**, CLI-флага для плана нет. Свой план подкладывать под этим именем в отдельную папку | +| Вариант запуска без approval | `docker run --rm -v …:/app/data:ro -v …/Music:/music:rw tagwriter:v2 --dry-run` | +| `/mnt/RED_2TB/IRONWOLF` | пустой второй пул (не библиотека) | + +### ❓ ОТКРЫТЫЙ ВОПРОС ALEX (сессия 20, конец) + +Alex про песни из `!Детские` — «**А нам все равно, если б я был султан, платы паровоз — какой +albumartist и album? Они же в песнях для детей лежат? Почему они не в одном альбоме для детей +оказались?**» + +**Факт:** этих песен в `!Детские` **нет**. Все три — в **`!Retro/Юрий Никулин`** (3 файла): + +``` +!Retro/Юрий Никулин/Если бы я был султан.mp3 +!Retro/Юрий Никулин/Постой паровоз.mp3 +!Retro/Юрий Никулин/А нам все равно.mp3 + folder = !Retro/Юрий Никулин class = АЛЬБОМ + album = Песни albumartist = Юрий Никулин artist = Юрий Никулин +``` + +Причина: правило **D21** (файл в папке артиста = один альбом) смотрит только на **путь** и не +учитывает, что песня «детская». `!Детские` (570 файлов) содержит свои альбомы +(`Сборка Песни для детей` 165 · `Детский Хит Сезона` 156), эти три — не там. + +**«Храбрый зайчик»** — поиск по плану и по диску (`*зайчик*`, `*заяц*`, `*храбр*`) дал **0**. +Найденные «зайчики» — другие песни (`Мартовский заяц`, `Хор мальчиков-зайчиков`, `Солнечный зайчик` ×2). +⏭ Ждём от Alex точное имя/исполнителя. + --- ## 🟣 СЕССИЯ 18 (2026-09-27) — NAVIDROME РАЗВЁРНУТ, ДЕФЕКТ-КЛАСС ВСКРЫТ, ПРАВИЛА ВОССТАНОВЛЕНЫ ИЗ ZULIP, 306 СТРОК ИСПРАВЛЕНЫ, НОВЫЙ ДИФФ ГОТОВ diff --git a/personal/plans/tagwriter-container.md b/personal/plans/tagwriter-container.md index 59000b62..90519704 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: session22-apply-306-done-navidrome-rescan-failed-14-orphans +status: session22-apply-306-done-navidrome-db-rebuilt-0-orphans tags: - music - truenas @@ -118,15 +118,52 @@ sqlite3 "file:$DB?mode=ro" "SELECT COUNT(*) FROM album WHERE name LIKE '(%';" Compose не менялся (бэкап `docker-compose.yml.bak-20260927-052857`), данные/музыка целы. ⚠️ Сироты: `updated_at` 10:09–10:23 UTC, `missing=0` — скан их живыми считает. -**🔑 СЛЕДУЮЩИЙ ШАГ (не сделан): `touch` 306 файлов → полный скан.** `touch` меняет только `mtime`, -содержимое/аудио не трогает; Navidrome увидит «изменённые» файлы и перечитает теги. Альтернатива — -UI-скан с галкой **Full scan** (пароль `navi_admin` неизвестен — **не выдумывать**, -`curl …/rest/ping` → `code 40 Wrong username or password`). +🔑 **РЕШЕНИЕ НАЙДЕНО (Alex): «Сука базу блядь снеси руками!!!» → снос `navidrome.db`.** -Проверка результата — тот же запрос: `LIKE '(%'` должно стать **0**. +| # | Способ | Результат | +|---|---|---| +| 1 | `docker restart navidrome` | ❌ `fullScan=false` → те же **14** | +| 2 | `docker compose down` + `up -d` | ❌ `fullScan=false`, `duration=3.12s` → снова **14** | +| 3 | ✅ **снести `navidrome.db*` → старт** | ✅ `Full scan required after migration`, **`fullScan=true`** → **скобок 0** | -🔴 **ПИТФОЛЛ: `docker restart` и `docker compose down/up` для Navidrome НЕ дают полного скана** — -в логе всегда `fullScan=false`. Смена тегов без смены `mtime` не подхватывается. +**Порядок (выполнен и подтверждён):** + +```bash +D=/mnt/RED_2TB/docker/navidrome/data +mkdir -p "$D/navidrome.db.bak-$(date +%Y%m%d-%H%M%S)" # копия ПЕРЕД сносом +cp "$D"/navidrome.db* "$D/navidrome.db.bak-"/ +cd /mnt/RED_2TB/docker/navidrome && docker compose stop +rm -v "$D/navidrome.db" "$D/navidrome.db-shm" "$D/navidrome.db-wal" +docker compose up -d # построит БД заново +``` + +**Результат (факт по `sqlite3`):** + +| Метрика | До сноса | После | +|---|---:|---:| +| `album` со скобками | 14 | **0** | +| треков (`media_file`) | 7861 | **8167** | +| альбомов (`album`) | 967 | **837** | + +Все целевые значения присутствуют по одному разу: `Философские` · `Морские` · `Блатные` · +`Спортивные` · `Из Сказок` · `Разное` · `Москва пьёт пиво` · `Старые хиты` · `Дискотека Авария`(2) · +`Красивые, богатые` · `Retro` · `Вилли Токарев` · `Владимир Высоцкий` · `Несчастный Случай` · `zvezda`. + +⚠️ **Что теряется при сносе БД:** плейлисты, избранное, счётчики проигрываний, оценки, пользователи +Navidrome (пароль задаётся заново в UI). **Что НЕ теряется:** музыка и теги — они на диске. +Поэтому бэкап `navidrome.db.bak-/` обязателен — единственный путь к откату метаданных Navidrome. + +**Проверка после:** `sqlite3 "file:$DB?mode=ro" "SELECT COUNT(*) FROM album WHERE name LIKE '(%';"` → **0**. + +⚠️ Сироты: `updated_at` 10:09–10:23 UTC, `missing=0` — скан их живыми считает. + +🔴 **ПИТФОЛЛ (главный, метод): НИ `docker restart`, НИ `docker compose down/up` не дают полного +скана Navidrome — в логе всегда `fullScan=false`.** Массовая смена тегов без смены `mtime` не +подхватывается: Navidrome **добавляет** новые альбомы и **не удаляет** старые → дубли +«скобочный + чистый». `ND_SCANSCHEDULE=1h` тоже не помогает. **Единственный рабочий способ — +снести `navidrome.db`** (тогда старт форсирует `fullScan=true`). Альтернатива без сноса — +`touch` 306 файлов (меняет `mtime`, не содержимое) + полный скан; в этой сессии не применялась, +сработал снос БД. 🔴 **Питфолл-нюанс:** Navidrome при скане **пересчитывает album из тегов**, поэтому у 306 файлов кроме `TALB` сменился и `TPE2` — в БД это **новые** записи альбомов, а не апдейт старых.