С чего всё началось

С момента как появился домашний сервер было желание сделать нормальный медиа сервер - чтобы по красоте смотреть фильмы и сериалы в 4K, без костылей.

Начиналось всё просто: сам искал фильм на rutracker, закидывал в qBittorrent, а папка загрузок была расшарена с клиентом. Клиентом сначала был Kodi - не устроил ни вид, ни функционал. Поставил Plex - уже приятнее, но часть функций платная, что крайне не устраивало.

В итоге перешёл на Jellyfin и он мне понравился. Но проблема осталась та же: часть метаданных и обложек не подгружалась, а самому всё равно приходилось искать фильм и вручную кидать его в qBittorrent, выбирая категорию указывающую куда положить файл.

Хотелось, чтобы в одном приложении искал фильм, нажимал «скачать» - и дальше само: разложилось на фильмы и сериалы, подтянулись метаданные, обложки, всё как положено.

Цель

Свести получение любого фильма или сериала к одному действию: нашёл → нажал «скачать» → посмотрел. Всё остальное - поиск релиза, скачивание, проверка качества и языка дорожки, переименование файла, раскладка по нужным папкам библиотеки - должно происходить где-то фоново, без меня. Отдельно не хотелось терять качество выбора. Раньше при ручном поиске я сам сравнивал раздачи по качеству, сидам, дорожкам.

Что получилось на выходе

Ключевой результат - из Jellyfin теперь вообще не нужно выходить. Плагин Jellyfin-Enhanced встраивает поиск и запрос через Seerr прямо в интерфейс Jellyfin: ищу фильм, жму «скачать» - не переключаясь на отдельную вкладку или приложение. А дальше система сама находит релиз на трекере, проверяет его по метаданным, скачивает, переименовывает и кладёт в правильную папку. Через некоторое время фильм уже находится в библиотеке Jellyfin с обложкой и описанием, готовый к просмотру. Ну просто песня, то, что и хотел.

Пример карточки
Пример карточки

Отступление

Готового решения «поставил - и работает» под такой результат я не нашёл. Когда собирал всю эту связку, мягко говоря не был в восторге от того, сколько отдельных инструментов пришлось ставить на каждый чих. Radarr отвечает только за фильмы, Sonarr - только за сериалы, Prowlarr - только за подключение к торрент-трекерам, Seerr - за поиск поверх всего перечисленного. Чтож так сложно жить-то, почему до сих пор никто не собрал это всё в один готовый контейнер - вопрос открытый.

Архитектура

Jellyfin - единственная точка входа глазами пользователя. Через плагин Jellyfin-Enhanced - поиск и запрос (проксируется в Seerr), плюс просмотр готовых файлов из /movies и /tv. Seerr - поиск (TMDB) и маршрутизации запроса - кому передать, Radarr или Sonarr - и проверки, что уже есть в библиотеке. Интерфейс к нему теперь встроен в Jellyfin через плагин, отдельно как вкладку не открываю.
Radarr - весь жизненный цикл фильма: запрос → поиск релиза через индексер → скачивание → сверка по метаданным → переименование → hardlink в /movies. Следит за апгрейдом качества.
Sonarr - то же самое для сериалов, плюс отслеживание выхода новых серий по сезонам (нумерация S01E05, докачка пропущенного).
Prowlarr - держит подключение к индексеру (например к rutracker) и раздаёт его в Radarr и Sonarr одной настройкой.
qBittorrent - просто качает файл в папку своей категории.

docker-compose.yaml
networks:
  home-network:
    driver: bridge
    external: true

services:
  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      - PUID=1000
      - PGID=1000
      - WEBUI_PORT=8080
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./qbittorrent/config:/config
      - /mnt/media:/data
    networks:
      - home-network

  radarr:
    image: lscr.io/linuxserver/radarr:latest
    container_name: radarr
    restart: unless-stopped
    ports:
      - "7878:7878"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Moscow
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./radarr/config:/config
      - /mnt/media:/data
    networks:
      - home-network

  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    restart: unless-stopped
    ports:
      - "8989:8989"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Moscow
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./sonarr/config:/config
      - /mnt/media:/data
    networks:
      - home-network

  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    container_name: prowlarr
    restart: unless-stopped
    ports:
      - "9696:9696"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Moscow
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./prowlarr/config:/config
    networks:
      - home-network

  seerr:
    image: ghcr.io/seerr-team/seerr:latest
    init: true
    container_name: seerr
    restart: unless-stopped
    ports:
      - "5055:5055"
    environment:
      - TZ=Europe/Moscow
      - LOG_LEVEL=info
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./jellyseerr/config:/app/config
    networks:
      - home-network

  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    volumes:
      - ./jellyfin/config:/config
      - ./jellyfin/cache:/cache
      - /mnt/media/movies:/movies
      - /mnt/media/tv:/tv
    restart: unless-stopped
    network_mode: host
    environment:
      - JELLYFIN_PublishedServerUrl=http://192.168.0.2:8096
    devices:
      - /dev/dri:/dev/dri

