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 / completed —
workerполлит qBittorrent по категории. - recognizing —
recognizeстроит план раскладки и оценку уверенности (см. recognition.md). - review — план уходит человеку (веб-UI / Telegram), ждём решения.
- linking —
layoutсоздаёт хардлинки в библиотеке. - done — опционально дёргаем скан библиотеки Jellyfin.
Состояние персистентно в SQLite — перезапуск сервиса безопасен, worker
продолжает с того же места.
Транспорты
Все три ведут в один Ingest(req):
- HTTP API + веб-UI — форма «добавить», список загрузок, экран подтверждения раскладки (server-rendered + htmx, без JS-сборки).
- Telegram-бот — переслать magnet или сообщение торрент-бота прямо в jellybit; текст становится контекстом распознавания.
- CLI —
jellybit 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).