[2026-09-27] eagle: family/how-to/navidrome-truenas-android.md personal/plans/music-artist-albumartist-repair.md personal/tech/music-tags-repair-truenas.md personal/tech/skill-truenas-administration.md
This commit is contained in:
1 parent
d77aec3548
commit
eac340006e
4 files changed
+342
-12
No files matched your search
@@ -4,7 +4,7 @@ created: '2026-09-27'
|
||||
updated: '2026-09-27'
|
||||
type: plan
|
||||
namespace: personal
|
||||
status: session29ter-APPLY-PLAN-=-RC-RC-verify-7861-rashozhdeniy-genre-7861-track-1699-pokrytie-polnoe-AWAITING-ALEX
|
||||
status: session29quater-ndignore-FIXED-live-music-7861-generator-FOUND-build_fix_plan2-NON_ARTIST-EXACT-MATCH-defect-AWAITING-ALEX
|
||||
tags:
|
||||
- music
|
||||
- metadata
|
||||
@@ -288,6 +288,149 @@ leaf='!Классика' artist='Фредерик Шопен' aa='Various
|
||||
|
||||
---
|
||||
|
||||
## 🔴 СЕССИЯ 29-КВАТЕР (2026-09-27) — ГЕНЕРАТОР ПЛАНА НАЙДЕН ЧЕРЕЗ ZULIP DB + `.ndignore` ИСПРАВЛЕН
|
||||
|
||||
> **ТРИГГЕР (последовательность):** «**ладно ок. то есть план с базой сходится так?**» →
|
||||
> «**и почему у нас альбомы (zvezda), (несчастный случай), (Авария) до сих пор в базе — мы же
|
||||
> правили блядь скобки в альбомах?!**» → «**бэкапы же исключены из базы? разве нет?**» →
|
||||
> «**ты блядь исключал из базы. ты туда блядь специальные ignore файлы блядь положил.
|
||||
> почему они блядь в базе**» → «**Пиздец блядь. Конечно дописывать блядь**» →
|
||||
> «**Теперь на основе скрипта который генерил apply список на 74xx записей, найди комяк который
|
||||
> не поймал зайчик песни для детей и Юрий Никулин "песни"**» → «**нет. иди в зулип базу и ищи
|
||||
> каким скриптом генерили APPLY-PLAN.csv**»
|
||||
|
||||
### 🔴 ПРОЦЕССНЫЙ ПРОВАЛ: 3 РАЗА ОТВЕТИЛ «НЕ ЗНАЮ» ВМЕСТО ПОХОДА НА NAS
|
||||
|
||||
Alex спросил «бэкапы же исключены из базы? разве нет?» — я ответил теорией (что бэкап лежит внутри
|
||||
дерева) и **не пошёл смотреть факт**. Затем «**ты блядь исключал из базы, ты туда ignore файлы
|
||||
клал — почему они в базе**» → снова «я не нашёл ignore-файл» (искал только в `~/Downloads` и `/tmp`,
|
||||
**на NAS не смотрел**). Затем «**В смысле БЛЯДЬ не знаю?! Файлы блядь там или нет?!**» →
|
||||
только тогда `ssh ... ls .ndignore`.
|
||||
|
||||
**🔑 ПРАВИЛО: «почему X до сих пор в базе/на NAS» = вопрос о ФАКТЕ.**
|
||||
Первый tool-call — `ssh` на NAS, а не рассуждение. `grep` по локальным папкам НЕ заменяет
|
||||
проверку боевого хоста. Промедление прочитано как «серишь».
|
||||
(Повторение урока скилла `zulip-db-forensics`: «live diagnostics first, history for context second».)
|
||||
|
||||
### ✅ `.ndignore` — ФАКТ И ФИКС (детали → [[family/how-to/navidrome-truenas-android]])
|
||||
|
||||
Файл **существовал**, но содержал только **4 строки** из **6** существующих бэкап-папок.
|
||||
Причина: `.ndignore` создан **03:49**, `backup_before_306` — **05:17**,
|
||||
`backup_album_root_20260927-album-root-229` — **06:19**. Файл не обновляли после новых бэкапов.
|
||||
|
||||
Фикс: бэкап файла → собрать полный список ЛОКАЛЬНО → `scp` → `cp` на место → `docker restart navidrome`.
|
||||
|
||||
| Метрика | До | После |
|
||||
|---|---:|---:|
|
||||
| `media_file` всего | 8167 | **8396** |
|
||||
| `missing=1` (игнор) | — | **535** |
|
||||
| **живая музыка** | 7861 | **7861** ✅ |
|
||||
|
||||
### 🔴🔴 ГЛАВНЫЙ МЕТОД-ПИТФОЛЛ СЕССИИ: ЗАПРОС К БД БЕЗ ФИЛЬТРА БЭКАПА
|
||||
|
||||
**Я выдал бэкап за живое дерево и отчитался «скобки НЕ исправлены».** Запрос
|
||||
`SELECT DISTINCT album FROM media_file WHERE album LIKE '(%'` **без фильтра** вытащил 306 файлов
|
||||
из `backup_before_306/20260927-051727/`, где старые скобочные значения и лежат.
|
||||
|
||||
**В живом дереве `(zvezda)`, `(Авария)`, `(Несчастный Случай)` ОТСУТСТВУЮТ — правка отработала.**
|
||||
Факт после фикса: скобок-обёрток **0**.
|
||||
|
||||
```
|
||||
ОБЯЗАТЕЛЬНЫЙ ФИЛЬТР: WHERE missing=0 AND path NOT LIKE 'backup%'
|
||||
```
|
||||
|
||||
**Два класса скобок (не смешивать):** обёртка вокруг всего названия (`(Авария)`, `(zvezda)`) —
|
||||
правится; скобка в КОНЦЕ как уточнение (`Бумер (2003)`, `Муза (EP)`, `Outcasts (DEMOS)`) —
|
||||
часть названия, НЕ правится (осталось 17 таких значений).
|
||||
|
||||
### ✅ РАЗБОР ВОПРОСА «ПОЧЕМУ НЕТ УЧЁТА ТРЕКОВ»: покрытие план↔БД ПОЛНОЕ
|
||||
|
||||
«**то есть план с базой сходится так?**» — **по путям ДА, по тегам НЕТ.**
|
||||
`/tmp/gap_db_plan.py` (двусторонний): БД без backup **7861**, план **7861**, уникальных путей **7861**,
|
||||
`ЕСТЬ В БД, НЕТ В ПЛАНЕ` = **0**, `ЕСТЬ В ПЛАНЕ, НЕТ В БД` = **0**.
|
||||
Но `RC-VERIFY.csv`: **0 файлов** совпали по всем 6 полям — по тегам расходятся все 7861 (детали § СЕССИЯ 29-ТЕР).
|
||||
|
||||
### 🔑 ГЕНЕРАТОР ПЛАНА НАЙДЕН — ТОЛЬКО ЧЕРЕЗ ZULIP DB
|
||||
|
||||
Локальный `grep -l "APPLY-PLAN" *.py` дал **63 файла-потребителя**, но **ни одного генератора**
|
||||
(все — правки/аудиты поверх готового плана). Zulip DB показал цепочку:
|
||||
|
||||
```
|
||||
tag_inventory2.py → tag-inventory3.csv (7861 строк — съём тегов с диска)
|
||||
build_fix_plan2.py → APPLY-PLAN-FINAL.csv (7861 строк — план правок)
|
||||
→ APPLY-PLAN.csv (боевой канон)
|
||||
```
|
||||
|
||||
**Путь: `~/Developer/personal-os/tools/music-tags/build_fix_plan2.py`** (29690 байт).
|
||||
Вызов: `python3 build_fix_plan2.py INVENTORY.csv OUT.csv [HOST_ROOT]`.
|
||||
|
||||
> 🔑 **ПРАВИЛО: артефакт созданный давней сессией — искать в Zulip DB, а не только локально.**
|
||||
> Локальный файл-потребитель — не генератор. Скрипт-производитель назван в сообщении сессии создания.
|
||||
> Ключ поиска: `m.content ILIKE '%<имя_артефакта>%' AND m.content ILIKE '%write_file%'`.
|
||||
|
||||
### 🔴 КОРЕНЬ ДЕФЕКТА «мусор в `album`»: `NON_ARTIST` + ТОЧНОЕ СРАВНЕНИЕ
|
||||
|
||||
Вопрос Alex: **почему не пойманы `Храбрый Зайчик. Песни для детей` (Миансарова) и `Песни` (Никулин)?**
|
||||
|
||||
**Строки 692-697 `build_fix_plan2.py`:**
|
||||
```python
|
||||
if not new_al and d_album:
|
||||
new_al = d_album
|
||||
if new_al and norm(new_al) in NON_ARTIST and d_album:
|
||||
new_al = d_album # 🔴
|
||||
```
|
||||
|
||||
**Три причины (диагностика `/tmp/find_junk_miss.py`):**
|
||||
|
||||
| # | Причина | Факт |
|
||||
|---|---|---|
|
||||
| 1 | `NON_ARTIST` **не содержит** `песни` | в списке есть `сборник песен`, но не `песни` |
|
||||
| 2 | **ТОЧНОЕ сравнение всей строки** (`norm(new_al) in NON_ARTIST`), не поиск слова | `Храбрый Зайчик. Песни для детей` — фраза, в списке одиночные слова → мимо |
|
||||
| 3 | `norm()` = только `strip().lower()` — регистр значим | `песни` строчными ≠ `Песни` |
|
||||
|
||||
`Избранное` прошло **только потому, что буквально совпало** с элементом списка.
|
||||
|
||||
**Пропущено 44 файла в 5 значениях:**
|
||||
`Песни` **18** (Никулин 3, Руки вверх 2, Little Big …) · `Избранное` **16** (Пилот, Агата Кристи) ·
|
||||
`Супер ДискотЭка Радио Рекорд` **6** · `песни` **3** (Наутилус `2000 - песни`) ·
|
||||
`Храбрый Зайчик. Песни для детей` **1** (Миансарова).
|
||||
|
||||
**🔑 ДЕФЕКТ НЕ В КОРОТКОМ СПИСКЕ, А В ТОЧНОМ СРАВНЕНИИ.** Даже с `песни` в `NON_ARTIST`
|
||||
Миансарова всё равно прошла бы. Нужна **проверка по вхождению слова**, а не по равенству строки.
|
||||
|
||||
> 🔑 **Это 4-е повторение ОДНОГО метод-урока:** лишняя строгость ключа сравнения молча убивает детектор.
|
||||
> 1. Сессия 28: `leaf not in (artist, aa)` на равенство → потеряно 908 файлов.
|
||||
> 2. Сессия 29: `was` в ключе схлопывания → схлопывание не работало никогда.
|
||||
> 3. Сессия 29-бис: правило корня перебивало верный `album` из плана (`Sbornik_Novij_Rok`).
|
||||
> 4. Сессия 29-кватер: `norm(new_al) in NON_ARTIST` на точное равенство → 44 файла мусора.
|
||||
> **ВСЕГДА: `norm()` + вхождение. НИКОГДА: равенство.**
|
||||
|
||||
### 🛠 СКРИПТЫ ЭТОГО БЛОКА
|
||||
|
||||
```
|
||||
/tmp/find_junk_miss.py ⭐ находит значения, НЕ попавшие в хардкод NON_ARTIST (5 значений / 44 файла)
|
||||
/tmp/gap_db_plan.py ⭐ двусторонний gap план↔БД (0 / 0)
|
||||
/tmp/find_zaychik.py 🔍 поиск 'Храбрый зайчик' в плане
|
||||
/tmp/ndignore-new новый .ndignore (6 строк, 103 байта) — собран локально
|
||||
|
||||
~/Developer/personal-os/tools/music-tags/build_fix_plan2.py ⭐ ГЕНЕРАТОР ПЛАНА (29690 байт)
|
||||
~/Developer/personal-os/tools/music-tags/tag_inventory2.py источник инвентаря
|
||||
```
|
||||
|
||||
### ⏳ СТАТУС БЛОКА
|
||||
|
||||
✅ **Сделано:** `.ndignore` дополнен (боевая правка на NAS), скан, живая музыка **7861**;
|
||||
генератор найден, корень дефекта доказан по коду и данным.
|
||||
|
||||
🔴 **Открыто (3, все ждут решения Alex):**
|
||||
1. **Фикс `NON_ARTIST`** — править только album-детектор, или сразу все подобные
|
||||
(для `artist`/`albumartist`) по принципу вхождения?
|
||||
2. **Новый apply csv** + новый дифф по `new_*` — задача поставлена, **не выполнена**
|
||||
(ждёт ответа по п.1: генератор должен быть исправлен ДО генерации нового csv).
|
||||
3. **Дефект №5** из § СЕССИЯ 29-БИС (`nartist in nleaf` ловит `50 Cent` в `Eminem,50cent`).
|
||||
|
||||
---
|
||||
|
||||
## 🔴 СЕССИЯ 29-ТЕР (2026-09-27) — ПЕРЕОСМЫСЛЕНИЕ: `APPLY-PLAN.csv` = RC, СВЕРКА `new_*` vs БД
|
||||
|
||||
> **ТРИГГЕР:** «**стоп блядь. полный назад. возвращаемся блядь к исходной.**» →
|
||||
|
||||
@@ -75,6 +75,23 @@ related:
|
||||
> перечитала теги. Разбор — § СЕССИЯ 29-ТЕР.
|
||||
> ✅ **Покрытие план↔БД ПОЛНОЕ:** 7861 = 7861, `GAP-db-not-in-plan.csv` и
|
||||
> `GAP-plan-not-in-db.csv` **оба пусты** (`/tmp/gap_db_plan.py`).
|
||||
>
|
||||
> ✅ **СЕССИЯ 29-КВАТЕР — ДВА ГЛАВНЫХ РЕЗУЛЬТАТА:**
|
||||
> 1. 🔴 **`.ndignore` ИСПРАВЛЕН** — не хватало 2 бэкап-папок (`backup_before_306`,
|
||||
> `backup_album_root_…-229`, созданы ПОЗЖЕ файла). Живая музыка = **7861** = плану.
|
||||
> Детали → [[family/how-to/navidrome-truenas-android]].
|
||||
> 2. 🔑 **ГЕНЕРАТОР ПЛАНА НАЙДЕН** (только через **Zulip DB**):
|
||||
> `~/Developer/personal-os/tools/music-tags/build_fix_plan2.py`.
|
||||
> Корень дефекта «мусор в `album`»: `norm(new_al) in NON_ARTIST` — **точное сравнение всей
|
||||
> строки** + `NON_ARTIST` без слова `песни` → пропущено **44 файла** (Никулин `Песни` 18,
|
||||
> Миансарова `Храбрый Зайчик. Песни для детей` 1, `Избранное` 16, …).
|
||||
> Разбор — [[personal/plans/music-artist-albumartist-repair]] § СЕССИЯ 29-КВАТЕР.
|
||||
>
|
||||
> 🔴🔴 **ПИТФОЛЛ (метод, сессия 29-кватер): ЗАПРОС К `media_file` БЕЗ ФИЛЬТРА БЭКАПА.**
|
||||
> Запрос `album LIKE '(%'` без фильтра вытащил 306 файлов бэкапа → **ложный отчёт «скобки не
|
||||
> исправлены»**. В живом дереве скобок-обёрток **0**. **ОБЯЗАТЕЛЬНО:**
|
||||
> `WHERE missing=0 AND path NOT LIKE 'backup%'`.
|
||||
|
||||
> 🔑 **ПИТФОЛЛ: «Чёрный кот» пишется через Ё** — `grep "черный кот"` даёт 0 и создаёт
|
||||
> ложное «файла нет». Правило: искать и через `ё`, и через `е`, и без гласной.
|
||||
> 🔴 **Питфолл БД:** колонка — **`track_number`**, не `track`; возвращается **int**;
|
||||
|
||||
@@ -3,16 +3,19 @@ title: skill — truenas-administration
|
||||
namespace: personal
|
||||
type: tech
|
||||
created: '2026-09-26'
|
||||
updated: '2026-09-26'
|
||||
updated: '2026-09-27'
|
||||
tags:
|
||||
- truenas
|
||||
- skill
|
||||
- docker
|
||||
- acl
|
||||
- nfc
|
||||
- navidrome
|
||||
- ndignore
|
||||
related:
|
||||
- '[[personal/plans/tagwriter-container]]'
|
||||
- '[[personal/tech/music-tags-repair-truenas]]'
|
||||
- '[[family/how-to/navidrome-truenas-android]]'
|
||||
---
|
||||
|
||||
# Зеркало навыка `truenas-administration`
|
||||
@@ -20,7 +23,50 @@ related:
|
||||
Навык: `~/.hermes/hermes-whale/skills/devops/truenas-administration/SKILL.md`
|
||||
(umbrella: ACL/PUID, ZFS panic recovery, tree comparison, named-volumes→bind-mount).
|
||||
|
||||
Ниже — дельта, добавленная **2026-09-26** (сессия music-tags волна 38 + сборка `tagwriter`).
|
||||
Ниже — дельта. **2026-09-26:** волна 38 + сборка `tagwriter`. **2026-09-27:** добавился RULE 0
|
||||
(Area 3) про `.ndignore`.
|
||||
|
||||
## 0. 🔴 RULE 0 (2026-09-27): любой новый `backup*` → в `.ndignore` В ТОМ ЖЕ ПРОГОНЕ
|
||||
|
||||
Область: `/mnt/RED_2TB/storage/Music/` — корень библиотеки Navidrome (монтируется как `/music`).
|
||||
Navidrome игнорирует **только то, что перечислено в `.ndignore`**. Бэкап, которого там нет,
|
||||
**сканируется как обычная музыка** и пачкает КАЖДЫЙ запрос к БД: расхождения счётчиков,
|
||||
фантомные находки («альбом со скобками до сих пор в базе», хотя правка отработала),
|
||||
дифф, который выглядит сломанным, хотя он верный.
|
||||
|
||||
**Проверенный провал 2026-09-27:** `.ndignore` создан **03:49** и содержал 4 папки
|
||||
(`backup`, `backup_conv40`, `backup_fix`, `backup_raw`). Бэкапы, созданные **позже**, в файл
|
||||
не попали: `backup_before_306` (**05:17**), `backup_album_root_20260927-album-root-229` (**06:19**).
|
||||
Итог: БД **8167** против плана **7861**, разница **306** = неотфильтрованный бэкап.
|
||||
Альбомы `(zvezda)`, `(Авария)`, `(Несчастный Случай)` «остались в базе» — они существовали
|
||||
**только внутри бэкапа**.
|
||||
|
||||
**Фикс (боевой конфиг → порядок: бэкап ДО → правка → проверка → коммит ПОСЛЕ):**
|
||||
```bash
|
||||
# 1. бэкап файла
|
||||
ssh truenas_admin@mallexxx.duckdns.org \
|
||||
"cp /mnt/RED_2TB/storage/Music/.ndignore /mnt/RED_2TB/storage/Music/.ndignore.bak-\$(date +%Y%m%d-%H%M%S)"
|
||||
# 2. перечислить ВСЕ бэкап-папки и сверить со списком
|
||||
ssh truenas_admin@mallexxx.duckdns.org "cd /mnt/RED_2TB/storage/Music && ls -d */ | grep -i backup"
|
||||
# 3. полный файл собрать ЛОКАЛЬНО (write_file) → scp → cp НА МЕСТО (НЕ sed на NAS!)
|
||||
scp /tmp/ndignore-new truenas_admin@mallexxx.duckdns.org:/tmp/ndignore-new
|
||||
ssh truenas_admin@mallexxx.duckdns.org "cp /tmp/ndignore-new /mnt/RED_2TB/storage/Music/.ndignore"
|
||||
```
|
||||
Navidrome подхватывает файл по рестарту; после скана проверить, что игнор сработал —
|
||||
игнорируемые получают **`missing=1`, их НЕ удаляют**:
|
||||
```bash
|
||||
sqlite3 /mnt/RED_2TB/docker/navidrome/data/navidrome.db \
|
||||
"SELECT COUNT(*) FROM media_file; -- всего
|
||||
SELECT COUNT(*) FROM media_file WHERE missing=1; -- игнор/отсутствуют
|
||||
SELECT COUNT(*) FROM media_file WHERE missing=0 AND path NOT LIKE 'backup%';" -- живая музыка
|
||||
```
|
||||
**Контрольное число:** живая музыка = числу строк плана (**7861** на 2026-09-27).
|
||||
Факт после фикса: всего **8396**, `missing=1` **535**, живая **7861** ✅.
|
||||
|
||||
> 🔴 **ОБЯЗАТЕЛЬНЫЙ ФИЛЬТР в ЛЮБОМ запросе к `media_file`:**
|
||||
> `missing=0 AND path NOT LIKE 'backup%'`
|
||||
> Без него читаешь бэкап-копии и делаешь ЛОЖНЫЕ выводы. Эта ошибка дала неверный отчёт
|
||||
> «скобки не исправлены» — бэкап был выдан за живое дерево.
|
||||
|
||||
## 1. Создание НОВОГО каталога под `/mnt/<POOL>/docker/` — из контейнера
|
||||
|
||||
|
||||
Reference in new issue
Block a user