В ходе экспериментов возможно что-то уже упустил или забыл убрать из docker-compose.yaml, но это текущий мой рабочий конфиг.

Из ключевого там это единый путь /data во всех контейнерах. qbittorrent, radarr и sonarr монтируют /mnt/media под одним и тем же путём. Это обязательное условие для того, чтобы Radarr/Sonarr переносили готовый файл через hardlink, а не через полное копирование - мгновенно и без расхода места на диске дважды.

Настройка Radarr

1) Settings → Media Management → Root Folders → /data/movies

2) Settings → Media Management → Importing → Use Hardlinks instead of Copy

3) Settings → Download Clients → Add → qBittorrent: Host: qbittorrent (имя контейнера - оба в одной сети home-network, резолвится по имени), Port: 8080 , Username/Password: логин-пароль от WebUI, Category: radarr
4) Settings → Connect → Jellyfin (URL http://jellyfin:8096 + API-ключ) - чтобы библиотека обновлялась сразу после импорта.

Настройка Sonarr

То же самое: Root Folder /data/tv, категория sonarr, Use Hardlinks, Connect → Jellyfin.

Настройка Prowlarr

1) Indexers → Add Indexer → RuTracker.org → логин/пароль от аккаунта.

2) Settings → Apps → Add Application:

Radarr: Prowlarr Server http://prowlarr:9696, Radarr Server http://radarr:7878, API Key из Radarr, Sync Level: Full Sync

Sonarr: аналогично, http://sonarr:8989 После этого rutracker сам появляется в индексерах у Radarr и Sonarr - прописывать его там второй раз не нужно.

Настройка Seerr

1) Settings → Services → Jellyfin (URL, логин), Radarr (URL + API Key), Sonarr (URL + API Key)

2) Settings → General → регион/язык ru-RU - тайтлы и описания на русском (данные из TMDB)

3) Раз сервер личный - включил автоодобрение заявок: Request сразу уходит в работу, без второго подтверждения

Настройка Jellyfin

Чтобы вся связка заработала как нужно, необходимо поставить плагин Jellyfin-Enhanced. Инструкция по установке простая, просто в Jellyfin добавляем репозиторий, устанавливаем плагин и перезагружаем сервис. После этого в настройках в меню у нас появится пункт "Jellyfin Enhanced.

Переходим в данный раздел, открываем Seerr и настраиваем по инструкции.

На этом настройка закончена. Перезагружаем Jellyfin, обновляем страницу, пишем поиске название и нажимаем "Запрос" (скачать) и все.

Грабли по пути

В Seerr ничего не загружалось, страницы фильмов и сериалов, в Jellyfin не подтягивались метаданные. Спустя время была найдена причина - не было доступа до themoviedb. У меня стоит AdGuard поэтому я там в настройках DNS, в Upstream DNS servers переопределил днс добавив пару строк которые и решили проблему:

[/themoviedb.org/]9.9.9.9   
[/tmdb.org/]9.9.9.9

Плагины которые поставил

jellyfin-editors-choice-plugin - Полноразмерный слайдер на главной странице с подборкой контента, как на Netflix. Источник подборки - избранное конкретного пользователя или случайная выборка с фильтром по рейтингу.

Jellyfin-Enhanced - помимо интеграции с Seerr это также популярный UX-плагин: горячие клавиши, кастомизация субтитров, кастомизация карточки фильма, отзывы с TMDB.

intro-skipper - по аудио-отпечатку определяет заставку/титры и даёт кнопку "Пропустить" как в Netflix. Работает по всей библиотеке автоматически, разового сканирования достаточно.

jellyfin-icon-metadata - заменяет текстовые ссылки на источники метаданных (IMDb, TMDb, TheTVDB и т.д.) на иконки на странице фильма/сериала.

Будущие цели

Вроде бы получил все что хотел, но порой хочется просто выбрать какой-то рандомный фильм, а не конкретный. В Seerr для этого есть раздел фильмы/сериалы/найти что-то новое с подборками по рекомендациям, студиям и тд. Вот этого не хватаетв в Jellyfin для полной автономности. Есть плагин SeerrFin но там пока что только просто лента фильмов/сериалов, без возможности искать рекомендации, по жанрам, студиям.