Files
jellybit/docs/specs/architecture.md
T

7.0 KiB

Архитектура

Назначение

Jellybit принимает торрент с текстовым контекстом, скачивает его через qBittorrent, определяет содержимое (фильм или сериал с сезонами и сериями) и раскладывает файлы по конвенциям Jellyfin — хардлинками, не трогая исходную раздачу.

Принципы

  • Один статический бинарь. Доставка — копированием на сервер. См. ADR-2026-06-13-go-single-binary.
  • Источник не трогаем. В библиотеку кладём хардлинки; qBittorrent продолжает раздачу, место на диске не дублируется.
  • Единое ядро, тонкие транспорты. Вся логика приёма загрузки — в use-case Ingest. HTTP API, веб-UI и Telegram — обёртки над ним.
  • Опциональные внешние зависимости. Базы метаданных (TMDB/TVDB) включаются конфигом; без них сервис работает на одном LLM.
  • Минимум компонентов. В духе umbar — без лишних сервисов.

Компоненты

Пакет Ответственность
ingest use-case приёма загрузки, общий для всех транспортов
qbt клиент qBittorrent WebUI API
worker фоновый цикл: машина состояний, поллинг завершения
recognize пред-парс имени + LLM + модель уверенности
metadata интерфейс баз метаданных + TMDB/TVDB (опц.)
layout конвенции Jellyfin + хардлинкер
store SQLite: загрузки, распознавание, ссылки
httpapi REST + веб-UI (server-rendered, htmx)
tgbot Telegram-адаптер + парсер сообщений торрент-бота
config загрузка TOML-конфига

Поток и машина состояний

ingest → downloading → completed → recognizing ─┬─ уверенно ───────→ linking → done
                                                 └─ сомнительно → review → linking → done
любой шаг при ошибке → failed
  • ingest — приняли источник + контекст, поставили в qBittorrent (категория jellybit), записали в БД.
  • downloading / completedworker поллит qBittorrent по категории.
  • recognizingrecognize строит план раскладки и оценку уверенности (см. recognition.md).
  • review — план уходит человеку (веб-UI / Telegram), ждём решения.
  • linkinglayout создаёт хардлинки в библиотеке.
  • done — опционально дёргаем скан библиотеки Jellyfin.

Состояние персистентно в SQLite — перезапуск сервиса безопасен, worker продолжает с того же места.

Транспорты

Все три ведут в один Ingest(req):

  • HTTP API + веб-UI — форма «добавить», список загрузок, экран подтверждения раскладки (server-rendered + htmx, без JS-сборки).
  • Telegram-бот — переслать magnet или сообщение торрент-бота прямо в jellybit; текст становится контекстом распознавания.
  • CLIjellybit add <magnet> --context "..." для отладки.

Хранилище

SQLite, минимум таблиц:

  • download — источник, контекст, hash торрента, категория, состояние, тайминги.
  • recognition — тип, название, год, сезон, provider-id, оценка уверенности, сырой ответ LLM.
  • file_link — соответствие исходный файл → целевой путь, вид (видео/субтитры), статус.

Конфигурация

TOML, секреты — placeholder'ы; реальный конфиг не коммитим. Пример:

[qbittorrent]
url      = "http://127.0.0.1:8989"
username = "admin"
password = ""
category = "jellybit"

[paths]
downloads = "/srv/downloads"
movies    = "/srv/media/movies"
series    = "/srv/media/series"

[llm]
provider = "anthropic"
model    = "claude-sonnet-4-6"   # сложные случаи — claude-opus-4-8
api_key  = ""

[metadata.tmdb]
enabled = true
api_key = ""

[metadata.tvdb]
enabled = false
api_key = ""

[recognition]
auto_confidence_threshold = 0.85

[telegram]
enabled          = false
token            = ""
allowed_user_ids = []

[http]
listen = ":8080"

[log]
level  = "info"
format = "json"

Логирование

Структурированный JSON через log/slog. Каждая загрузка проходит со сквозным идентификатором; решения распознавания (почему авто/ревью) логируются явно.

Раскладка файлов

Хардлинки в paths.movies / paths.series по конвенциям Jellyfin. Детали и крайние случаи — в jellyfin-layout.md. Требование: downloads и media на одной ФС (иначе хардлинк невозможен). Если jellybit в docker — смонтировать общего родителя, чтобы хардлинк работал внутри контейнера.

Предполагаемая структура репозитория

cmd/jellybit/         точка входа, сборка зависимостей
internal/
  ingest/  qbt/  worker/  recognize/  metadata/
  layout/  store/  httpapi/  tgbot/  config/
migrations/           миграции SQLite
web/templates/        шаблоны веб-UI
docs/                 specs / adr / drafts
config.example.toml

Открытые вопросы

  • Подтвердить, что /srv/downloads и /srv/media — одна ФС.
  • Способ детекта завершения: поллинг (старт) или webhook qBittorrent «run on completion» (позже).
  • Где хранить секреты при деплое (шаблонизация из umbar).