Files
jellybit/docs/specs/jellyfin-layout.md
T
avandClaude Opus 4.8 d190072647 Единый беклог задач вместо todo.md и ideas.md (docs)
Слил docs/todo.md и docs/drafts/ideas.md в docs/backlog.md: единый список
будущих задач по приоритетам (Высокий/Средний/Низкий), спекулятивные пункты
помечены _(идея)_. Реализованное из ideas.md (повторное распознавание,
нотификации) не переносил.

Добавил задачи: переработка ревью (выбор источника совпадения с
предпросмотром), главная как список карточек вместо таблицы, отдельная
страница просмотра загрузки (поднял из «Расширенной информации»), скрытие
deleted-загрузок по умолчанию.

Ссылки на drafts/ideas.md из docs/specs/* перенаправлены на backlog.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 15:31:27 +03:00

6.6 KiB

Конвенции раскладки Jellyfin

Целевые имена и структура, в которые jellybit раскладывает файлы хардлинками. Источники: Movies, Shows.

Фильмы

movies/
  Дюна Часть вторая (2024) [tmdbid-693134]/
    Дюна Часть вторая (2024).mkv
    Дюна Часть вторая (2024).ru.srt
  • Папка и файл — Название (Год).
  • provider-id в имени папки ([tmdbid-...]) добавляется при работе с базой — снимает неоднозначность для русских названий, которые Jellyfin иначе может опознать неверно.
  • Внешние субтитры — Имя.<lang>[.flag].srt (флаги forced/sdh/ default/hi), напр. …ru.forced.srt; база имени совпадает с именем видеофайла. Пары VobSub — .idx + .sub.

Сериалы

series/
  Название (2024) [tvdbid-123456]/
    Season 01/
      Название (2024) S01E01.mkv
      Название (2024) S01E02.mkv
  • provider-id — на папке сериала.
  • Сезоны — Season 01, файлы — ... SxxEyy.

Сопоставление источник → цель

Источник берём по пути из qBittorrent (save_path + относительное имя файла из /torrents/files, которое уже содержит корневую папку многофайловой раздачи; это уже хост-путь, path_map — фолбэк). Для каждого распознанного файла (не каталога) создаётся хардлинк в paths.movies/paths.series; целевые каталоги — mkdir (0755, 1000:1000). Исходный файл остаётся на месте (раздача продолжается), inode общий — диск не дублируется.

Целевое имя строится из распознанных полей и санитизируется (без разделителей пути, .., управляющих символов); финальный путь обязан быть строго под библиотекой. Существующую цель не перезаписываем (тот же inode → готово; другой файл → коллизия → review). Инварианты и undo — в architecture.md → «Раскладка файлов».

Владение целевым путём

Целевой путь принадлежит одной загрузке. Когда новая раскладка успешно ложится на путь, который раньше занимала другая загрузка (путь к этому моменту свободен — иначе была бы коллизия → review, чужой файл не перезаписываем), владение переходит к новой загрузке: прежние записи file_link на этот путь помечаются статусом superseded и перестают считаться целью прежней загрузки. Это нужно сверке с реальностью: иначе повторная закачка того же фильма (например, в другом качестве) по тому же пути ложно «воскрешала» бы удалённую задачу — см. workflow.md → «Сверка с реальностью». superseded-ссылки не считаются целью при сверке и не снимаются в Undo.

Желательно: целевой и исходный каталоги — на одной ФС/одном mount'е (внутри контейнера это обеспечивает единая песочница /srv/media), тогда работает дешёвый хардлинк. Если хардлинк невозможен (разные ФС или ФС без поддержки жёстких ссылок), layout не падает, а копирует файл с предупреждением в лог — см. architecture.md → «Раскладка файлов».

Безопасный undo (не снимать последнюю копию)

Undo снимает лишний хардлинк, а не единственный файл. Перед удалением батча layout проверяет каждую цель: если исходный файл уже не существует или у цели не осталось других жёстких ссылок (nlink <= 1), это — последняя копия данных, и весь Undo отклоняется целиком (ошибка ErrLastCopy), не сняв ни одной ссылки (частичный откат тоже стёр бы часть данных). Так нарушенный инвариант «источник неприкосновенен» (источник удалён вручную) не приводит к потере данных. Отсутствующую цель Undo пропускает как уже снятую (идемпотентность). Связь с состояниями рассинхрона — workflow.md → «Сверка с реальностью».

Крайние случаи

  • Многофайловый фильм (части) — стэкинг по точному токену Jellyfin (… - part1/cd1); точный формат уточнить при реализации.
  • РедакцииИмя (Год) [edition-Director's Cut] либо отдельные версии в папке фильма.
  • Двойная серия в одном файле — … SxxEyy-Eyy.
  • СпецвыпускиSeason 00.
  • Сезон-пак — серии в один Season xx; смешанный пак — по per-file сезонам.
  • Несколько аудиодорожек — обычно внутри mkv, не наша забота.
  • Аниме с абсолютной нумерацией — пересчёт в S·E, отдельная проработка (backlog.md).