137 lines
8.5 KiB
Markdown
Executable File
137 lines
8.5 KiB
Markdown
Executable File
# 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
|