Response
{
"status": "ok",
"stats": {
"torrents": 182540,
"files": 1248301,
"scan_paths": 3
}
}
Серверная утилита на Python: индексирует .torrent-файлы трекера и отдаёт пользователям готовые раздачи по сигнатурам их медиатеки. Этот документ — единый источник правды по установке, конфигурации и эксплуатации.
apt install python3-tk.torrent-файлами трекераПитон-зависимости из requirements.txt:
bencodepy # парсинг .torrent fastapi # HTTP API uvicorn # ASGI-сервер pydantic # валидация запросов watchdog # inotify/real-time мониторинг папок
# клонировать репозиторий и перейти в папку утилиты cd reseeder_api # создать изолированную среду python3 -m venv .venv source .venv/bin/activate # установить зависимости pip install -r requirements.txt
# 1. Первичное сканирование папки(ок) с .torrent файлами python -m reseeder_api --scan /var/trackers/torrents # 2. Проверить что получилось python -m reseeder_api --stats # 3. Запустить API сервер python -m reseeder_api --serve --host 0.0.0.0 --port 8080
Документация API доступна на http://<host>:8080/docs (Swagger UI).
python -m reseeder_api # GUI (Tkinter) python -m reseeder_api --scan PATH [PATH…] # сканирование путей python -m reseeder_api --stats # статистика БД python -m reseeder_api --watch # фоновый мониторинг python -m reseeder_api --serve [--host H] [--port P] # HTTP API сервер python -m reseeder_api --backup # создать бэкап БД сейчас python -m reseeder_api --backup-list # список существующих бэкапов python -m reseeder_api --restore /path/to/backup.db # восстановить БД из бэкапа python -m reseeder_api --db /path/to/custom.db … # другой путь к БД
--scan и --stats можно комбинировать. --serve блокирующий.
По умолчанию reseeder_api.db (SQLite) создаётся в рабочей директории, откуда запущен процесс. Для production рекомендуется фиксированный путь:
python -m reseeder_api --db /var/lib/reseeder_api/reseeder_api.db --serve
Схема включает 5 таблиц: torrents, torrent_files, scan_paths, match_log, settings. Все создаются автоматически при первом запуске.
Ограничений по info_hash нет: если один и тот же торрент лежит в нескольких папках — в БД попадут все копии. Матчер в ответе клиенту дедуплицирует по info_hash автоматически.
Хранятся в таблице settings, редактируются через GUI или SQL. Дефолты создаются при первом запуске.
| Параметр | Дефолт | Описание |
|---|---|---|
| min_file_size | 104857600 (100 МБ) | Передаётся клиенту в handshake. Клиент сам фильтрует свои медиафайлы перед отправкой. Не влияет на индексацию — в БД попадают все файлы любого размера. |
| max_files_per_request | 10000 | Максимум файлов в одном запросе от клиента. |
| max_torrents_per_response | 500 | Максимум .torrent в одном ответе. |
| watch_interval_sec | 60 | Интервал polling-fallback для watcher, если watchdog недоступен. |
| log_level | info | debug / info / warn / error. |
| log_file | reseeder_api.log | Путь к файлу логов. |
| db_path | reseeder_api.db | Путь к SQLite. Переопределяется флагом --db. |
| hash_duplicates_log | 0 | Если 1 — при сканировании считается SHA1 каждого .torrent, дубликаты логируются группами. По умолчанию выключено (удлиняет скан на больших коллекциях). |
| backup_interval_hours | 0 | Интервал авто-бэкапа БД в часах. 0 = выключено. Бэкап делается онлайн (SQLite Backup API), не блокирует API-сервер и watcher. |
| backup_dir | backups | Папка для бэкапов. Относительный путь разрешается относительно каталога БД (db_path). Для production обычно абсолютный: /var/lib/reseeder_api/backups. |
| backup_keep | 7 | Сколько последних бэкапов хранить. Старые удаляются автоматически после создания нового. |
Изменить значение напрямую через SQL:
sqlite3 reseeder_api.db "UPDATE settings SET value='20000' WHERE key='max_files_per_request'"
python -m reseeder_api --scan /path/to/torrents
Рекурсивный обход, парсинг .torrent через bencode, вычисление info_hash, запись в БД. Инкрементально: повторный запуск обработает только новые/изменённые/удалённые файлы (сравнение по mtime).
python -m reseeder_api --watch
Мониторит папки, отслеживает создание, удаление, переименование, изменение .torrent файлов в реальном времени. На Linux использует inotify через watchdog. Если watchdog не установлен — polling с интервалом watch_interval_sec.
created / modified — перепарс файла и запись в БД (новый или обновление)deleted — удаление записи из БДmoved (rename) — удаление по старому пути + добавление по новомуКаждое событие обрабатывается немедленно. При modified сравнивается mtime — если не изменился, парсинг пропускается. Если во время копирования большого файла событие приходит раньше, чем файл дописан — парсер вернёт error, но это безвредно: следующее modified (по завершении записи) корректно добавит торрент.
Добавляются через GUI (вкладка «Сканирование») или напрямую в БД:
sqlite3 reseeder_api.db "INSERT INTO scan_paths(path, enabled) VALUES('/var/trackers/torrents', 1)"
Все запросы — application/json, все ответы — JSON. Авторизация и rate-limit делегируются трекеру (через reverse-proxy или middleware).
{
"status": "ok",
"stats": {
"torrents": 182540,
"files": 1248301,
"scan_paths": 3
}
}
Клиент получает параметры утилиты, чтобы знать ограничения перед отправкой файлов. Авторизация и контроль доступа — ответственность трекера, утилита не ограничивает запросы.
{"user_id": "12345"}
{
"status": "ok",
"min_file_size": 104857600,
"max_files_per_request": 10000,
"max_torrents_per_response": 500
}
user_id — передаётся трекером, используется только для логирования в match_log (статистика: кто сколько сматчил).
{
"user_id": "12345",
"phase": 1,
"files": [
{"name": "movie.mkv", "size": 4294967296},
{"name": "show.s01e01.mkv", "size": 1073741824}
]
}
{
"status": "ok",
"matched_torrents": [
{
"torrent_id": 42,
"info_hash": "abc123...",
"name": "Movie Name",
"torrent_file": "<base64 .torrent>"
}
],
"matched_files_count": 1
}
{
"user_id": "12345",
"phase": 2,
"files": [{"size": 4294967296}],
"exclude_torrent_ids": [42, 55]
}
exclude_torrent_ids — список id торрентов, которые уже были отданы в фазе 1 этой же сессии. Сервер их не повторит.
{
"status": "ok",
"matched_torrents": [ ... ],
"matched_files_count": 3
}
Клиент отправляет результат матча — что было успешно подтверждено. Сервер логирует для статистики (ретеншн, популярные раздачи). Не влияет на работу клиента.
{
"user_id": "12345",
"confirmed": [{"info_hash": "abc123...", "pieces_verified": 12}],
"rejected": [{"info_hash": "def456..."}]
}
Структура тела произвольная — сервер принимает любой JSON и пишет в лог.
{"status": "ok"}
{"status": "error", "code": "TOO_MANY_FILES", "message": "Максимум 10000 файлов…"}
{"status": "error", "code": "INVALID_REQUEST", "message": "..."}
{"status": "error", "code": "SERVER_ERROR", "message": "..."}
HTTP-статус — 400 для ошибок валидации/бизнес-логики, 500 для необработанных исключений.
/etc/systemd/system/reseeder-api.service:
[Unit]
Description=ReSeeder API - tracker matching utility
After=network.target
[Service]
Type=simple
User=reseeder
Group=reseeder
WorkingDirectory=/opt/reseeder_api
ExecStart=/opt/reseeder_api/.venv/bin/python -m reseeder_api \
--db /var/lib/reseeder_api/reseeder_api.db \
--serve --host 127.0.0.1 --port 8080
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
/etc/systemd/system/reseeder-watch.service — отдельный сервис для real-time мониторинга:
[Unit]
Description=ReSeeder API - torrent folder watcher
After=network.target
[Service]
Type=simple
User=reseeder
Group=reseeder
WorkingDirectory=/opt/reseeder_api
ExecStart=/opt/reseeder_api/.venv/bin/python -m reseeder_api \
--db /var/lib/reseeder_api/reseeder_api.db --watch
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo useradd -r -s /bin/false reseeder sudo mkdir -p /var/lib/reseeder_api sudo chown reseeder:reseeder /var/lib/reseeder_api sudo systemctl daemon-reload sudo systemctl enable --now reseeder-api reseeder-watch
location /reseeder_api/ {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# rate-limit и авторизацию добавляйте здесь
}
Юзер reseeder должен иметь read на папки с .torrent файлами трекера и read/write на /var/lib/reseeder_api/.
При сотнях тысяч .torrent-файлов (и их папок) стандартного лимита может не хватить. Проверить:
cat /proc/sys/fs/inotify/max_user_watches
Увеличить:
echo "fs.inotify.max_user_watches=524288" | sudo tee /etc/sysctl.d/90-reseeder.conf sudo sysctl -p /etc/sysctl.d/90-reseeder.conf
Если увеличивать нельзя — отключите watch-сервис и используйте периодический --scan по cron:
*/15 * * * * /opt/reseeder_api/.venv/bin/python -m reseeder_api \
--db /var/lib/reseeder_api/reseeder_api.db --scan /var/trackers/torrents
Помимо встроенного авто-бэкапа (см. ниже):
sqlite3 /var/lib/reseeder_api/reseeder_api.db ".backup /backup/reseeder_api.db"
На десктопе (Windows / Linux с X11):
python -m reseeder_api
Пять вкладок:
piece_lengthmin_file_size задаётся и отображается в МБ. hash_duplicates_log — чекбоксGUI не нужен для production — все функции доступны через CLI и БД напрямую.
Утилита умеет делать горячий бэкап БД (через SQLite Online Backup API — безопасен во время активных запросов), хранить историю, автоматически ротировать и восстанавливать.
Настраивается тремя параметрами (раздел 6):
backup_interval_hours — интервал в часах (0 = выключено)backup_dir — папка для бэкаповbackup_keep — сколько последних файлов хранитьТаймер запускается автоматически вместе с --serve, --watch и GUI. Каждые 60 секунд проверяет настройки и при наступлении времени делает бэкап, затем удаляет старые файлы сверх лимита.
Имя файла бэкапа: reseeder_api_YYYYMMDD_HHMMSS.db — таймштамп легко сортируется.
backup_interval_hours=6, backup_keep=14 — каждые 6 часов, две недели истории.backup_interval_hours=24, backup_keep=7.backup_keep=1 и отдавать ротацию внешней системе.CLI:
python -m reseeder_api --backup python -m reseeder_api --backup-list
GUI: вкладка Бэкап → «Создать бэкап сейчас». Там же список всех существующих бэкапов с датой и размером.
CLI (рекомендуется для production):
# Остановите сервис перед восстановлением
sudo systemctl stop reseeder-api reseeder-watch
python -m reseeder_api --db /var/lib/reseeder_api/reseeder_api.db \
--restore /var/lib/reseeder_api/backups/reseeder_api_20260405_153000.db
sudo systemctl start reseeder-api reseeder-watch
Спросит подтверждение [y/N]. После y заменит текущую БД файлом бэкапа (copy2 — работает одинаково на Linux и Windows).
GUI: вкладка Бэкап → выбрать строку → «Восстановить выбранный». GUI остановит watcher/backup-timer, перезапишет БД и закроет окно — запустите утилиту заново.
backup_dir абсолютный путь (/var/lib/reseeder_api/backups) — используется как есть.backup_dir относительный (дефолт backups) — разрешается от каталога, где лежит файл БД:
/var/lib/reseeder_api/reseeder_api.db → /var/lib/reseeder_api/backups/D:\reseeder_api\reseeder_api.db → D:\reseeder_api\backups\Такое поведение делает путь одинаковым на обеих ОС — не нужно переопределять настройки при переносе.
-wal, -shm, -journal рядом с БД перед копированием — иначе SQLite может смешать старые незафиксированные транзакции с восстановленными данными. Учтено в --restore и кнопке восстановления в GUI.
Scan complete: +0 new, ~0 updated, -0 removed, err=Nerr — количество .torrent-файлов, которые не удалось распарсить. Причины:
info словаряВключите log_level=debug и пересканируйте — в логе будут конкретные пути.
watchdog установлен: pip list | grep watchdogWatcher started (polling) если watchdog упал — разберитесь почемуdatabase is locked)WAL-режим должен это предотвращать. Если всё равно возникает — проверьте, что нет второго процесса, пишущего в ту же БД с отключённым WAL.
reseeder_api/ ├── __init__.py ├── __main__.py ├── reseeder_tool.py # CLI + GUI entry point ├── config.py # настройки, дефолты ├── logger.py # логирование ├── database.py # SQLite: схема, CRUD, матч-запросы, backup_to ├── scanner.py # парсер .torrent, синхронизация БД ├── matcher.py # фаза 1/2, handshake, payload validation ├── watcher.py # inotify/polling мониторинг, мгновенная обработка ├── backup.py # авто-бэкап, ротация, восстановление (cross-platform) ├── api.py # FastAPI сервер ├── gui.py # Tkinter GUI (5 вкладок) ├── requirements.txt └── README.md
Архив содержит все исходники Python-утилиты и requirements.txt. MIT-лицензия — используйте и модифицируйте свободно.
Вопросы по интеграции — на странице для трекеров.