From bd81e88e68308e2359f34543b827d8fbc15add72 Mon Sep 17 00:00:00 2001 From: Struchkov Mark Date: Thu, 4 Dec 2025 19:08:10 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BC=D0=BE=D0=BD=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D0=BD?= =?UTF-8?q?=D0=B3=20=D0=B7=D0=B0=D0=B2=D0=B5=D1=80=D1=88=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D1=82=D0=BE=D1=80=D1=80=D0=B5=D0=BD=D1=82=D0=BE=D0=B2?= =?UTF-8?q?=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20RPC=E2=80=91=D0=BE=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавлена функция monitorTorrentCompletion для проверки состояния торрента каждые 10 секунд. Добавлена структура torrentState для отслеживания состояния торрентов и определения их завершения. Обновлена основная логика для работы с chat ID при отправке уведомлений. Улучшен README — добавлены сведения об автоматических уведомлениях о завершении загрузки и методах мониторинга. --- README.md | 198 +++++++++++++++++++++++++++++++++++++++++++++++++----- main.go | 80 +++++++++++++++++++++- 2 files changed, 261 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 28bb534..b2e968f 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,38 @@ # transmission-telegram -#### Manage your transmission through Telegram. +#### Управляйте Transmission через Telegram. ## CLI -### Install +### Установка -Just [download](https://github.com/pyed/transmission-telegram/releases) the appropriate binary for your OS, place `transmission-telegram` in your `$PATH` and you are good to go. +Просто [скачайте](https://github.com/pyed/transmission-telegram/releases) подходящий бинарный файл для вашей ОС, поместите `transmission-telegram` в ваш `$PATH` и готово. -Or if you have `Go` installed: `go get -u github.com/pyed/transmission-telegram` +Или, если у вас установлен `Go`: `go get -u github.com/pyed/transmission-telegram` -## Usage +## Использование [Wiki](https://github.com/pyed/transmission-telegram/wiki) - -## Docker Alternate Installation Route +## Установка через Docker ### Standalone -``` +```bash docker run -d --name transmission-telegram \ kevinhalpin/transmission-telegram:latest \ --token= \ --master= \ +-token=<Ваш Токен Бота> \ +-master=<Ваш Username> \ -url= \ --username= \ --password= +-username= \ +-password= ``` -### docker-compose Example +### Пример docker-compose -``` +```yaml version: '2.4' services: transmission: @@ -57,5 +56,174 @@ telegram-transmission-bot: - emby network_mode: 'host' image: kevinhalpin/transmission-telegram:latest - command: '-token=${TELEGRAM_TRANSMISSION_BOT} -master=${TELEGRAM_USERNAME} -url=${TRANSMISSION_URL} - username=${TRANSMISSION_USERNAME} -password=${PASS}' + command: '-token=${TELEGRAM_TRANSMISSION_BOT} -master=${TELEGRAM_USERNAME} -url=${TRANSMISSION_URL} -username=${TRANSMISSION_USERNAME} -password=${PASS}' ``` + +## Возможности + +Этот проект представляет собой Telegram-бота для управления клиентом BitTorrent Transmission. Бот позволяет: + +- **Просмотр торрентов**: список всех торрентов, фильтрация по статусу (загрузка, раздача, на паузе, проверка), поиск по имени или трекеру +- **Управление торрентами**: добавление (по URL, magnet-ссылке или файлу .torrent), запуск, остановка, удаление, проверка целостности +- **Мониторинг**: просмотр статистики, скорости загрузки/отдачи, информации о конкретных торрентах с live-обновлениями +- **Настройки**: установка лимитов скорости, изменение директории загрузки, сортировка торрентов +- **Уведомления**: автоматические уведомления о завершении загрузок через мониторинг RPC API (работает автоматически, без дополнительной настройки) + +Бот работает только с авторизованными пользователями (masters), что обеспечивает безопасность управления вашими торрентами. + +## Настройка уведомлений о завершении загрузок + +Бот автоматически отправляет уведомления в Telegram, когда торрент завершает загрузку. Для этого используется **мониторинг через RPC API** (рекомендуемый метод), который работает без дополнительной настройки. + +### Метод 1: Мониторинг через RPC API (рекомендуется) ⭐ + +Этот метод работает автоматически и не требует дополнительной настройки. Бот периодически опрашивает Transmission через RPC API и отслеживает изменение статуса торрентов с "Загрузка" на "Раздача". + +#### Как это работает + +1. **Автоматический запуск**: Мониторинг запускается автоматически при старте бота +2. **Polling**: Бот опрашивает статус торрентов каждые 10 секунд через RPC API +3. **Обнаружение завершения**: При переходе торрента из статуса "Downloading" в "Seeding" (или при достижении 100% загрузки) отправляется уведомление +4. **Активация**: Отправьте боту любое сообщение (например, `/help`), чтобы он запомнил ваш chat ID для отправки уведомлений + +#### Преимущества + +- ✅ Не требует доступа к файловой системе +- ✅ Не требует настройки логирования в Transmission +- ✅ Работает в любой конфигурации (Docker, standalone, и т.д.) +- ✅ Более надежный и быстрый метод +- ✅ Не зависит от формата логов + +#### Пример уведомления + +Когда торрент завершит загрузку, вы получите сообщение вида: +``` +✅ Completed: My-Torrent-Name +``` + +### Метод 2: Мониторинг через лог-файл (альтернативный) + +Альтернативный метод - мониторинг лог-файла Transmission. Этот метод требует дополнительной настройки, но может быть полезен в некоторых случаях. + +#### Шаг 1: Включение логирования в Transmission + +1. Откройте настройки Transmission (через веб-интерфейс или конфигурационный файл `settings.json`) +2. Включите логирование, установив параметр `"message-level": 2` (или выше) в `settings.json` +3. Убедитесь, что логирование включено: `"logging-enabled": true` + +Для Docker-контейнера Transmission (linuxserver/transmission) логи обычно находятся в: +- `/config/transmission.log` (внутри контейнера) +- `${CONFIG}/transmission/transmission.log` (на хосте, если смонтирован volume) + +**Пример настройки в `settings.json`:** +```json +{ + "logging-enabled": true, + "message-level": 2 +} +``` + +#### Шаг 2: Настройка бота для мониторинга логов + +Добавьте параметр `-transmission-logfile` с путем к лог-файлу Transmission при запуске бота. + +#### Для CLI: + +```bash +transmission-telegram \ + -token=<Ваш Токен Бота> \ + -master=<Ваш Username> \ + -url= \ + -transmission-logfile=/path/to/transmission.log +``` + +#### Для Docker Standalone: + +```bash +docker run -d --name transmission-telegram \ + -v /path/to/transmission.log:/transmission.log:ro \ + kevinhalpin/transmission-telegram:latest \ + -token=<Ваш Токен Бота> \ + -master=<Ваш Username> \ + -url= \ + -transmission-logfile=/transmission.log +``` + +#### Для docker-compose: + +```yaml +version: '2.4' +services: + transmission: + container_name: transmission + environment: + - PUID=${PUID_DOCKUSER} + - PGID=${PGID_APPZ} + image: linuxserver/transmission + network_mode: 'host' + hostname: 'transmission' + volumes: + - ${CONFIG}/transmission:/config + - ${DATA}/transmission/downloads:/downloads + + telegram-transmission-bot: + container_name: telegram-transmission-bot + restart: on-failure + depends_on: + - transmission + network_mode: 'host' + image: kevinhalpin/transmission-telegram:latest + volumes: + - ${CONFIG}/transmission/transmission.log:/transmission.log:ro + command: > + -token=${TELEGRAM_TRANSMISSION_BOT} + -master=${TELEGRAM_USERNAME} + -url=${TRANSMISSION_URL} + -username=${TRANSMISSION_USERNAME} + -password=${PASS} + -transmission-logfile=/transmission.log +``` + +#### Шаг 3: Активация уведомлений + +**Важно**: После запуска бота с параметром `-transmission-logfile`, отправьте боту любое сообщение (например, `/help` или `list`). Это необходимо для того, чтобы бот запомнил ваш chat ID и мог отправлять уведомления. + +#### Как это работает + +Бот мониторит указанный лог-файл в реальном времени и ищет строки с паттерном `"Incomplete" to "Complete"`, которые Transmission записывает при завершении загрузки торрента. При обнаружении такой строки бот автоматически извлекает имя завершенного торрента и отправляет уведомление в Telegram. + +**Пример строки в логе Transmission:** +``` +[2017-02-22 21:00:00.898] My-Torrent-Name State changed from "Incomplete" to "Complete" (torrent.c:2218) +``` + +### Устранение проблем + +#### Устранение проблем (метод через лог-файл) + +- **Уведомления не приходят**: + - Убедитесь, что логирование включено в Transmission (`logging-enabled: true`) + - Проверьте, что путь к лог-файлу указан правильно + - Убедитесь, что бот имеет доступ на чтение к лог-файлу + - Отправьте боту сообщение после запуска, чтобы он запомнил ваш chat ID + +- **Лог-файл не найден**: + - Проверьте путь к файлу в настройках Transmission + - Для Docker: убедитесь, что volume с лог-файлом смонтирован правильно + - Проверьте права доступа к файлу + +- **Бот не видит изменения в логе**: + - Убедитесь, что Transmission действительно пишет в указанный файл + - Проверьте уровень логирования (`message-level` должен быть 2 или выше) + +#### Устранение проблем (метод через RPC API) + +- **Уведомления не приходят**: + - Убедитесь, что бот имеет доступ к Transmission RPC API + - Проверьте, что Transmission работает и доступен по указанному URL + - Отправьте боту сообщение после запуска, чтобы он запомнил ваш chat ID + - Проверьте логи бота на наличие ошибок подключения к Transmission + +- **Задержка уведомлений**: + - Бот опрашивает статус каждые 10 секунд, поэтому может быть небольшая задержка + - Это нормальное поведение и не требует настройки diff --git a/main.go b/main.go index 64137ec..21756d2 100644 --- a/main.go +++ b/main.go @@ -134,6 +134,9 @@ var ( // chatID will be used to keep track of which chat to send completion notifictions. chatID int64 + // torrentState stores previous state of torrents for completion detection + torrentStates = make(map[int]torrentState) + // logging logger = log.New(os.Stdout, "", log.LstdFlags) @@ -151,6 +154,12 @@ var ( "`", "'") ) +// torrentState stores the state of a torrent for completion detection +type torrentState struct { + Status int + PercentDone float64 +} + // we need a type for masters for the flag package to parse them as a slice type masterSlice []string @@ -303,6 +312,9 @@ func init() { } func main() { + // Start torrent completion monitoring via RPC polling + go monitorTorrentCompletion() + for update := range Updates { // ignore edited messages if update.Message == nil { @@ -315,8 +327,8 @@ func main() { continue } - // update chatID for complete notification - if TransLogFile != "" && chatID != update.Message.Chat.ID { + // update chatID for complete notification (used by both log monitoring and RPC polling) + if chatID != update.Message.Chat.ID { chatID = update.Message.Chat.ID } @@ -1537,6 +1549,70 @@ func getVersion(ud tgbotapi.Update) { send(fmt.Sprintf("Transmission *%s*\nTransmission-telegram *%s*", Client.Version(), VERSION), ud.Message.Chat.ID, true) } +// monitorTorrentCompletion monitors torrents via RPC API polling to detect completion +// It checks for status change from Downloading to Seeding, indicating completion +func monitorTorrentCompletion() { + // Polling interval - check every 10 seconds + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + + logger.Printf("[INFO] Starting torrent completion monitoring via RPC polling") + + for range ticker.C { + // Skip if no chatID is set yet + if chatID == 0 { + continue + } + + // Get current torrents + torrents, err := Client.GetTorrents() + if err != nil { + logger.Printf("[ERROR] Failed to get torrents for monitoring: %s", err) + continue + } + + // Check each torrent for completion + for _, torrent := range torrents { + prevState, exists := torrentStates[torrent.ID] + + // Detect completion: transition from Downloading to Seeding with 100% done + completed := false + if exists && prevState.Status == transmission.StatusDownloading { + // Case 1: Status changed from Downloading to Seeding (most common) + if torrent.Status == transmission.StatusSeeding && torrent.PercentDone >= 1.0 { + completed = true + } + // Case 2: Torrent reached 100% while still in Downloading status + // (status might change to Seeding in next poll) + if torrent.Status == transmission.StatusDownloading && + prevState.PercentDone < 1.0 && + torrent.PercentDone >= 1.0 { + completed = true + } + } + + if completed { + // Send completion notification + msg := fmt.Sprintf("✅ Completed: %s", torrent.Name) + send(msg, chatID, false) + logger.Printf("[INFO] Torrent completed: %s (ID: %d)", torrent.Name, torrent.ID) + } + + // Update state - only track downloading torrents to save memory + if torrent.Status == transmission.StatusDownloading || + torrent.Status == transmission.StatusDownloadPending { + torrentStates[torrent.ID] = torrentState{ + Status: torrent.Status, + PercentDone: torrent.PercentDone, + } + } else { + // Remove completed or stopped torrents from tracking + delete(torrentStates, torrent.ID) + } + } + } +} + // send takes a chat id and a message to send, returns the message id of the send message func send(text string, chatID int64, markdown bool) int { // set typing action