8.5 KiB
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. Без бэкапа БД откат невозможен.
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-теги — три причины
- Баг
jellyfin/jellyfin#18162(confirmed, In Progress): имя MusicArtist берётся из имени ПАПКИ, перекрываяARTIST/ALBUMARTIST. Если имя папки произвольное — Jellyfin идёт в MusicBrainz и создаёт артиста оттуда. - Отсутствует
TPE2(albumartist) — ключевое поле для иерархии Artist→Album→Track. При пустомTPE2Jellyfin уходит в fallback на папки и перестаёт читатьTPE1вообще. - 4-уровневая структура
категория/подпапка/релиз/файл— Jellyfin читает какArtist/Album.
Сигнатура дефекта: число MusicArtist == число папок верхнего уровня.
🔬 Диагностика — через od, НЕ ffprobe
ffprobe нормализует вывод и угадывает кодировку → может показать album_artist,
которого нет как фрейма TPE2 (из ID3v1-хвоста или TXXX).
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. Ключевое:
docker stop→ бэкап текущей БД;- распаковка архивной БД + проверка MD5;
- удаление WAL/SHM при ЗАПУЩЕННОМ контейнере (
docker execне работает на остановленном); docker cpБД внутрь +chown abc:abc+docker start;- проверка
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»
Обход без правки тегов:
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