Files
obsidian-vault/personal/tech/jellyfin-music-library-pitfalls.md
T

137 lines
8.5 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Skill: jellyfin-music-library-pitfalls — зеркало навыка
**Скилл:** `devops/jellyfin-music-library-pitfalls`
**Путь:** `~/.hermes/hermes-whale/skills/devops/jellyfin-music-library-pitfalls/SKILL.md`
**Создан:** 2026-09-27
**Category:** devops
> Зеркало для vault. Полный текст — в SKILL.md скилла.
## Когда применять
Любая работа с **музыкальной** библиотекой Jellyfin на удалённом Docker-хосте
(TrueNAS/Taiga, Kraken): добавление, отладка неверной навигации, откат.
**Сначала читать в vault:**
- [[personal/tech/jellyfin-tags-cp1251-unreadable]] — почему Jellyfin не читает теги
- [[family/plans/music-jellyfin-lidarr-taiga]] — план проекта
## Ключевые правила (краткая версия)
### 🔴 RULE 0 — бэкап БД ДО создания библиотеки
Создание библиотеки + скан пишет тысячи строк в `BaseItems`. **Без бэкапа БД откат невозможен.**
```bash
docker stop jellyfin
docker cp jellyfin:/config/data/data/jellyfin.db /home/truenas_admin/jellyfin.db.bak-$(date +%Y%m%d-%H%M%S)
docker start jellyfin
```
- **WAL чекпоинтится только при остановленном контейнере** — иначе копия битая.
- **`SQLiteBackups/` часто ПУСТА** — не полагаться на авто-бэкапы Jellyfin, проверять.
- **Снапшоты ZFS часто 0 штук** — проверять `zfs list -t snapshot | wc -l`.
### 🔴 Почему Jellyfin игнорирует ID3-теги — три причины
1. **Баг `jellyfin/jellyfin#18162`** (confirmed, In Progress): имя MusicArtist берётся
**из имени ПАПКИ**, перекрывая `ARTIST`/`ALBUMARTIST`. Если имя папки произвольное —
Jellyfin идёт в **MusicBrainz** и создаёт артиста оттуда.
2. **Отсутствует `TPE2` (albumartist)** — ключевое поле для иерархии Artist→Album→Track.
При пустом `TPE2` Jellyfin уходит в fallback на папки и **перестаёт читать `TPE1` вообще**.
3. **4-уровневая структура** `категория/подпапка/релиз/файл` — Jellyfin читает как
`Artist/Album`.
**Сигнатура дефекта:** `число MusicArtist == число папок верхнего уровня`.
### 🔬 Диагностика — через `od`, НЕ `ffprobe`
`ffprobe` нормализует вывод и **угадывает кодировку** → может показать `album_artist`,
которого нет как фрейма `TPE2` (из ID3v1-хвоста или TXXX).
```bash
od -A d -t x1z -N 200 "/path/file.mp3" # заголовок + первые фреймы
od -A d -t x1z -N 2000 "$F" | grep -oE "[A-Z][A-Z0-9]{3}" | sort -u # все фреймы
od -A d -t x1z -N 4000 "$F" | grep "P E 2" # есть ли TPE2
```
**Питфоллы:**
- `-of default=nw=1:nk=1` срезает префиксы `TAG:` → ложный вывод «теги пустые».
- `TAG:ID3v1 Comment=` — это **128-байтный ID3v1-хвост**, где CP1251 нормальна.
Цитировать как доказательство CP1251 в ID3v2 — **ошибка вывода**.
- **Валидация ffprobe ≠ доказательство читаемости для потребителя.** Проверять движком,
который читает в проде. Выборка 1% (108 из 7861) ничего не доказывает.
### 🔴 НИКОГДА не использовать `DELETE /Items` — он удаляет ФАЙЛЫ
Удаляет медиафайл с диска, не только запись БД. При rw-монтировании **снесёт музыку**.
Спасает только `ro`-mount. `POST /Library/Media/Deleted` → **404**; `POST /Library/Media/Updated`
→ **415** без JSON body.
**Для удаления только записей — править SQLite напрямую при остановленном контейнере.**
### Безопасный откат БД
Полная процедура (5 шагов) — в SKILL.md. Ключевое:
1. `docker stop` → бэкап текущей БД;
2. распаковка архивной БД + **проверка MD5**;
3. удаление WAL/SHM **при ЗАПУЩЕННОМ контейнере** (`docker exec` не работает на остановленном);
4. `docker cp` БД внутрь + `chown abc:abc` + `docker start`;
5. **проверка `md5sum` ВНУТРИ контейнера** — не по коду возврата.
### Питфоллы (проверено)
| # | Питфолл |
|---|---|
| 1 | `docker exec` НЕ работает на остановленном контейнере → WAL удалять при запущенном |
| 2 | `docker cp` может вернуть `container is not running`, **НО копия проходит** → проверять `md5sum` |
| 3 | Глоб `jellyfin.db*` не раскрывается в zsh контейнера → ложное «файла нет» |
| 4 | `docker stop` возвращает `Exited (137)` (SIGKILL) — не признак поломки данных |
| 5 | Хост и контейнер показывают разное время одного файла (PDT vs +07) — это НЕ расхождение |
| 6 | **Не запускать скрипт-мутатор «для проверки»** — создаст библиотеку обратно |
| 7 | `"a"+"b"` в bash/zsh → пустая строка → HTTP 401. Правильно `"${A}${B}"` |
| 8 | Токен/`os.environ` в файле искажается санитайзером → внешняя обёртка + `export`, сверять `md5sum` |
### Выбор движка: Jellyfin vs Navidrome
| | Jellyfin | Navidrome |
|---|---|---|
| Источник имени артиста | **папка перекрывает тег** (баг #18162) | **только тег** |
| Структура папок | `Artist/Album/Track` обязательна | **игнорируется полностью** |
| Интернет-метаданные | тянет MusicBrainz | **не тянет** |
| Пишет в файлы | может | **никогда** |
| Видео | ✅ | ❌ |
**`ALBUMARTIST` в Navidrome НЕ обязателен** — мейнтейнер `deluan` (#5924):
> «when an album artist tag is missing, Navidrome substitutes the track artist in its place»
Обход без правки тегов:
```toml
PID.Album = "musicbrainz_albumid|albumartist,album,albumversion,releasedate"
```
- **сырое `albumartist`**, НЕ `albumartistid` (тот никогда не пуст);
- `folder` в спеку как fallback класть **нельзя**;
- смена `PID.Album` → полный рескан + новые ID → **бэкапить `navidrome.db`**.
**Lidarr пишет теги сам** при импорте (MusicBrainz + `Write Metadata Tags`) — новые закачки
приходят с `Album Artist`. Связка: `navidrome-lidarr-bridge`.
### Ловушка: семантически валидные, но бессмысленные теги
```
artist=Классика в современной обработке ← не артист
artist=Классика для детей П.И. Чайковский ← не артист
artist=Maria Makarova (organ) ← исполнитель вместо композитора
```
Проходят любую проверку на мойибаке/кодировку. **Если имя артиста в UI удивляет — сначала
grep по тегу `artist` реальных файлов**, прежде чем строить версии про внешние базы.
## Связанные заметки
- [[personal/tech/jellyfin-tags-cp1251-unreadable]] — полный разбор дефекта
- [[family/plans/music-jellyfin-lidarr-taiga]] — план проекта, открытые задачи
- [[family/how-to/navidrome-truenas-android]] — план деплоя Navidrome
- [[personal/tech/jellyfin-db-schema-mismatch]] — схема БД Jellyfin