[2026-09-27] eagle: family/how-to/jellyfin-config.md family/plans/music-jellyfin-lidarr-taiga.md family/projects/media-toolbox-taiga.md personal/tech/jellyfin-tags-cp1251-unreadable.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-27 10:06:14 +06:00
1 parent 97c31f3ebb
commit 266b604b30
4 files changed
+238 -37

No files matched your search

+102 -13
View File
@@ -1,19 +1,62 @@
# Jellyfin не читает теги в CP1251 — корневой дефект музыкальной библиотеки
# Jellyfin не читает теги — корневой дефект музыкальной библиотеки
> 📌 **Имя файла `jellyfin-tags-cp1251-unreadable` — ЛЕГАСИ**, оставлено ради целостности ссылок
> (на него ссылаются 6 заметок). **Актуальная причина — не CP1251, а отсутствие `TPE2`.**
**Дата обнаружения:** 2026-09-27
**Хост:** Taiga (TrueNAS), Jellyfin 10.11.11, имя сервера `Taiga`
**Библиотека:** Music, ItemId `7e64e319657a9516ec78490da03edccb`, путь `/storage/Music`
**Namespace:** personal
**Статус:** 🔴 дефект подтверждён. **Библиотека УДАЛЕНА при откате (2026-09-27), идёт восстановление
БД из бэкапа до импорта.** Ремонт кодировки отложен до завершения отката.
**Статус:** ✅ **ПРИЧИНА УСТАНОВЛЕНА ФАКТОМ.** Библиотека **удалена**, БД **восстановлена**
на версию до импорта. Ремонт (простановка `TPE2`) отложен — не выполнен.
> 🔄 **ОБНОВЛЕНО 2026-09-27 (вечер): Alex потребовал откат.** Библиотека Music удалена
> (`DELETE /Library/VirtualFolders` → HTTP 204), 6 видео-библиотек на месте. Найден валидный
> бэкап БД до импорта: `/home/truenas_admin/jellyfin-config-bak-20260926-203007.tar.gz`
> (внутри `jellyfin.db` 39 МБ, Music-записей **0**, CollectionFolder **6**).
> Процедура восстановления — [[family/plans/music-jellyfin-lidarr-taiga]] §ОТКАТ.
> **Этот документ остаётся актуальным:** дефект CP1251 никуда не делся, ремонт кодировки
> понадобится при повторной попытке создания библиотеки.
> 🔴 **ИСПРАВЛЕНО 2026-09-27 (v5): диагноз «теги в CP1251» ОПРОВЕРГНУТ.** Alex указал:
> «мы переписывали все теги, как раз чтобы убрать cp1251» — **он был прав**.
> Байтовый анализ показал: теги **уже в UTF-16 с BOM**, encoding-байт `01`, CP1251 нет.
> **Настоящая причина — в файлах ОТСУТСТВУЕТ фрейм `TPE2` (albumartist).**
> См. раздел «ИСТИННАЯ причина» ниже. Прежняя версия про CP1251 сохранена в конце как история
> ошибки — **не тиражировать**.
> ✅ **ОТКАТ ЗАВЕРШЁН:** БД восстановлена из `/home/truenas_admin/jellyfin-config-bak-20260926-203007.tar.gz`
> (внутри `jellyfin.db` 39 МБ, MD5 `b71b5d659a1262fa98b85a6ab0003f24`). Итог: 6 библиотек, Audio=0,
> MusicArtist=0. Процедура и питфоллы — [[family/plans/music-jellyfin-lidarr-taiga]] §ВОССТАНОВЛЕНИЕ.
## ИСТИННАЯ причина: нет фрейма `TPE2` (albumartist)
Разбор `/storage/Music/!Детские/Сказки/Letuchij korabl/Летучий корабль (2).mp3`:
```
49 44 33 03 00 → ID3v2.3
TIT2 ... 00 01 ff fe 1b 04 35 04 ... → encoding=01 (UTF-16 + BOM), ff fe = BOM LE
TPE1 ... 00 01 ff fe ... → encoding=01, UTF-16 ✅
TALB ... 00 01 ff fe ... → encoding=01, UTF-16 ✅
TRCK 00 00 00 07 00 00 01 ff fe 32 → encoding=01 ✅
041b 0435 0442 0443 0447 0438 0439 → Л е т у ч и й → "Летучий"
```
**Полный список фреймов того же файла:**
| Фрейм | Поле | Есть? |
|---|---|---|
| `TIT2` | title | ✅ |
| `TPE1` | artist | ✅ |
| `TALB` | album | ✅ |
| `TRCK` | track | ✅ |
| `COMM` | comment | ✅ |
| **`TPE2`** | **albumartist** | ❌ **ОТСУТСТВУЕТ** |
**Механика fallback:** в music-библиотеке Jellyfin **ключевое поле артиста — `AlbumArtist` (`TPE2`)**,
а не `Artist` (`TPE1`). Иерархия строится **Artist → Album → Track** по `TPE2`.
`TPE2` пуст → Jellyfin уходит в fallback на файловую систему и **перестаёт смотреть на `TPE1` вообще**:
```
Artist = папка уровня 1 (!Детские)
Album = папка уровня 2 (Letuchij korabl)
Name = имя файла
```
**Ремонт:** проставить **`TPE2` = значение `TPE1`** во все 7826 файла, ID3v2.3 / UTF-16 (как сейчас),
затем перескан. Проверка гипотезы — 3 копии в `/tmp`, оригиналы не трогать.
## Симптом (как проявился)
@@ -36,10 +79,56 @@ z Другое, Enigma, Ленинград
```
Alex видит в UI исполнителей «Летучий корабль», «Винни-Пух», «Maria Makarova» — это **имена
папок уровня 2**, показанные как альбомы. `Maria Makarova` оказалась единственной настоящей
(из тега) — её имя ASCII-совместимо.
папок уровня 2**, показанные как альбомы. `Maria Makarova` — единственная настоящая (из тега).
## Корневая причина
> ⚠️ Ранее здесь стояло объяснение «потому что её имя ASCII-совместимо» — **неверно**
> (теги и так UTF-16, см. выше). Истинная причина (наличие `TPE2` либо подтянутые метаданные)
> **фактом не подтверждена** — не тиражировать.
## 🔬 Метод: как ПРАВИЛЬНО проверить, что реально лежит в ID3
Байтовый анализ — единственный надёжный способ. `ffprobe` **нормализует** вывод и скрывает
кодировку и encoding-байты.
```bash
# Заголовок ID3 + первые 200 байт с ASCII-подписями
od -A d -t x1z -N 200 "/path/file.mp3"
# Расшифровка:
# байты 0-2 49 44 33 → "ID3"
# байт 3 03 → ID3v2.3 (04 = ID3v2.4)
# фрейм TIT2/TPE1/... → 4 байта имя
# далее 4 байта размер, 2 байта flags
# байт enc 00=Latin-1, 01=UTF-16+BOM, 03=UTF-8
# BOM ff fe = UTF-16 LE, fe ff = UTF-16 BE
# Полный список фреймов файла
od -A d -t x1z -N 2000 "$F" | grep -oE "[A-Z][A-Z0-9]{3}" | sort -u
# Проверка конкретного фрейма
od -A d -t x1z -N 2000 "$F" | grep "P E 2" # TPE2 = albumartist
```
**Универсальная проверка наличия albumartist у одного файла:**
```bash
docker exec jellyfin /usr/lib/jellyfin-ffmpeg/ffprobe -v error \
-show_entries format_tags=artist,album_artist,albumartist,title,album,genre,date,track \
-of default "/storage/Music/<path>"
```
> 🔴 **Питфолл: `-of default=nw=1:nk=1` срезает префиксы `TAG:`** → `grep "^TAG:artist="` даёт
> **0 совпадений** → ложный вывод «теги пустые». Использовать `-of default` (с префиксами).
> ⚠️ Но даже `-of default` **не покажет encoding-байт** — для кодировки только `od`.
> 🔴 **Питфолл вывода: `ID3v1 Comment` в ffprobe — это 128-байтный ID3v1-хвост, НЕ ID3v2.**
> Кодировка в ID3v1 не декларируется в принципе, там CP1251 — это **нормально**.
> Брать его как «доказательство CP1251 в ID3v2» — **грубая ошибка вывода** (поймана здесь).
## ❌ ОПРОВЕРГНУТАЯ версия: «теги в CP1251» (история ошибки — НЕ тиражировать)
> **Ниже — первоначальный диагноз, оказавшийся НЕВЕРНЫМ.** Оставлено как история, чтобы
> будущая сессия не пошла по ложному пути. **Истинная причина — отсутствие `TPE2`, см. выше.**
**Теги записаны ID3v2.3 в CP1251 без декларации кодировки. Jellyfin такие теги отбрасывает.**