[2026-09-27] eagle: personal/plans/music-artist-albumartist-repair.md personal/plans/tagwriter-container.md personal/tech/music-tags-repair-truenas.md
This commit is contained in:
1 parent
412fca65ae
commit
9394c23cb0
3 files changed
+180
-32
No files matched your search
@@ -4,7 +4,7 @@ created: '2026-09-27'
|
|||||||
updated: '2026-09-27'
|
updated: '2026-09-27'
|
||||||
type: plan
|
type: plan
|
||||||
namespace: personal
|
namespace: personal
|
||||||
status: script-reviewed-tested-awaiting-go
|
status: script-v11-track-restored-awaiting-go
|
||||||
tags:
|
tags:
|
||||||
- music
|
- music
|
||||||
- metadata
|
- metadata
|
||||||
@@ -689,7 +689,65 @@ paths не найдено в inventory: 0
|
|||||||
Первый аудит дал **4475 «мусорных» `date`** и **6310 `track`**, потому что regex
|
Первый аудит дал **4475 «мусорных» `date`** и **6310 `track`**, потому что regex
|
||||||
`^\d+$` считал числа мусором. Это нормальные значения. **Исключать поля-числа из аудита мусора.**
|
`^\d+$` считал числа мусором. Это нормальные значения. **Исключать поля-числа из аудита мусора.**
|
||||||
|
|
||||||
## ⏭ СЛЕДУЮЩИЕ ШАГИ (обновлено 2026-09-27)
|
## 🔴🔴 НАЙДЕНА ПОТЕРЯННАЯ КОЛОНКА `track` (Alex: «У нас же были трек номера в csv?»)
|
||||||
|
|
||||||
|
**Да, были — и ассистент их потерял при сведении.** Это **вторая половина дефекта P1**.
|
||||||
|
|
||||||
|
```
|
||||||
|
tag-inventory3.csv: 6432 из 7861 ← источник, номера ЕСТЬ
|
||||||
|
APPLY-PLAN-FINAL: 0 ← ❌ колонка не перенесена при сведении
|
||||||
|
```
|
||||||
|
|
||||||
|
**Механика:** при сведении `fix-plan-FINAL.csv` + `genre-plan-FINAL.csv` в единый
|
||||||
|
`APPLY-PLAN-FINAL.csv` колонка `track` **не попала в `fieldnames`**.
|
||||||
|
|
||||||
|
**Почему P1 был половинчатым фиксом:** `TRCK` перестал удаляться (P1), но **записаться
|
||||||
|
не мог** — значения в плане не существовало. 6432 номера уцелели бы, но 1429 файлов
|
||||||
|
остались бы без `TRCK`, а битые номера не обновились.
|
||||||
|
|
||||||
|
### Исправлено (v11)
|
||||||
|
|
||||||
|
```
|
||||||
|
✓ cur_track / new_track в APPLY-PLAN-FINAL.csv — 6432 из 7861, 0 путей не найдено
|
||||||
|
✓ CSV: 16 колонок (было 14)
|
||||||
|
✓ TRCK в FIELD_MAP → `_managed_frame_ids()` = 6 фреймов
|
||||||
|
✓ _frames() создаёт TRCK(encoding=1)
|
||||||
|
✓ expected() включает TRCK → verify сверяет номер трека
|
||||||
|
✓ _self_check() — инвариант на старте: ABORT, если управляемый фрейм не создаётся
|
||||||
|
```
|
||||||
|
|
||||||
|
`new_track = cur_track` — **номер трека не переписывается**, только переносится (Alex не просил менять).
|
||||||
|
|
||||||
|
### ✅ Тест TRCK после фикса
|
||||||
|
|
||||||
|
`Высоцкий/Рецидивист/09 Рецидивист.mp3` (9 фреймов, `TRCK='9'`):
|
||||||
|
|
||||||
|
```
|
||||||
|
APPLY: 1/1 ok=1 err=0
|
||||||
|
TCON (genre): 1 ← изменён по плану
|
||||||
|
TRCK (track): 0 ← в сводке, значение не менялось
|
||||||
|
VERIFY: совпало 1/1, MISMATCH 0
|
||||||
|
После: TRCK="9" · TCOM/TSSE на месте
|
||||||
|
```
|
||||||
|
|
||||||
|
## ✅ ТЕСТОВЫЕ ФАЙЛЫ ВОЗВРАЩЕНЫ ИЗ БЭКАПА (Alex: «Да, восстанови файлы»)
|
||||||
|
|
||||||
|
```
|
||||||
|
!Классика/{Чайковский, Моцарт, Григ, Вивальди, Холст} 5
|
||||||
|
!Барды/Владимир Высоцкий/Рецидивист/{09,02} 2
|
||||||
|
!Барды/Елена Камбурова/Маленький принц 1
|
||||||
|
──────────────────────────────────────────────────────
|
||||||
|
восстановлено: 8/8 не найдено: 0
|
||||||
|
```
|
||||||
|
|
||||||
|
**Подтверждено снимком, не словами:** `TIT2='Рецидивист.'` (с точкой — исходное),
|
||||||
|
`TCON='Поп'` (не `Pop`), `TRCK='9'`.
|
||||||
|
|
||||||
|
⚠️ **Размер тег-блока меняется при перезаписи:** `Холст — Mars.mp3` после теста
|
||||||
|
**17 509 496** байт, в бэкапе **19 174 756** (+1.6 МБ). Данные не потеряны, но
|
||||||
|
**при сверках размеров учитывать, что ID3-блок пересобирается компактнее.**
|
||||||
|
|
||||||
|
## ⏭ СЛЕДУЮЩИЕ ШАГИ (обновлено 2026-09-27, v11)
|
||||||
|
|
||||||
1. ✅ план `fix-plan-FINAL.csv` — 7861 стр, 0 пустых
|
1. ✅ план `fix-plan-FINAL.csv` — 7861 стр, 0 пустых
|
||||||
2. ✅ жанры `genre-plan-FINAL.csv` — 65 уникальных, 0 пустых
|
2. ✅ жанры `genre-plan-FINAL.csv` — 65 уникальных, 0 пустых
|
||||||
@@ -698,28 +756,27 @@ paths не найдено в inventory: 0
|
|||||||
5. ✅ **`album` дозаполнен по папке** — 452 → 0 пустых
|
5. ✅ **`album` дозаполнен по папке** — 452 → 0 пустых
|
||||||
6. ✅ **Бэкап проверен фактом** — `backup/` 7861 MP3, 1:1 по относительным путям (0 расхождений)
|
6. ✅ **Бэкап проверен фактом** — `backup/` 7861 MP3, 1:1 по относительным путям (0 расхождений)
|
||||||
7. ✅ **`cur_*` проверены** — не сломаны (1 расхождение = пробел)
|
7. ✅ **`cur_*` проверены** — не сломаны (1 расхождение = пробел)
|
||||||
8. ✅ **Скрипт-писатель `apply_tags_v2.py` НАПИСАН** — все 4 дефекта v1 закрыты, образ
|
8. ✅ **Скрипт-писатель `apply_tags_v2.py` НАПИСАН** — 4 дефекта v1 закрыты, образ
|
||||||
`tagwriter:v2` собран, **тест на 5 файлах пройден** (`ok=5 err=0`, `VERIFY 5/5 MISMATCH=0`)
|
`tagwriter:v2` собран, тесты 5 + 3 файла (`MISMATCH=0`)
|
||||||
→ [[personal/plans/tagwriter-container]]
|
9. ✅ **СКРИПТ ПЕРЕПРОВЕРЕН** (Alex: «Ещё раз проверь весь текст скрипта на адекватность») —
|
||||||
9. ✅ **СКРИПТ ПОЛНОСТЬЮ ПЕРЕПРОВЕРЕН** (Alex: «Ещё раз проверь весь текст скрипта на
|
**6 дефектов, один критический**:
|
||||||
адекватность») — найдено **6 дефектов, один критический**:
|
- 🔴 **P1: `TRCK` стирался безвозвратно** — в списке на удаление, но не в `_frames()`,
|
||||||
- 🔴 **P1: `TRCK` СТИРАЛСЯ БЕЗВОЗВРАТНО** — `_managed_frame_ids()` содержал `TRCK`
|
и колонки `track` в CSV нет → номер исчез бы у всех 7861.
|
||||||
(на удаление), но `_frames()` его не создавал, а **колонки `track`/`new_track` в CSV
|
|
||||||
НЕТ ВООБЩЕ** → номер трека исчез бы у всех 7861 файла, восстановить нечем.
|
|
||||||
**Фикс:** `_managed_frame_ids()` = ровно `FIELD_MAP`.
|
**Фикс:** `_managed_frame_ids()` = ровно `FIELD_MAP`.
|
||||||
- P2 docstring врал (обещал `TDRC`) · P3 `TDRC` сохранялся случайно · P4 `changed=no`
|
- P2 docstring врал · P3 `TDRC` сохранялся случайно · P4 `changed=no` перезаписывались
|
||||||
перезаписывались (233 файла) → `--force` · P5 нет защиты пути → `ValueError` при выходе
|
(233 файла) → `--force` · P5 нет защиты пути → `ValueError` · P6 `save()` не атомарный.
|
||||||
за `MUSIC` · P6 `save()` не атомарный (известный риск, бэкап есть).
|
10. ✅ **ТЕСТ «ДО/ПОСЛЕ» НА ЖИВОМ ФАЙЛЕ** — 9-фреймовый `Высоцкий/09`: `TRCK` сохранён,
|
||||||
10. ✅ **ТЕСТ «ДО/ПОСЛЕ» НА ЖИВОМ ФАЙЛЕ** — `snapshot.py` → apply → `snapshot.py` → `cmp_snap.py`
|
`TCOM`/`TSSE` сохранены, **потеряно 0 фреймов, размер 4148743 → 4148743**
|
||||||
на файле с **9 фреймами** (`Высоцкий/Рецидивист/09 Рецидивист.mp3`, `TRCK='9'`):
|
11. ✅ **КОЛОНКА `track` ВОССТАНОВЛЕНА** (Alex: «У нас же были трек номера в csv?») —
|
||||||
**`TRCK` СОХРАНЁН · `TCOM`/`TSSE` сохранены · потеряно 0 фреймов · размер 4148743 → 4148743**
|
`cur_track`/`new_track` добавлены, **6432 из 7861**; `TRCK` в `FIELD_MAP`/`_frames()`;
|
||||||
11. 🔴 **ЖДЁТ «go» ОТ ALEX** — массовый прогон `--apply --verify` по `APPLY-PLAN-FINAL.csv` (7861).
|
`_self_check()` инвариант. **Тест: `TRCK='9'` записан, `MISMATCH=0`**
|
||||||
⚠️ **Перед боевым прогоном вернуть 8 тестовых файлов из бэкапа** (`!Классика` ×5,
|
12. ✅ **8 ТЕСТОВЫХ ФАЙЛОВ ВОЗВРАЩЕНЫ ИЗ БЭКАПА** — 8/8, подтверждено снимком
|
||||||
`Высоцкий` ×2, `Камбурова` ×1 — они уже с новыми тегами после тестов).
|
13. 🔴 **ЖДЁТ «go» ОТ ALEX** — массовый прогон `--apply --verify` по `APPLY-PLAN-FINAL.csv` (7861).
|
||||||
12. ⏳ Приёмка Alex: **видно в UI** (Navidrome/Jellyfin), не «read back» ассистента
|
Все тесты откачены, файлы в исходном состоянии, бэкап на месте
|
||||||
13. ⏳ После приёмки: откат 40 из `backup_conv40/` (если нужен), удаление 29 битых/DRM,
|
14. ⏳ Приёмка Alex: **видно в UI** (Navidrome/Jellyfin), не «read back» ассистента
|
||||||
|
15. ⏳ После приёмки: откат 40 из `backup_conv40/` (если нужен), удаление 29 битых/DRM,
|
||||||
удаление бэкапов `backup/` + `backup_raw/` + `backup_fix/` + `backup_conv40/`
|
удаление бэкапов `backup/` + `backup_raw/` + `backup_fix/` + `backup_conv40/`
|
||||||
14. ⏳ Lidarr + Navidrome (первоначальная задача Alex, ещё не начата)
|
16. ⏳ Lidarr + Navidrome (первоначальная задача Alex, ещё не начата)
|
||||||
|
|
||||||
## 🔴 ПРАВИЛО (открыто в этой сессии): «управляемый» набор фреймов = набор записываемых
|
## 🔴 ПРАВИЛО (открыто в этой сессии): «управляемый» набор фреймов = набор записываемых
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace: personal
|
|||||||
related:
|
related:
|
||||||
- '[[personal/plans/music-tags-wave38-fixes]]'
|
- '[[personal/plans/music-tags-wave38-fixes]]'
|
||||||
- '[[personal/tech/music-tags-repair-truenas]]'
|
- '[[personal/tech/music-tags-repair-truenas]]'
|
||||||
status: v2-script-ready-awaiting-go
|
status: v11-script-ready-awaiting-go
|
||||||
tags:
|
tags:
|
||||||
- music
|
- music
|
||||||
- truenas
|
- truenas
|
||||||
@@ -13,11 +13,11 @@ tags:
|
|||||||
- plan
|
- plan
|
||||||
title: tagwriter — контейнер применения тегов MP3
|
title: tagwriter — контейнер применения тегов MP3
|
||||||
type: plan
|
type: plan
|
||||||
updated: '2026-09-26'
|
updated: '2026-09-27'
|
||||||
---
|
---
|
||||||
# tagwriter — контейнер применения тегов MP3 (TrueNAS)
|
# tagwriter — контейнер применения тегов MP3 (TrueNAS)
|
||||||
|
|
||||||
_Создан: 2026-09-26. **Статус (обновлён 2026-09-27): ✅ `apply_tags_v2.py` НАПИСАН + ПОЛНОСТЬЮ ПЕРЕПРОВЕРЕН (v10). ЗАКРЫТЫ 4 ДЕФЕКТА v1 (D1 `delall` вне `if` · D2 +`TPE2`/`TCON` · D3 фильтр `.mp3` · D4 прогресс+сводка+`--verify`) + 6 ДЕФЕКТОВ, найденных при перечитывании (P1 🔴 `TRCK` стирался безвозвратно · P2 docstring врал · P3 `TDRC` сохранялся случайно · P4 `changed=no` перезаписывались · P5 нет защиты пути · P6 `save()` не атомарный). ОБРАЗ `tagwriter:v2` СОБРАН. ТЕСТЫ: 5 файлов (`ok=5 err=0`, `MISMATCH=0`) + 3 файла (`ok=3 err=0`, `MISMATCH=0`) + ТЕСТ «ДО/ПОСЛЕ» на файле с 9 фреймами (`TRCK` СОХРАНЁН, `TCOM`/`TSSE` сохранены, размер 4148743 → 4148743 байт, потеряно 0 фреймов). 🔴 **ФАЙЛЫ МУЗЫКИ НЕ ТРОНУТЫ МАССОВО — ЖДЁТ «go» ОТ ALEX.** ⏳ НЕ выполнено: массовый apply по `APPLY-PLAN-FINAL.csv` (7861), возврат 8 тестовых файлов из бэкапа, откат 40 из `backup_conv40/`, удаление 29 битых/DRM, приёмка Jellyfin. Бэкапы готовы и проверены по путям: `backup/` 7861 MP3 (1:1 с основной библиотекой), `backup_conv40/` 40, `backup_fix/` 165, `backup_raw/` 71. Решение Alex по TRCK = **B** (номера не удалять).**_
|
_Создан: 2026-09-26. **Статус (обновлён 2026-09-27, v11): ✅ `apply_tags_v2.py` НАПИСАН + ПЕРЕПРОВЕРЕН + 🔴 НАЙДЕНА И ВОССТАНОВЛЕНА ПОТЕРЯННАЯ КОЛОНКА `track`. ЗАКРЫТЫ 4 ДЕФЕКТА v1 (D1 `delall` вне `if` · D2 +`TPE2`/`TCON` · D3 фильтр `.mp3` · D4 прогресс+сводка+`--verify`) + 6 ДЕФЕКТОВ перечитывания (P1 🔴 `TRCK` стирался безвозвратно · P2 docstring врал · P3 `TDRC` случайно · P4 `changed=no` перезаписывались · P5 нет защиты пути · P6 `save()` не атомарный) + v11 (потерянная колонка `track` восстановлена → 6432 номера, `TRCK` в `FIELD_MAP`/`_frames()`, `_self_check()` инвариант). ОБРАЗ `tagwriter:v2` СОБРАН. ТЕСТЫ: 5 файлов · 3 файла · 1 файл (`TRCK` записан) — везде `MISMATCH=0`; «ДО/ПОСЛЕ» на 9-фреймовом файле (потеряно 0 фреймов). 8 ТЕСТОВЫХ ФАЙЛОВ ВОЗВРАЩЕНЫ ИЗ БЭКАПА (подтверждено снимком). 🔴 **ФАЙЛЫ МУЗЫКИ НЕ ТРОНУТЫ МАССОВО — ЖДЁТ «go» ОТ ALEX.** ⏳ НЕ выполнено: массовый apply по `APPLY-PLAN-FINAL.csv` (7861), откат 40 из `backup_conv40/`, удаление 29 битых/DRM, приёмка Jellyfin, Lidarr+Navidrome. Бэкапы проверены по путям: `backup/` 7861 MP3 (1:1), `backup_conv40/` 40, `backup_fix/` 165, `backup_raw/` 71. Решение Alex по TRCK = **B** (номера не удалять).**_
|
||||||
_Основание: [[personal/plans/music-tags-wave38-fixes]]._
|
_Основание: [[personal/plans/music-tags-wave38-fixes]]._
|
||||||
|
|
||||||
## ✅ v10 (2026-09-27): ПОЛНОЕ ПЕРЕЧИТЫВАНИЕ СКРИПТА — 🔴 НАЙДЕН ДЕФЕКТ УНИЧТОЖЕНИЯ `TRCK`
|
## ✅ v10 (2026-09-27): ПОЛНОЕ ПЕРЕЧИТЫВАНИЕ СКРИПТА — 🔴 НАЙДЕН ДЕФЕКТ УНИЧТОЖЕНИЯ `TRCK`
|
||||||
@@ -114,6 +114,86 @@ VERIFY: совпало 3/3, MISMATCH 0
|
|||||||
хотя `scp` вроде прошёл. **Проверять `ls -la` монтируемого файла ПОСЛЕ `scp`, до `docker run`.**
|
хотя `scp` вроде прошёл. **Проверять `ls -la` монтируемого файла ПОСЛЕ `scp`, до `docker run`.**
|
||||||
`/app` — образ, `/app/data` — монтирование; `scp` в `data/` нужен **и** `-v .../data:/app/data`.
|
`/app` — образ, `/app/data` — монтирование; `scp` в `data/` нужен **и** `-v .../data:/app/data`.
|
||||||
|
|
||||||
|
## ✅ v11 (2026-09-27): 🔴 ПОТЕРЯННАЯ КОЛОНКА `track` НАЙДЕНА ALEX'ОМ → ВОССТАНОВЛЕНА
|
||||||
|
|
||||||
|
Alex: «**У нас же были трек номера в csv?**» — **да, были, и ассистент их потерял при сведении.**
|
||||||
|
|
||||||
|
```
|
||||||
|
tag-inventory.csv: 5014 из 7906
|
||||||
|
tag-inventory2.csv: 5119 из 7906
|
||||||
|
tag-inventory3.csv: 6432 из 7861 ← актуальный источник
|
||||||
|
APPLY-PLAN-FINAL: 0 ← ❌ КОЛОНКА НЕ БЫЛА ПЕРЕНЕСЕНА
|
||||||
|
```
|
||||||
|
|
||||||
|
**Найденная причина** — при сведении `fix-plan-FINAL.csv` + `genre-plan-FINAL.csv` в единый
|
||||||
|
`APPLY-PLAN-FINAL.csv` колонка `track` из `tag-inventory3.csv` **не была включена** в `fieldnames`.
|
||||||
|
Именно поэтому фикс P1 (`TRCK` в `_managed_frame_ids()`) был **половинчатым**: фрейм перестал
|
||||||
|
удаляться, но и **записаться не мог** — данных о номере трека в плане не существовало.
|
||||||
|
|
||||||
|
**Последствие, если бы не поймали:** 6432 существующих номера уцелели бы (P1 их спасал),
|
||||||
|
но 1429 файлов остались бы без `TRCK`, а битые номера не обновились. **Это тот же класс дефекта,
|
||||||
|
что P1 — «управляемый фрейм без источника данных».**
|
||||||
|
|
||||||
|
### Исправлено
|
||||||
|
|
||||||
|
| Шаг | Факт |
|
||||||
|
|---|---|
|
||||||
|
| `cur_track` / `new_track` добавлены в `APPLY-PLAN-FINAL.csv` | ✅ **6432 из 7861** с номерами · 0 путей не найдено |
|
||||||
|
| Новая раскладка колонок | **16 колонок** (было 14): `cur_track` после `cur_genre`, `new_track` после `new_genre` |
|
||||||
|
| `TRCK` добавлен в `FIELD_MAP` скрипта | ✅ теперь 6 управляемых фреймов |
|
||||||
|
| `_frames()` создаёт `TRCK` | ✅ `TRCK(encoding=1, text=[...])` |
|
||||||
|
| `expected()` включает `TRCK` | ✅ verify сверяет номер трека |
|
||||||
|
| 🔴 **`_self_check()` — инвариант на старте** | ✅ падает с `ABORT`, если управляемый фрейм нельзя создать в `_frames()` |
|
||||||
|
|
||||||
|
**Номер трека НЕ переписывается** — `new_track = cur_track` (перенос как есть, Alex не просил менять).
|
||||||
|
|
||||||
|
### 🔴 ПРАВИЛО (главное этой сессии)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Инвариант, который обязан быть в скрипте-писателе тегов:
|
||||||
|
assert sorted(_managed_frame_ids()) == sorted(fid for _, fid, _ in FIELD_MAP)
|
||||||
|
```
|
||||||
|
|
||||||
|
**«Управляемый» набор фреймов = РОВНО набор записываемых.** Фрейм, который скрипт удаляет,
|
||||||
|
но значение которого нигде не задано (нет в CSV / нет в `_frames()`), — **потеря данных
|
||||||
|
по определению.** Ловушка не проявляется в тестах: `delall` + отсутствие `add` не дают ошибки,
|
||||||
|
просто тихо стирают тег. **Находится только построчным перечитыванием списков «что трогаем».**
|
||||||
|
|
||||||
|
### ✅ ТЕСТ `TRCK` ПОСЛЕ ФИКСА — ЗАПИСАН И ПРОВЕРЕН
|
||||||
|
|
||||||
|
Файл `Высоцкий/Рецидивист/09 Рецидивист.mp3` (9 фреймов, `TRCK='9'`):
|
||||||
|
|
||||||
|
```
|
||||||
|
=== APPLY: 1 файлов ===
|
||||||
|
... 1/1 (100%) ok=1 err=0
|
||||||
|
изменения по полям:
|
||||||
|
TCON (genre ): 1
|
||||||
|
TRCK (track ): 0 ← TRCK в сводке, не изменился (new_track == cur_track)
|
||||||
|
=== VERIFY: ... совпало=1 MISMATCH=0
|
||||||
|
|
||||||
|
После: TRCK="9" · TCON="Pop" · TCOM/TSSE на месте
|
||||||
|
```
|
||||||
|
|
||||||
|
### ✅ ТЕСТОВЫЕ ФАЙЛЫ ВОЗВРАЩЕНЫ ИЗ БЭКАПА (8 шт.)
|
||||||
|
|
||||||
|
Alex: «**Да, восстанови файлы**».
|
||||||
|
|
||||||
|
```
|
||||||
|
!Классика/Чайковский, Моцарт, Григ, Вивальди, Холст (5)
|
||||||
|
!Барды/Владимир Высоцкий/Рецидивист/09, /02 (2)
|
||||||
|
!Барды/Елена Камбурова/Маленький принц (1)
|
||||||
|
────────────────────────────────────────────────────
|
||||||
|
восстановлено: 8/8, не найдено: 0
|
||||||
|
```
|
||||||
|
|
||||||
|
**Проверка фактом:** Высоцкий/09 → `TIT2='Рецидивист.'` (с точкой — исходное значение),
|
||||||
|
`TCON='Поп'` (не `Pop`), `TRCK='9'`. **Откат подтверждён снимком, не словами.**
|
||||||
|
|
||||||
|
⚠️ **Замечание по размеру:** у `Холст — Mars.mp3` после теста размер был **17 509 496**,
|
||||||
|
в бэкапе — **19 174 756** (больше на 1.6 МБ). Значит **тестовый apply переписал ID3-блок
|
||||||
|
компактнее** — бэкапная версия имеет более жирный тег. Данные не потеряны, но
|
||||||
|
**размер тег-блока меняется при перезаписи** — учитывать при сверках.
|
||||||
|
|
||||||
## ✅ v9 (2026-09-27): `apply_tags_v2.py` — НОВЫЙ СКРИПТ-ПИСАТЕЛЬ, ВСЕ 4 ДЕФЕКТА ЗАКРЫТЫ
|
## ✅ v9 (2026-09-27): `apply_tags_v2.py` — НОВЫЙ СКРИПТ-ПИСАТЕЛЬ, ВСЕ 4 ДЕФЕКТА ЗАКРЫТЫ
|
||||||
|
|
||||||
**Задача Alex:** «Бери скрипт которым ты уже прогонял apply и фикси его чтобы писал все нужные
|
**Задача Alex:** «Бери скрипт которым ты уже прогонял apply и фикси его чтобы писал все нужные
|
||||||
|
|||||||
@@ -42,22 +42,33 @@ related:
|
|||||||
> - ✅ `genre-plan-FINAL.csv` — 7861 стр, **65 уникальных жанра** (было 154), **0 пустых**,
|
> - ✅ `genre-plan-FINAL.csv` — 7861 стр, **65 уникальных жанра** (было 154), **0 пустых**,
|
||||||
> мойибаке `Psy Årance` → `Psy-Trance` (29 файлов, `Å`/`Е` — латиница vs кириллица)
|
> мойибаке `Psy Årance` → `Psy-Trance` (29 файлов, `Å`/`Е` — латиница vs кириллица)
|
||||||
>
|
>
|
||||||
> ### ✅ ОБНОВЛЕНИЕ 2026-09-27 (вечер) — ПЛАН ЗАКРЫТ, СКРИПТ ГОТОВ, ЖДЁТ «GO»
|
> ### ✅ ОБНОВЛЕНИЕ 2026-09-27 (вечер, v11) — 🔴 КОЛОНКА `track` БЫЛА ПОТЕРЯНА И ВОССТАНОВЛЕНА
|
||||||
>
|
>
|
||||||
> | Шаг | Факт |
|
> | Шаг | Факт |
|
||||||
> |---|---|
|
> |---|---|
|
||||||
> | `APPLY-PLAN-FINAL.csv` | ✅ 7861 стр, 7628 изменений, **все 5 полей заполнены** (title/artist/albumartist/album/genre) |
|
> | `APPLY-PLAN-FINAL.csv` | ✅ 7861 стр, 7628 изменений, **16 колонок** (было 14) |
|
||||||
> | `album` дозаполнен по папке | ✅ 452 → **0 пустых** |
|
> | 🔴 **Колонка `track`** | **БЫЛА ПОТЕРЯНА** при сведении (Alex: «У нас же были трек номера в csv?») → **восстановлена: 6432 из 7861** |
|
||||||
|
> | Все поля заполнены | ✅ title · artist · albumartist · album · genre · **track** |
|
||||||
> | Валидация | ✅ дубли 0 · спам 0 · мойибаке 0 · пустых 0 · class↔albumartist 0 |
|
> | Валидация | ✅ дубли 0 · спам 0 · мойибаке 0 · пустых 0 · class↔albumartist 0 |
|
||||||
> | Бэкап | ✅ `backup/` **7861 MP3**, сверка по относительным путям **1:1** (0 расхождений) |
|
> | Бэкап | ✅ `backup/` **7861 MP3**, сверка по относительным путям **1:1** (0 расхождений) |
|
||||||
> | `cur_*` | ✅ **не сломаны** — 1 расхождение = пробел в `genre` |
|
> | `cur_*` | ✅ **не сломаны** — 1 расхождение = пробел в `genre` |
|
||||||
> | Скрипт `apply_tags_v2.py` | ✅ написан, 4 дефекта v1 закрыты; **⚠️ ПОСЛЕ ПОЛНОЙ ПЕРЕПРОВЕРКИ исправлено ещё 6 дефектов** (🔴 `TRCK` стирался безвозвратно · `changed=no` перезаписывались · нет защиты пути · docstring врал); тесты 5+3 файла `MISMATCH=0` + «ДО/ПОСЛЕ» на 9-фреймовом файле (`TRCK` сохранён, потеряно 0 фреймов) |
|
> | Скрипт `apply_tags_v2.py` | ✅ **v11**: 4 дефекта v1 + 6 дефектов перечитывания (🔴 `TRCK` стирался · `changed=no` перезаписывались · нет защиты пути · docstring врал) + `TRCK` в `FIELD_MAP`/`_frames()` + **`_self_check()` инвариант** |
|
||||||
> | 🔴 Дальше | **ЖДЁТ «go» ОТ ALEX** — массовый `--apply --verify` по 7861. ⚠️ Перед прогоном вернуть 8 тестовых файлов из бэкапа |
|
> | Тесты | ✅ 5 файлов · 3 файла · 1 файл (`TRCK='9'` записан) — везде `MISMATCH=0`; «ДО/ПОСЛЕ» на 9-фреймовом файле: потеряно 0 фреймов |
|
||||||
|
> | 8 тестовых файлов | ✅ **возвращены из бэкапа** (подтверждено снимком: `TIT2='Рецидивист.'`, `TCON='Поп'`) |
|
||||||
|
> | 🔴 Дальше | **ЖДЁТ «go» ОТ ALEX** — массовый `--apply --verify` по 7861. Все тесты откачены, файлы в исходном состоянии |
|
||||||
|
>
|
||||||
|
> 🔴 **ГЛАВНОЕ ПРАВИЛО СЕССИИ:** «управляемый» набор фреймов = РОВНО набор записываемых.
|
||||||
|
> `TRCK` стоял на **удаление**, но отсутствовал в `_frames()` **и в CSV** → номер трека исчез бы
|
||||||
|
> у всех 7861 файла без возможности восстановления. Инвариант:
|
||||||
|
> `assert sorted(_managed_frame_ids()) == sorted(fid for _,fid,_ in FIELD_MAP)`.
|
||||||
|
> **Ловушка не проявляется в тестах** (`delall` + нет `add` = тихая потеря, не ошибка) —
|
||||||
|
> находится только **построчным перечитыванием списков «что трогаем»**.
|
||||||
|
> Детали → [[personal/plans/music-artist-albumartist-repair]] и [[personal/plans/tagwriter-container]].
|
||||||
>
|
>
|
||||||
> Питфоллы сессии: `cur_*` ≠ `new_*` в отчётах · `/storage/Music` не существует на хосте (только
|
> Питфоллы сессии: `cur_*` ≠ `new_*` в отчётах · `/storage/Music` не существует на хосте (только
|
||||||
> `/mnt/RED_2TB/storage/Music`, в контейнере `/storage` ro) · инлайн-python через ssh ломается на
|
> `/mnt/RED_2TB/storage/Music`, в контейнере `/storage` ro) · инлайн-python через ssh ломается на
|
||||||
> кавычках · tirith блокирует кириллицу вплотную к ASCII.
|
> кавычках · tirith блокирует кириллицу вплотную к ASCII · субагенту **явно запрещать** создавать
|
||||||
> Детали → [[personal/plans/music-artist-albumartist-repair]] и [[personal/plans/tagwriter-container]].
|
> файлы (писал в корень vault).
|
||||||
|
|
||||||
> ## ✅ ТРИДЦАТЬ ВОСЬМАЯ ВОЛНА (2026-09-26) — ФИНАЛЬНЫЙ АУДИТ + 4 ПРАВКИ + ПРИМЕНЕНИЕ НА NAS
|
> ## ✅ ТРИДЦАТЬ ВОСЬМАЯ ВОЛНА (2026-09-26) — ФИНАЛЬНЫЙ АУДИТ + 4 ПРАВКИ + ПРИМЕНЕНИЕ НА NAS
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in new issue
Block a user