diff --git a/cmd/bot/main.go b/cmd/bot/main.go index 38d6d4c..a7ca0e9 100644 --- a/cmd/bot/main.go +++ b/cmd/bot/main.go @@ -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) { diff --git a/go.mod b/go.mod index 36f5c47..b5cd420 100644 --- a/go.mod +++ b/go.mod @@ -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 +) diff --git a/internal/bot/bot.go b/internal/bot/bot.go index 5616efb..4c5d6ae 100644 --- a/internal/bot/bot.go +++ b/internal/bot/bot.go @@ -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) }) } } diff --git a/internal/bot/handlers.go b/internal/bot/handlers.go index 0adfe10..3360f69 100644 --- a/internal/bot/handlers.go +++ b/internal/bot/handlers.go @@ -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])) } } diff --git a/internal/transmission/client.go b/internal/transmission/client.go index 1a4bc05..dcae85a 100644 --- a/internal/transmission/client.go +++ b/internal/transmission/client.go @@ -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() } diff --git a/internal/transmission/interfaces.go b/internal/transmission/interfaces.go index 2b82e06..45b4a4a 100644 --- a/internal/transmission/interfaces.go +++ b/internal/transmission/interfaces.go @@ -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 }