Обновлены зависимости в go.mod, добавлены новые пакеты для улучшения функциональности. В коде Telegram-бота изменены вызовы методов на использование нового стиля именования, улучшена обработка сообщений и логирование. Оптимизированы функции для работы с торрентами, включая обработку ошибок и форматирование сообщений.

This commit is contained in:
Struchkov Mark
2025-12-04 21:43:36 +03:00
parent 21cfe56a0b
commit caeb5f06bd
6 changed files with 117 additions and 104 deletions

View File

@@ -59,17 +59,17 @@ func main() {
cachedClient := transmissionClient.NewCachedClient(transClient, 2*time.Second)
// Initialize Telegram bot
bot, err := tgbotapi.NewBotAPI(cfg.BotToken)
telegramBotAPI, err := tgbotapi.NewBotAPI(cfg.BotToken)
if err != nil {
fmt.Fprintf(os.Stderr, "[ERROR] Telegram: %s\n", err)
os.Exit(1)
}
log.Printf("[INFO] Authorized: %s", bot.Self.UserName)
log.Printf("[INFO] Authorized: %s", telegramBotAPI.Self.UserName)
u := tgbotapi.NewUpdate(0)
u.Timeout = config.TelegramUpdateTimeout
updates, err := bot.GetUpdatesChan(u)
updates, err := telegramBotAPI.GetUpdatesChan(u)
if err != nil {
fmt.Fprintf(os.Stderr, "[ERROR] Telegram: %s\n", err)
os.Exit(1)
@@ -79,7 +79,7 @@ func main() {
mon := monitor.NewMonitor(cachedClient, log, config.DefaultPollInterval)
// Create bot instance first
telegramBot := bot.NewBot(bot, cachedClient, cfg, log, updates, mon)
telegramBot := bot.NewBot(telegramBotAPI, cachedClient, cfg, log, updates, mon)
// Set up completion callback - chatID will be set by bot when user sends first message
mon.SetOnComplete(func(torrent *transmission.Torrent) {

11
go.mod
View File

@@ -4,8 +4,15 @@ go 1.21
require (
github.com/dustin/go-humanize v1.0.1
github.com/pyed/tailer v0.0.0-20180809195549-5c8b5b0b5b5b
github.com/pyed/transmission v0.0.0-20210101100000-000000000000
gopkg.in/telegram-bot-api.v4 v4.6.4
)
require (
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab // indirect
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
github.com/martini-contrib/auth v0.0.0-20150219114609-fa62c19b7ae8 // indirect
github.com/pyed/transmission v0.0.0-20240821061748-4cfdbb917ad4
github.com/smartystreets/goconvey v1.8.1 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
)

View File

@@ -179,8 +179,8 @@ func (b *Bot) getCommandHandler(command string, update tgbotapi.Update, tokens [
"/rm": b.handleDel,
"deldata": b.handleDelData,
"/deldata": b.handleDelData,
"help": func(u tgbotapi.Update, _ []string) { b.sendMessage(u.Message.Chat.ID, HelpText, true) },
"/help": func(u tgbotapi.Update, _ []string) { b.sendMessage(u.Message.Chat.ID, HelpText, true) },
"help": func(u tgbotapi.Update, _ []string) { b.SendMessage(u.Message.Chat.ID, HelpText, true) },
"/help": func(u tgbotapi.Update, _ []string) { b.SendMessage(u.Message.Chat.ID, HelpText, true) },
"version": func(u tgbotapi.Update, _ []string) { b.handleVersion(u) },
"/version": func(u tgbotapi.Update, _ []string) { b.handleVersion(u) },
"ver": func(u tgbotapi.Update, _ []string) { b.handleVersion(u) },
@@ -202,6 +202,9 @@ func (b *Bot) handleUpdate(update tgbotapi.Update) {
}
// Check if user is master
if update.Message.From == nil {
return
}
if !b.cfg.IsMaster(update.Message.From.UserName) {
b.logger.Printf("[INFO] Ignored a message from: %s", update.Message.From.String())
return
@@ -239,7 +242,7 @@ func (b *Bot) handleUpdate(update tgbotapi.Update) {
go b.safeHandler(handler)
} else {
// no such command
go b.safeHandler(func() { b.sendMessage(update.Message.Chat.ID, "No such command, try /help", false) })
go b.safeHandler(func() { b.SendMessage(update.Message.Chat.ID, "No such command, try /help", false) })
}
}

View File

@@ -15,7 +15,6 @@ import (
tgbotapi "gopkg.in/telegram-bot-api.v4"
"transmission-telegram/internal/config"
"transmission-telegram/internal/formatter"
"transmission-telegram/pkg/utils"
)
const (
@@ -76,7 +75,11 @@ func getCompiledRegex(pattern string) (*regexp.Regexp, error) {
select {
case <-ctx.Done():
return nil, fmt.Errorf("regex compilation timeout (pattern may be too complex): %s", pattern[:min(len(pattern), 50)])
patternPreview := pattern
if len(patternPreview) > 50 {
patternPreview = patternPreview[:50]
}
return nil, fmt.Errorf("regex compilation timeout (pattern may be too complex): %s", patternPreview)
case res := <-resultCh:
if res.err != nil {
return nil, fmt.Errorf("regex compilation error: %w", res.err)
@@ -86,8 +89,8 @@ func getCompiledRegex(pattern string) (*regexp.Regexp, error) {
}
}
// min returns the minimum of two integers
func min(a, b int) int {
// minInt returns the minimum of two integers
func minInt(a, b int) int {
if a < b {
return a
}
@@ -117,7 +120,7 @@ func putBuffer(buf *bytes.Buffer) {
func (b *Bot) handleClientError(chatID int64, prefix string, err error) {
if err != nil {
b.logger.Printf("[ERROR] %s: %v", prefix, err)
b.sendMessage(chatID, prefix+": "+err.Error(), false)
b.SendMessage(chatID, prefix+": "+err.Error(), false)
}
}
@@ -132,16 +135,16 @@ func (b *Bot) handleTorrentList(update tgbotapi.Update, errorPrefix, emptyMessag
buf := getBuffer()
defer putBuffer(buf)
for i := range torrents {
if filter(&torrents[i]) {
buf.WriteString(format(&torrents[i]))
if filter(torrents[i]) {
buf.WriteString(format(torrents[i]))
}
}
if buf.Len() == 0 {
b.sendMessage(update.Message.Chat.ID, emptyMessage, false)
b.SendMessage(update.Message.Chat.ID, emptyMessage, false)
return
}
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
b.SendMessage(update.Message.Chat.ID, buf.String(), false)
}
// Handler methods for bot commands - these are placeholders that need full implementation
@@ -176,14 +179,14 @@ func (b *Bot) handleList(update tgbotapi.Update, tokens []string) {
if buf.Len() == 0 {
if len(tokens) != 0 {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*list:* No tracker matches: *%s*", tokens[0]), true)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*list:* No tracker matches: *%s*", tokens[0]), true)
return
}
b.sendMessage(update.Message.Chat.ID, "*list:* no torrents", false)
b.SendMessage(update.Message.Chat.ID, "*list:* no torrents", false)
return
}
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
b.SendMessage(update.Message.Chat.ID, buf.String(), false)
}
func (b *Bot) handleHead(update tgbotapi.Update, tokens []string) {
@@ -207,15 +210,15 @@ func (b *Bot) handleHead(update tgbotapi.Update, tokens []string) {
buf := getBuffer()
defer putBuffer(buf)
for i := range torrents[:n] {
buf.WriteString(formatter.FormatTorrentDetailed(&torrents[i]))
buf.WriteString(formatter.FormatTorrentDetailed(torrents[i]))
}
if buf.Len() == 0 {
b.sendMessage(update.Message.Chat.ID, "*head:* no torrents", false)
b.SendMessage(update.Message.Chat.ID, "*head:* no torrents", false)
return
}
msgID := b.sendMessage(update.Message.Chat.ID, buf.String(), true)
msgID := b.SendMessage(update.Message.Chat.ID, buf.String(), true)
if !b.cfg.NoLive {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(b.cfg.Duration)*b.cfg.Interval+time.Second)
defer cancel()
@@ -249,15 +252,15 @@ func (b *Bot) handleTail(update tgbotapi.Update, tokens []string) {
buf := getBuffer()
defer putBuffer(buf)
for _, torrent := range torrents[len(torrents)-n:] {
buf.WriteString(formatter.FormatTorrentDetailed(&torrent))
buf.WriteString(formatter.FormatTorrentDetailed(torrent))
}
if buf.Len() == 0 {
b.sendMessage(update.Message.Chat.ID, "*tail:* no torrents", false)
b.SendMessage(update.Message.Chat.ID, "*tail:* no torrents", false)
return
}
msgID := b.sendMessage(update.Message.Chat.ID, buf.String(), true)
msgID := b.SendMessage(update.Message.Chat.ID, buf.String(), true)
if !b.cfg.NoLive {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(b.cfg.Duration)*b.cfg.Interval+time.Second)
defer cancel()
@@ -324,16 +327,16 @@ func (b *Bot) handleActive(update tgbotapi.Update) {
defer putBuffer(buf)
for i := range torrents {
if torrents[i].RateDownload > 0 || torrents[i].RateUpload > 0 {
buf.WriteString(formatter.FormatTorrentDetailed(&torrents[i]))
buf.WriteString(formatter.FormatTorrentDetailed(torrents[i]))
}
}
if buf.Len() == 0 {
b.sendMessage(update.Message.Chat.ID, "No active torrents", false)
b.SendMessage(update.Message.Chat.ID, "No active torrents", false)
return
}
msgID := b.sendMessage(update.Message.Chat.ID, buf.String(), true)
msgID := b.SendMessage(update.Message.Chat.ID, buf.String(), true)
if !b.cfg.NoLive {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(b.cfg.Duration)*b.cfg.Interval+time.Second)
defer cancel()
@@ -353,7 +356,7 @@ func (b *Bot) handleErrors(update tgbotapi.Update) {
func (b *Bot) handleSort(update tgbotapi.Update, tokens []string) {
if len(tokens) == 0 {
b.sendMessage(update.Message.Chat.ID, `*sort* takes one of:
b.SendMessage(update.Message.Chat.ID, `*sort* takes one of:
(*id, name, age, size, progress, downspeed, upspeed, download, upload, ratio*)
optionally start with (*rev*) for reversed order
e.g. "*sort rev size*" to get biggest torrents first.`, true)
@@ -367,8 +370,8 @@ func (b *Bot) handleSort(update tgbotapi.Update, tokens []string) {
}
sortMap := map[string]struct {
normal transmission.SortType
rev transmission.SortType
normal transmission.Sorting
rev transmission.Sorting
}{
"id": {transmission.SortID, transmission.SortRevID},
"name": {transmission.SortName, transmission.SortRevName},
@@ -385,13 +388,13 @@ func (b *Bot) handleSort(update tgbotapi.Update, tokens []string) {
if sort, ok := sortMap[strings.ToLower(tokens[0])]; ok {
if reversed {
b.client.SetSort(sort.rev)
b.sendMessage(update.Message.Chat.ID, "*sort:* reversed "+tokens[0], false)
b.SendMessage(update.Message.Chat.ID, "*sort:* reversed "+tokens[0], false)
} else {
b.client.SetSort(sort.normal)
b.sendMessage(update.Message.Chat.ID, "*sort:* "+tokens[0], false)
b.SendMessage(update.Message.Chat.ID, "*sort:* "+tokens[0], false)
}
} else {
b.sendMessage(update.Message.Chat.ID, "unknown sorting method", false)
b.SendMessage(update.Message.Chat.ID, "unknown sorting method", false)
}
}
@@ -420,15 +423,15 @@ func (b *Bot) handleTrackers(update tgbotapi.Update) {
}
if buf.Len() == 0 {
b.sendMessage(update.Message.Chat.ID, "No trackers!", false)
b.SendMessage(update.Message.Chat.ID, "No trackers!", false)
return
}
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
b.SendMessage(update.Message.Chat.ID, buf.String(), false)
}
func (b *Bot) handleDownloadDir(update tgbotapi.Update, tokens []string) {
if len(tokens) < 1 {
b.sendMessage(update.Message.Chat.ID, "Please, specify a path for downloaddir", false)
b.SendMessage(update.Message.Chat.ID, "Please, specify a path for downloaddir", false)
return
}
@@ -441,16 +444,16 @@ func (b *Bot) handleDownloadDir(update tgbotapi.Update, tokens []string) {
return
}
if out.Result != "success" {
b.sendMessage(update.Message.Chat.ID, "*downloaddir:* "+out.Result, false)
b.SendMessage(update.Message.Chat.ID, "*downloaddir:* "+out.Result, false)
return
}
b.sendMessage(update.Message.Chat.ID, "*downloaddir:* downloaddir has been successfully changed to "+tokens[0], false)
b.SendMessage(update.Message.Chat.ID, "*downloaddir:* downloaddir has been successfully changed to "+tokens[0], false)
}
func (b *Bot) handleAdd(update tgbotapi.Update, tokens []string) {
if len(tokens) == 0 {
b.sendMessage(update.Message.Chat.ID, "*add:* needs at least one URL", false)
b.SendMessage(update.Message.Chat.ID, "*add:* needs at least one URL", false)
return
}
@@ -458,21 +461,21 @@ func (b *Bot) handleAdd(update tgbotapi.Update, tokens []string) {
cmd := transmission.NewAddCmdByURL(url)
torrent, err := b.client.ExecuteAddCommand(cmd)
if err != nil {
b.sendMessage(update.Message.Chat.ID, "*add:* "+err.Error(), false)
b.SendMessage(update.Message.Chat.ID, "*add:* "+err.Error(), false)
continue
}
if torrent.Name == "" {
b.sendMessage(update.Message.Chat.ID, "*add:* error adding "+url, false)
b.SendMessage(update.Message.Chat.ID, "*add:* error adding "+url, false)
continue
}
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*Added:* <%d> %s", torrent.ID, torrent.Name), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*Added:* <%d> %s", torrent.ID, torrent.Name), false)
}
}
func (b *Bot) handleSearch(update tgbotapi.Update, tokens []string) {
if len(tokens) == 0 {
b.sendMessage(update.Message.Chat.ID, "*search:* needs an argument", false)
b.SendMessage(update.Message.Chat.ID, "*search:* needs an argument", false)
return
}
@@ -493,15 +496,15 @@ func (b *Bot) handleSearch(update tgbotapi.Update, tokens []string) {
defer putBuffer(buf)
for i := range torrents {
if regx.MatchString(torrents[i].Name) {
buf.WriteString(formatter.FormatTorrentShort(&torrents[i]) + "\n")
buf.WriteString(formatter.FormatTorrentShort(torrents[i]) + "\n")
}
}
if buf.Len() == 0 {
b.sendMessage(update.Message.Chat.ID, "No matches!", false)
b.SendMessage(update.Message.Chat.ID, "No matches!", false)
return
}
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
b.SendMessage(update.Message.Chat.ID, buf.String(), false)
}
func (b *Bot) handleLatest(update tgbotapi.Update, tokens []string) {
@@ -526,38 +529,38 @@ func (b *Bot) handleLatest(update tgbotapi.Update, tokens []string) {
buf := getBuffer()
defer putBuffer(buf)
for i := range torrents[:n] {
buf.WriteString(formatter.FormatTorrentShort(&torrents[i]) + "\n")
buf.WriteString(formatter.FormatTorrentShort(torrents[i]) + "\n")
}
if buf.Len() == 0 {
b.sendMessage(update.Message.Chat.ID, "*latest:* No torrents", false)
b.SendMessage(update.Message.Chat.ID, "*latest:* No torrents", false)
return
}
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
b.SendMessage(update.Message.Chat.ID, buf.String(), false)
}
func (b *Bot) handleInfo(update tgbotapi.Update, tokens []string) {
if len(tokens) == 0 {
b.sendMessage(update.Message.Chat.ID, "*info:* needs a torrent ID number", false)
b.SendMessage(update.Message.Chat.ID, "*info:* needs a torrent ID number", false)
return
}
for _, id := range tokens {
torrentID, err := strconv.Atoi(id)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*info:* %s is not a number", id), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*info:* %s is not a number", id), false)
continue
}
torrent, err := b.client.GetTorrent(torrentID)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*info:* Can't find a torrent with an ID of %d", torrentID), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*info:* Can't find a torrent with an ID of %d", torrentID), false)
continue
}
trackers := formatter.ExtractTrackers(torrent, trackerRegex)
info := formatter.FormatTorrentInfo(torrent, trackers)
msgID := b.sendMessage(update.Message.Chat.ID, info, true)
msgID := b.SendMessage(update.Message.Chat.ID, info, true)
if !b.cfg.NoLive {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(b.cfg.Duration)*b.cfg.Interval+time.Second)
@@ -569,109 +572,109 @@ func (b *Bot) handleInfo(update tgbotapi.Update, tokens []string) {
func (b *Bot) handleStop(update tgbotapi.Update, tokens []string) {
if len(tokens) == 0 {
b.sendMessage(update.Message.Chat.ID, "*stop:* needs an argument", false)
b.SendMessage(update.Message.Chat.ID, "*stop:* needs an argument", false)
return
}
if tokens[0] == "all" {
if err := b.client.StopAll(); err != nil {
b.sendMessage(update.Message.Chat.ID, "*stop:* error occurred while stopping some torrents", false)
b.SendMessage(update.Message.Chat.ID, "*stop:* error occurred while stopping some torrents", false)
return
}
b.sendMessage(update.Message.Chat.ID, "Stopped all torrents", false)
b.SendMessage(update.Message.Chat.ID, "Stopped all torrents", false)
return
}
for _, id := range tokens {
num, err := strconv.Atoi(id)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*stop:* %s is not a number", id), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*stop:* %s is not a number", id), false)
continue
}
status, err := b.client.StopTorrent(num)
if err != nil {
b.sendMessage(update.Message.Chat.ID, "*stop:* "+err.Error(), false)
b.SendMessage(update.Message.Chat.ID, "*stop:* "+err.Error(), false)
continue
}
torrent, err := b.client.GetTorrent(num)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("[fail] *stop:* No torrent with an ID of %d", num), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("[fail] *stop:* No torrent with an ID of %d", num), false)
continue
}
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("[%s] *stop:* %s", status, torrent.Name), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("[%s] *stop:* %s", status, torrent.Name), false)
}
}
func (b *Bot) handleStart(update tgbotapi.Update, tokens []string) {
if len(tokens) == 0 {
b.sendMessage(update.Message.Chat.ID, "*start:* needs an argument", false)
b.SendMessage(update.Message.Chat.ID, "*start:* needs an argument", false)
return
}
if tokens[0] == "all" {
if err := b.client.StartAll(); err != nil {
b.sendMessage(update.Message.Chat.ID, "*start:* error occurred while starting some torrents", false)
b.SendMessage(update.Message.Chat.ID, "*start:* error occurred while starting some torrents", false)
return
}
b.sendMessage(update.Message.Chat.ID, "Started all torrents", false)
b.SendMessage(update.Message.Chat.ID, "Started all torrents", false)
return
}
for _, id := range tokens {
num, err := strconv.Atoi(id)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*start:* %s is not a number", id), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*start:* %s is not a number", id), false)
continue
}
status, err := b.client.StartTorrent(num)
if err != nil {
b.sendMessage(update.Message.Chat.ID, "*start:* "+err.Error(), false)
b.SendMessage(update.Message.Chat.ID, "*start:* "+err.Error(), false)
continue
}
torrent, err := b.client.GetTorrent(num)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("[fail] *start:* No torrent with an ID of %d", num), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("[fail] *start:* No torrent with an ID of %d", num), false)
continue
}
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("[%s] *start:* %s", status, torrent.Name), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("[%s] *start:* %s", status, torrent.Name), false)
}
}
func (b *Bot) handleCheck(update tgbotapi.Update, tokens []string) {
if len(tokens) == 0 {
b.sendMessage(update.Message.Chat.ID, "*check:* needs an argument", false)
b.SendMessage(update.Message.Chat.ID, "*check:* needs an argument", false)
return
}
if tokens[0] == "all" {
if err := b.client.VerifyAll(); err != nil {
b.sendMessage(update.Message.Chat.ID, "*check:* error occurred while verifying some torrents", false)
b.SendMessage(update.Message.Chat.ID, "*check:* error occurred while verifying some torrents", false)
return
}
b.sendMessage(update.Message.Chat.ID, "Verifying all torrents", false)
b.SendMessage(update.Message.Chat.ID, "Verifying all torrents", false)
return
}
for _, id := range tokens {
num, err := strconv.Atoi(id)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*check:* %s is not a number", id), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*check:* %s is not a number", id), false)
continue
}
status, err := b.client.VerifyTorrent(num)
if err != nil {
b.sendMessage(update.Message.Chat.ID, "*check:* "+err.Error(), false)
b.SendMessage(update.Message.Chat.ID, "*check:* "+err.Error(), false)
continue
}
torrent, err := b.client.GetTorrent(num)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("[fail] *check:* No torrent with an ID of %d", num), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("[fail] *check:* No torrent with an ID of %d", num), false)
continue
}
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("[%s] *check:* %s", status, torrent.Name), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("[%s] *check:* %s", status, torrent.Name), false)
}
}
@@ -710,7 +713,7 @@ func (b *Bot) handleStats(update tgbotapi.Update) {
stats.CumulativeActiveTime(),
)
b.sendMessage(update.Message.Chat.ID, msg, true)
b.SendMessage(update.Message.Chat.ID, msg, true)
}
func (b *Bot) handleDownLimit(update tgbotapi.Update, tokens []string) {
@@ -723,19 +726,19 @@ func (b *Bot) handleUpLimit(update tgbotapi.Update, tokens []string) {
func (b *Bot) handleSpeedLimit(update tgbotapi.Update, tokens []string, limitType transmission.SpeedLimitType) {
if len(tokens) < 1 {
b.sendMessage(update.Message.Chat.ID, "Please, specify the limit", false)
b.SendMessage(update.Message.Chat.ID, "Please, specify the limit", false)
return
}
limit, err := strconv.ParseUint(tokens[0], 10, 32)
if err != nil {
b.sendMessage(update.Message.Chat.ID, "Please, specify the limit as number of kilobytes", false)
b.SendMessage(update.Message.Chat.ID, "Please, specify the limit as number of kilobytes", false)
return
}
speedLimitCmd := transmission.NewSpeedLimitCommand(limitType, uint(limit))
if speedLimitCmd == nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*%s:* internal error", limitType), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*%s:* internal error", limitType), false)
return
}
@@ -745,11 +748,11 @@ func (b *Bot) handleSpeedLimit(update tgbotapi.Update, tokens []string, limitTyp
return
}
if out.Result != "success" {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*%s:* %v", limitType, out.Result), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*%s:* %v", limitType, out.Result), false)
return
}
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*%s:* limit has been successfully changed to %d KB/s", limitType, limit), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*%s:* limit has been successfully changed to %d KB/s", limitType, limit), false)
}
func (b *Bot) handleSpeed(update tgbotapi.Update) {
@@ -760,7 +763,7 @@ func (b *Bot) handleSpeed(update tgbotapi.Update) {
}
msg := fmt.Sprintf("↓ %s ↑ %s", humanize.Bytes(stats.DownloadSpeed), humanize.Bytes(stats.UploadSpeed))
msgID := b.sendMessage(update.Message.Chat.ID, msg, false)
msgID := b.SendMessage(update.Message.Chat.ID, msg, false)
if !b.cfg.NoLive {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(b.cfg.Duration)*b.cfg.Interval+time.Second)
@@ -799,57 +802,57 @@ func (b *Bot) handleCount(update tgbotapi.Update) {
msg := fmt.Sprintf("Downloading: %d\nSeeding: %d\nPaused: %d\nVerifying: %d\n\n- Waiting to -\nDownload: %d\nSeed: %d\nVerify: %d\n\nTotal: %d",
downloading, seeding, stopped, checking, downloadingQ, seedingQ, checkingQ, len(torrents))
b.sendMessage(update.Message.Chat.ID, msg, false)
b.SendMessage(update.Message.Chat.ID, msg, false)
}
func (b *Bot) handleDel(update tgbotapi.Update, tokens []string) {
if len(tokens) == 0 {
b.sendMessage(update.Message.Chat.ID, "*del:* needs an ID", false)
b.SendMessage(update.Message.Chat.ID, "*del:* needs an ID", false)
return
}
for _, id := range tokens {
num, err := strconv.Atoi(id)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*del:* %s is not an ID", id), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*del:* %s is not an ID", id), false)
continue
}
name, err := b.client.DeleteTorrent(num, false)
if err != nil {
b.sendMessage(update.Message.Chat.ID, "*del:* "+err.Error(), false)
b.SendMessage(update.Message.Chat.ID, "*del:* "+err.Error(), false)
continue
}
b.sendMessage(update.Message.Chat.ID, "*Deleted:* "+name, false)
b.SendMessage(update.Message.Chat.ID, "*Deleted:* "+name, false)
}
}
func (b *Bot) handleDelData(update tgbotapi.Update, tokens []string) {
if len(tokens) == 0 {
b.sendMessage(update.Message.Chat.ID, "*deldata:* needs an ID", false)
b.SendMessage(update.Message.Chat.ID, "*deldata:* needs an ID", false)
return
}
for _, id := range tokens {
num, err := strconv.Atoi(id)
if err != nil {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*deldata:* %s is not an ID", id), false)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("*deldata:* %s is not an ID", id), false)
continue
}
name, err := b.client.DeleteTorrent(num, true)
if err != nil {
b.sendMessage(update.Message.Chat.ID, "*deldata:* "+err.Error(), false)
b.SendMessage(update.Message.Chat.ID, "*deldata:* "+err.Error(), false)
continue
}
b.sendMessage(update.Message.Chat.ID, "Deleted with data: "+name, false)
b.SendMessage(update.Message.Chat.ID, "Deleted with data: "+name, false)
}
}
func (b *Bot) handleVersion(update tgbotapi.Update) {
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("Transmission *%s*\nTransmission-telegram *%s*", b.client.Version(), config.Version), true)
b.SendMessage(update.Message.Chat.ID, fmt.Sprintf("Transmission *%s*\nTransmission-telegram *%s*", b.client.Version(), config.Version), true)
}
func (b *Bot) handleReceiveTorrent(update tgbotapi.Update) {
@@ -862,7 +865,7 @@ func (b *Bot) handleReceiveTorrent(update tgbotapi.Update) {
}
file, err := b.api.GetFile(fconfig)
if err != nil {
b.sendMessage(update.Message.Chat.ID, "*receiver:* "+err.Error(), false)
b.SendMessage(update.Message.Chat.ID, "*receiver:* "+err.Error(), false)
return
}
@@ -893,7 +896,7 @@ func (b *Bot) liveUpdateTorrents(ctx context.Context, chatID int64, msgID int, f
defer putBuffer(buf)
for i := range filtered {
buf.WriteString(formatter(&filtered[i]))
buf.WriteString(formatter(filtered[i]))
}
// Rate limit before sending
@@ -924,7 +927,7 @@ func (b *Bot) liveUpdateActive(ctx context.Context, chatID int64, msgID int) {
buf := getBuffer()
for i := range torrents {
if torrents[i].RateDownload > 0 || torrents[i].RateUpload > 0 {
buf.WriteString(formatter.FormatTorrentDetailed(&torrents[i]))
buf.WriteString(formatter.FormatTorrentDetailed(torrents[i]))
}
}
@@ -956,7 +959,7 @@ func (b *Bot) liveUpdateActive(ctx context.Context, chatID int64, msgID int) {
for i := range torrents {
if torrents[i].RateDownload > 0 || torrents[i].RateUpload > 0 {
buf.WriteString(formatter.FormatTorrentActiveStopped(&torrents[i]))
buf.WriteString(formatter.FormatTorrentActiveStopped(torrents[i]))
}
}

View File

@@ -165,7 +165,7 @@ func (c *CachedClient) DeleteTorrent(id int, deleteData bool) (string, error) {
}
// ExecuteCommand executes a command and invalidates cache
func (c *CachedClient) ExecuteCommand(cmd transmission.Command) (*transmission.CommandResult, error) {
func (c *CachedClient) ExecuteCommand(cmd *transmission.Command) (*transmission.Command, error) {
result, err := c.client.ExecuteCommand(cmd)
if err == nil {
c.InvalidateCache()
@@ -174,7 +174,7 @@ func (c *CachedClient) ExecuteCommand(cmd transmission.Command) (*transmission.C
}
// ExecuteAddCommand executes an add command and invalidates cache
func (c *CachedClient) ExecuteAddCommand(cmd transmission.AddCommand) (*transmission.Torrent, error) {
func (c *CachedClient) ExecuteAddCommand(cmd *transmission.Command) (transmission.TorrentAdded, error) {
torrent, err := c.client.ExecuteAddCommand(cmd)
if err == nil {
c.InvalidateCache()
@@ -183,7 +183,7 @@ func (c *CachedClient) ExecuteAddCommand(cmd transmission.AddCommand) (*transmis
}
// SetSort sets sort type and invalidates cache since it changes the order
func (c *CachedClient) SetSort(sort transmission.SortType) {
func (c *CachedClient) SetSort(sort transmission.Sorting) {
c.client.SetSort(sort)
c.InvalidateCache()
}

View File

@@ -16,9 +16,9 @@ type Client interface {
StartTorrent(id int) (string, error)
VerifyTorrent(id int) (string, error)
DeleteTorrent(id int, deleteData bool) (string, error)
ExecuteCommand(cmd transmission.Command) (*transmission.CommandResult, error)
ExecuteAddCommand(cmd transmission.AddCommand) (*transmission.Torrent, error)
SetSort(sort transmission.SortType)
ExecuteCommand(cmd *transmission.Command) (*transmission.Command, error)
ExecuteAddCommand(cmd *transmission.Command) (transmission.TorrentAdded, error)
SetSort(sort transmission.Sorting)
Version() string
}