- Раскладка docs/ приведена к канону 2: заведены passport/architecture/ database/security/review и research; docs/specs, drafts, backlog, review/ и BRIEF.md разобраны и удалены, беклог переехал в docs/tasks (34 задачи, 6 целей, слаги на английский). - Нарративы specs удалены как дубли openspec-спек после поимённой сверки; остаток заведён задачами (редактор маппинга ревью, крайние случаи именования), отказ от сущности title промоутнут в ADR. - Проектные копии агентов и скиллов ревью/пайплайна удалены в пользу плагинов av-dev-pm и av-dev-pipeline; в task gate добавлен шаг canon вместо er-schema.
134 lines
8.7 KiB
Markdown
134 lines
8.7 KiB
Markdown
# Jellybit
|
|
|
|
Jellybit — связующий сервис между qBittorrent и Jellyfin. Принимает
|
|
magnet-ссылку или `.torrent`-файл вместе с текстовым контекстом, ставит загрузку в
|
|
qBittorrent, дожидается её завершения, распознаёт содержимое (фильм или
|
|
сериал, сезоны и серии) и раскладывает готовые файлы по конвенциям
|
|
библиотеки Jellyfin.
|
|
|
|
Полный замысел, границы домена и типовые сценарии — в
|
|
[docs/passport.md](docs/passport.md).
|
|
|
|
## Зачем
|
|
|
|
Arr-стек (prowlarr/radarr/sonarr) плохо ложится на русские трекеры,
|
|
аниме и ручные раздачи. Jellybit намеренно сокращает путь: одна точка
|
|
входа → готовая раскладка для Jellyfin, без каталога индексаторов и
|
|
сложных правил качества. Распознавание делает LLM, которому помогает
|
|
переданный человеком контекст и (опционально) внешние базы метаданных.
|
|
|
|
## Как работает
|
|
|
|
1. Точка входа принимает magnet + контекст (HTTP API, веб-UI,
|
|
Telegram-бот или CLI).
|
|
2. Загрузка ставится в qBittorrent в выделенную категорию.
|
|
3. Сервис отслеживает завершение загрузки.
|
|
4. По именам файлов, контексту и (опц.) базам метаданных определяется
|
|
фильм/сериал и нужная раскладка.
|
|
5. Файлы **хардлинкаются** в библиотеку Jellyfin — источник остаётся в
|
|
раздаче, место на диске не дублируется.
|
|
6. После раскладки сервис (опц.) просит Jellyfin пересканировать
|
|
медиатеку, чтобы новые файлы быстрее появились в проигрывателе.
|
|
|
|
При высокой уверенности раскладка выполняется автоматически, иначе —
|
|
уходит на подтверждение человеку.
|
|
|
|
## Статус
|
|
|
|
Рабочий прототип с полным сквозным путём: приём magnet → загрузка в
|
|
qBittorrent → распознавание (LLM + опционально базы метаданных
|
|
TMDB/TVDB/TVMaze) → раскладка в библиотеку хардлинками, автоматически при
|
|
уверенном результате либо через подтверждение человеком. Транспорты приёма:
|
|
REST API, веб-UI, Telegram-бот и CLI (`jellybit add`).
|
|
|
|
Из источников поддержаны magnet и `.torrent`-файл; фетч `.torrent` по обычной
|
|
ссылке — в планах. Что дальше — [docs/tasks/PLAN.md](docs/tasks/PLAN.md).
|
|
|
|
## Документация
|
|
|
|
Разработка идёт по **Spec-Driven Development** через
|
|
[OpenSpec](https://github.com/Fission-AI/OpenSpec): изменение сначала
|
|
описывается спекой, потом реализуется.
|
|
|
|
- [openspec/specs/](openspec/specs/) — **что система делает**, нормативно:
|
|
capability-спеки. Изменения (proposal → design → tasks → archive) — в
|
|
`openspec/changes/`.
|
|
- [docs/passport.md](docs/passport.md) — зачем и для кого, чем **не** является.
|
|
- [docs/architecture.md](docs/architecture.md) — как сложено: компоненты,
|
|
внешние границы, эксплуатация, единые точки, деплой.
|
|
- [docs/database.md](docs/database.md) — схема хранилища и настройки.
|
|
- [docs/security.md](docs/security.md) — периметр и модель угроз.
|
|
- [docs/conventions/](docs/conventions/README.md) — как пишем код:
|
|
[логи](docs/conventions/logging.md), [ошибки](docs/conventions/errors.md),
|
|
[конфиг](docs/conventions/config.md), [БД](docs/conventions/database.md),
|
|
[веб-UI](docs/conventions/web-ui.md).
|
|
- [docs/adr/](docs/adr/README.md) — журнал решений (почему так), неизменяемый.
|
|
- [docs/research/](docs/research/README.md) — наблюдения за чужими форматами.
|
|
- [docs/tasks/](docs/tasks/BACKLOG.md) — задачи и цели.
|
|
|
|
Раскладка документации задана каноном av-dev и проверяется шагом `canon` в
|
|
`task gate`.
|
|
|
|
## Стек
|
|
|
|
Go (один статический бинарь), SQLite (`modernc.org/sqlite` + `sqlx`,
|
|
миграции `goose`), HTTP — `chi` + `html/template` + htmx, конфигурация —
|
|
TOML, логи — структурированный JSON (`slog`). Подробнее — в
|
|
[docs/architecture.md](docs/architecture.md).
|
|
|
|
## Конфигурация
|
|
|
|
Конфигурация — один файл TOML. По умолчанию ищется `config.toml` в рабочей
|
|
директории; путь переопределяется опцией `--config=path`. Образец со всеми
|
|
секциями и описанием каждого поля (назначение, диапазон значений, единицы
|
|
измерения) — [config.example.toml](config.example.toml); скопируй его в
|
|
`config.toml` и заполни под себя. Конфиг валидируется на старте: при
|
|
ошибке сервис не стартует.
|
|
|
|
Секреты (пароль qBittorrent, ключи LLM/метабаз, токен Telegram) в репозиторий
|
|
не коммитятся — их подставляет деплой прямо в файл. Доступ к внешним сервисам
|
|
(LLM, базы метаданных, Telegram) при необходимости идёт через HTTP-прокси —
|
|
поле `proxy` в соответствующих секциях. Правила — в
|
|
[docs/conventions/config.md](docs/conventions/config.md).
|
|
|
|
## Разработка
|
|
|
|
Нужны Go 1.26 и [Task](https://taskfile.dev). Полный список задач —
|
|
`task --list`.
|
|
|
|
```bash
|
|
cp config.example.toml config.toml # локально: db_path -> ./jellybit.db
|
|
task setup # golangci-lint + git-хуки lefthook
|
|
task tidy # go mod tidy
|
|
task run # go run ./cmd/jellybit --config ./config.toml
|
|
task test lint # тесты и golangci-lint
|
|
task build # статический бинарь (linux/amd64) для сервера
|
|
task image # docker-образ из готового бинаря
|
|
```
|
|
|
|
Отладка распознавания на реальной раздаче (только чтение, без раскладки):
|
|
|
|
```bash
|
|
jellybit recognize <infohash> --dry-run [--context "..."] --config ./config.toml
|
|
```
|
|
|
|
Берёт торрент из qBittorrent по infohash, прогоняет распознавание (LLM +
|
|
метабазы) и печатает план: тип/название/год, матч в базе, решение авто/review
|
|
и превью целевых путей — то, что создалось бы при Apply.
|
|
|
|
## Доставка
|
|
|
|
Рассчитан на домашний медиа-сервер. Артефакты репозитория — статический
|
|
бинарь (`task build`) и `Dockerfile` (упаковка в `distroless/static`). Образ
|
|
собирается целиком **локально** на control-хосте (`task image`) и едет на
|
|
сервер через `docker save`/`load` (роль `app_image` в umbar), поэтому
|
|
Go-тулчейн и `docker build` на сервере не нужны. В distroless нет shell/curl,
|
|
поэтому HEALTHCHECK зовёт сам бинарь: `jellybit healthcheck` (GET `/healthz`
|
|
по порту из конфига, exit 0/1).
|
|
|
|
Контейнер: `user 1000:1000`, порт `8080` на хост, mount `/srv/media` (единая
|
|
песочница для хардлинков) + том `/config` (ro, `config.toml`, восстановим при
|
|
деплое) + data-том `/data` (SQLite, бекапить); к qBittorrent — по сети Docker.
|
|
Конкретная деплой-обвязка (плейбук, секреты) держится в отдельном приватном
|
|
репозитории и в комплект не входит.
|