884 lines
24 KiB
Go
884 lines
24 KiB
Go
package bot
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/dustin/go-humanize"
|
|
"github.com/pyed/transmission"
|
|
tgbotapi "gopkg.in/telegram-bot-api.v4"
|
|
"transmission-telegram/internal/config"
|
|
"transmission-telegram/internal/formatter"
|
|
"transmission-telegram/pkg/utils"
|
|
)
|
|
|
|
var trackerRegex = regexp.MustCompile(`[https?|udp]://([^:/]*)`)
|
|
|
|
// Handler methods for bot commands - these are placeholders that need full implementation
|
|
// For now, they provide basic functionality
|
|
|
|
func (b *Bot) handleList(update tgbotapi.Update, tokens []string) {
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*list:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
if len(tokens) != 0 {
|
|
regx, err := regexp.Compile("(?i)" + tokens[0])
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*list:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
for i := range torrents {
|
|
if regx.MatchString(torrents[i].GetTrackers()) {
|
|
buf.WriteString(fmt.Sprintf("<%d> %s\n", torrents[i].ID, torrents[i].Name))
|
|
}
|
|
}
|
|
} else {
|
|
for i := range torrents {
|
|
buf.WriteString(fmt.Sprintf("<%d> %s\n", torrents[i].ID, torrents[i].Name))
|
|
}
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
if len(tokens) != 0 {
|
|
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)
|
|
return
|
|
}
|
|
|
|
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
|
|
}
|
|
|
|
func (b *Bot) handleHead(update tgbotapi.Update, tokens []string) {
|
|
n := 5
|
|
if len(tokens) > 0 {
|
|
if parsed, err := strconv.Atoi(tokens[0]); err == nil {
|
|
n = parsed
|
|
}
|
|
}
|
|
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*head:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
if n <= 0 || n > len(torrents) {
|
|
n = len(torrents)
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents[:n] {
|
|
buf.WriteString(formatter.FormatTorrentDetailed(&torrents[i]))
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "*head:* no torrents", false)
|
|
return
|
|
}
|
|
|
|
msgID := b.sendMessage(update.Message.Chat.ID, buf.String(), true)
|
|
if !b.cfg.NoLive {
|
|
b.liveUpdateTorrents(update.Message.Chat.ID, msgID, func(torrents transmission.Torrents) transmission.Torrents {
|
|
if n > len(torrents) {
|
|
return torrents[:len(torrents)]
|
|
}
|
|
return torrents[:n]
|
|
}, formatter.FormatTorrentDetailed)
|
|
}
|
|
}
|
|
|
|
func (b *Bot) handleTail(update tgbotapi.Update, tokens []string) {
|
|
n := 5
|
|
if len(tokens) > 0 {
|
|
if parsed, err := strconv.Atoi(tokens[0]); err == nil {
|
|
n = parsed
|
|
}
|
|
}
|
|
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*tail:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
if n <= 0 || n > len(torrents) {
|
|
n = len(torrents)
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for _, torrent := range torrents[len(torrents)-n:] {
|
|
buf.WriteString(formatter.FormatTorrentDetailed(&torrent))
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "*tail:* no torrents", false)
|
|
return
|
|
}
|
|
|
|
msgID := b.sendMessage(update.Message.Chat.ID, buf.String(), true)
|
|
if !b.cfg.NoLive {
|
|
b.liveUpdateTorrents(update.Message.Chat.ID, msgID, func(torrents transmission.Torrents) transmission.Torrents {
|
|
if n > len(torrents) {
|
|
return torrents
|
|
}
|
|
return torrents[len(torrents)-n:]
|
|
}, formatter.FormatTorrentDetailed)
|
|
}
|
|
}
|
|
|
|
func (b *Bot) handleDowns(update tgbotapi.Update) {
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*downs:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents {
|
|
if torrents[i].Status == transmission.StatusDownloading ||
|
|
torrents[i].Status == transmission.StatusDownloadPending {
|
|
buf.WriteString(formatter.FormatTorrentShort(&torrents[i]) + "\n")
|
|
}
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "No downloads", false)
|
|
return
|
|
}
|
|
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
|
|
}
|
|
|
|
func (b *Bot) handleSeeding(update tgbotapi.Update) {
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*seeding:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents {
|
|
if torrents[i].Status == transmission.StatusSeeding ||
|
|
torrents[i].Status == transmission.StatusSeedPending {
|
|
buf.WriteString(formatter.FormatTorrentShort(&torrents[i]) + "\n")
|
|
}
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "No torrents seeding", false)
|
|
return
|
|
}
|
|
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
|
|
}
|
|
|
|
func (b *Bot) handlePaused(update tgbotapi.Update) {
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*paused:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents {
|
|
if torrents[i].Status == transmission.StatusStopped {
|
|
buf.WriteString(formatter.FormatTorrentPaused(&torrents[i]))
|
|
}
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "No paused torrents", false)
|
|
return
|
|
}
|
|
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
|
|
}
|
|
|
|
func (b *Bot) handleChecking(update tgbotapi.Update) {
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*checking:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents {
|
|
if torrents[i].Status == transmission.StatusChecking ||
|
|
torrents[i].Status == transmission.StatusCheckPending {
|
|
buf.WriteString(formatter.FormatTorrentChecking(&torrents[i]))
|
|
}
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "No torrents verifying", false)
|
|
return
|
|
}
|
|
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
|
|
}
|
|
|
|
func (b *Bot) handleActive(update tgbotapi.Update) {
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*active:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents {
|
|
if torrents[i].RateDownload > 0 || torrents[i].RateUpload > 0 {
|
|
buf.WriteString(formatter.FormatTorrentDetailed(&torrents[i]))
|
|
}
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "No active torrents", false)
|
|
return
|
|
}
|
|
|
|
msgID := b.sendMessage(update.Message.Chat.ID, buf.String(), true)
|
|
if !b.cfg.NoLive {
|
|
b.liveUpdateActive(update.Message.Chat.ID, msgID)
|
|
}
|
|
}
|
|
|
|
func (b *Bot) handleErrors(update tgbotapi.Update) {
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*errors:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents {
|
|
if torrents[i].Error != 0 {
|
|
buf.WriteString(fmt.Sprintf("<%d> %s\n%s\n", torrents[i].ID, torrents[i].Name, torrents[i].ErrorString))
|
|
}
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "No errors", false)
|
|
return
|
|
}
|
|
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
|
|
}
|
|
|
|
func (b *Bot) handleSort(update tgbotapi.Update, tokens []string) {
|
|
if len(tokens) == 0 {
|
|
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)
|
|
return
|
|
}
|
|
|
|
var reversed bool
|
|
if strings.ToLower(tokens[0]) == "rev" {
|
|
reversed = true
|
|
tokens = tokens[1:]
|
|
}
|
|
|
|
sortMap := map[string]struct {
|
|
normal transmission.SortType
|
|
rev transmission.SortType
|
|
}{
|
|
"id": {transmission.SortID, transmission.SortRevID},
|
|
"name": {transmission.SortName, transmission.SortRevName},
|
|
"age": {transmission.SortAge, transmission.SortRevAge},
|
|
"size": {transmission.SortSize, transmission.SortRevSize},
|
|
"progress": {transmission.SortProgress, transmission.SortRevProgress},
|
|
"downspeed": {transmission.SortDownSpeed, transmission.SortRevDownSpeed},
|
|
"upspeed": {transmission.SortUpSpeed, transmission.SortRevUpSpeed},
|
|
"download": {transmission.SortDownloaded, transmission.SortRevDownloaded},
|
|
"upload": {transmission.SortUploaded, transmission.SortRevUploaded},
|
|
"ratio": {transmission.SortRatio, transmission.SortRevRatio},
|
|
}
|
|
|
|
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)
|
|
} else {
|
|
b.client.SetSort(sort.normal)
|
|
b.sendMessage(update.Message.Chat.ID, "*sort:* "+tokens[0], false)
|
|
}
|
|
} else {
|
|
b.sendMessage(update.Message.Chat.ID, "unknown sorting method", false)
|
|
}
|
|
}
|
|
|
|
func (b *Bot) handleTrackers(update tgbotapi.Update) {
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*trackers:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
trackers := make(map[string]int)
|
|
for i := range torrents {
|
|
for _, tracker := range torrents[i].Trackers {
|
|
sm := trackerRegex.FindSubmatch([]byte(tracker.Announce))
|
|
if len(sm) > 1 {
|
|
currentTracker := string(sm[1])
|
|
trackers[currentTracker]++
|
|
}
|
|
}
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for k, v := range trackers {
|
|
buf.WriteString(fmt.Sprintf("%d - %s\n", v, k))
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "No trackers!", false)
|
|
return
|
|
}
|
|
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)
|
|
return
|
|
}
|
|
|
|
cmd := transmission.NewSessionSetCommand()
|
|
cmd.SetDownloadDir(tokens[0])
|
|
|
|
out, err := b.client.ExecuteCommand(cmd)
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*downloaddir:* "+err.Error(), false)
|
|
return
|
|
}
|
|
if out.Result != "success" {
|
|
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)
|
|
}
|
|
|
|
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)
|
|
return
|
|
}
|
|
|
|
for _, url := range tokens {
|
|
cmd := transmission.NewAddCmdByURL(url)
|
|
torrent, err := b.client.ExecuteAddCommand(cmd)
|
|
if err != nil {
|
|
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)
|
|
continue
|
|
}
|
|
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)
|
|
return
|
|
}
|
|
|
|
query := strings.Join(tokens, " ")
|
|
regx, err := regexp.Compile("(?i)" + query)
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*search:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*search:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents {
|
|
if regx.MatchString(torrents[i].Name) {
|
|
buf.WriteString(formatter.FormatTorrentShort(&torrents[i]) + "\n")
|
|
}
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "No matches!", false)
|
|
return
|
|
}
|
|
b.sendMessage(update.Message.Chat.ID, buf.String(), false)
|
|
}
|
|
|
|
func (b *Bot) handleLatest(update tgbotapi.Update, tokens []string) {
|
|
n := 5
|
|
if len(tokens) > 0 {
|
|
if parsed, err := strconv.Atoi(tokens[0]); err == nil {
|
|
n = parsed
|
|
}
|
|
}
|
|
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*latest:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
if n <= 0 || n > len(torrents) {
|
|
n = len(torrents)
|
|
}
|
|
|
|
torrents.SortAge(true)
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents[:n] {
|
|
buf.WriteString(formatter.FormatTorrentShort(&torrents[i]) + "\n")
|
|
}
|
|
|
|
if buf.Len() == 0 {
|
|
b.sendMessage(update.Message.Chat.ID, "*latest:* No torrents", false)
|
|
return
|
|
}
|
|
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)
|
|
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)
|
|
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)
|
|
continue
|
|
}
|
|
|
|
trackers := formatter.ExtractTrackers(torrent, trackerRegex)
|
|
info := formatter.FormatTorrentInfo(torrent, trackers)
|
|
msgID := b.sendMessage(update.Message.Chat.ID, info, true)
|
|
|
|
if !b.cfg.NoLive {
|
|
b.liveUpdateInfo(update.Message.Chat.ID, msgID, torrentID, trackers)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (b *Bot) handleStop(update tgbotapi.Update, tokens []string) {
|
|
if len(tokens) == 0 {
|
|
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)
|
|
return
|
|
}
|
|
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)
|
|
continue
|
|
}
|
|
status, err := b.client.StopTorrent(num)
|
|
if err != nil {
|
|
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)
|
|
continue
|
|
}
|
|
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)
|
|
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)
|
|
return
|
|
}
|
|
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)
|
|
continue
|
|
}
|
|
status, err := b.client.StartTorrent(num)
|
|
if err != nil {
|
|
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)
|
|
continue
|
|
}
|
|
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)
|
|
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)
|
|
return
|
|
}
|
|
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)
|
|
continue
|
|
}
|
|
status, err := b.client.VerifyTorrent(num)
|
|
if err != nil {
|
|
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)
|
|
continue
|
|
}
|
|
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("[%s] *check:* %s", status, torrent.Name), false)
|
|
}
|
|
}
|
|
|
|
func (b *Bot) handleStats(update tgbotapi.Update) {
|
|
stats, err := b.client.GetStats()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*stats:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
msg := fmt.Sprintf(`
|
|
Total: *%d*
|
|
Active: *%d*
|
|
Paused: *%d*
|
|
|
|
_Current Stats_
|
|
Downloaded: *%s*
|
|
Uploaded: *%s*
|
|
Running time: *%s*
|
|
|
|
_Accumulative Stats_
|
|
Sessions: *%d*
|
|
Downloaded: *%s*
|
|
Uploaded: *%s*
|
|
Total Running time: *%s*
|
|
`,
|
|
stats.TorrentCount,
|
|
stats.ActiveTorrentCount,
|
|
stats.PausedTorrentCount,
|
|
humanize.Bytes(stats.CurrentStats.DownloadedBytes),
|
|
humanize.Bytes(stats.CurrentStats.UploadedBytes),
|
|
stats.CurrentActiveTime(),
|
|
stats.CumulativeStats.SessionCount,
|
|
humanize.Bytes(stats.CumulativeStats.DownloadedBytes),
|
|
humanize.Bytes(stats.CumulativeStats.UploadedBytes),
|
|
stats.CumulativeActiveTime(),
|
|
)
|
|
|
|
b.sendMessage(update.Message.Chat.ID, msg, true)
|
|
}
|
|
|
|
func (b *Bot) handleDownLimit(update tgbotapi.Update, tokens []string) {
|
|
b.handleSpeedLimit(update, tokens, transmission.DownloadLimitType)
|
|
}
|
|
|
|
func (b *Bot) handleUpLimit(update tgbotapi.Update, tokens []string) {
|
|
b.handleSpeedLimit(update, tokens, transmission.UploadLimitType)
|
|
}
|
|
|
|
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)
|
|
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)
|
|
return
|
|
}
|
|
|
|
speedLimitCmd := transmission.NewSpeedLimitCommand(limitType, uint(limit))
|
|
if speedLimitCmd == nil {
|
|
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*%s:* internal error", limitType), false)
|
|
return
|
|
}
|
|
|
|
out, err := b.client.ExecuteCommand(speedLimitCmd)
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, fmt.Sprintf("*%s:* %v", limitType, err.Error()), false)
|
|
return
|
|
}
|
|
if out.Result != "success" {
|
|
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)
|
|
}
|
|
|
|
func (b *Bot) handleSpeed(update tgbotapi.Update) {
|
|
stats, err := b.client.GetStats()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*speed:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
msg := fmt.Sprintf("↓ %s ↑ %s", humanize.Bytes(stats.DownloadSpeed), humanize.Bytes(stats.UploadSpeed))
|
|
msgID := b.sendMessage(update.Message.Chat.ID, msg, false)
|
|
|
|
if !b.cfg.NoLive {
|
|
b.liveUpdateSpeed(update.Message.Chat.ID, msgID)
|
|
}
|
|
}
|
|
|
|
func (b *Bot) handleCount(update tgbotapi.Update) {
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*count:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
var downloading, seeding, stopped, checking, downloadingQ, seedingQ, checkingQ int
|
|
for i := range torrents {
|
|
switch torrents[i].Status {
|
|
case transmission.StatusDownloading:
|
|
downloading++
|
|
case transmission.StatusSeeding:
|
|
seeding++
|
|
case transmission.StatusStopped:
|
|
stopped++
|
|
case transmission.StatusChecking:
|
|
checking++
|
|
case transmission.StatusDownloadPending:
|
|
downloadingQ++
|
|
case transmission.StatusSeedPending:
|
|
seedingQ++
|
|
case transmission.StatusCheckPending:
|
|
checkingQ++
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
func (b *Bot) handleDel(update tgbotapi.Update, tokens []string) {
|
|
if len(tokens) == 0 {
|
|
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)
|
|
continue
|
|
}
|
|
|
|
name, err := b.client.DeleteTorrent(num, false)
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*del:* "+err.Error(), false)
|
|
continue
|
|
}
|
|
|
|
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)
|
|
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)
|
|
continue
|
|
}
|
|
|
|
name, err := b.client.DeleteTorrent(num, true)
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*deldata:* "+err.Error(), false)
|
|
continue
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
func (b *Bot) handleReceiveTorrent(update tgbotapi.Update) {
|
|
if update.Message.Document == nil {
|
|
return
|
|
}
|
|
|
|
fconfig := tgbotapi.FileConfig{
|
|
FileID: update.Message.Document.FileID,
|
|
}
|
|
file, err := b.api.GetFile(fconfig)
|
|
if err != nil {
|
|
b.sendMessage(update.Message.Chat.ID, "*receiver:* "+err.Error(), false)
|
|
return
|
|
}
|
|
|
|
b.handleAdd(update, []string{file.Link(b.cfg.BotToken)})
|
|
}
|
|
|
|
// Live update helpers
|
|
func (b *Bot) liveUpdateTorrents(chatID int64, msgID int, filter func(transmission.Torrents) transmission.Torrents, formatter func(*transmission.Torrent) string) {
|
|
for i := 0; i < b.cfg.Duration; i++ {
|
|
time.Sleep(b.cfg.Interval)
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
if len(torrents) < 1 {
|
|
continue
|
|
}
|
|
|
|
filtered := filter(torrents)
|
|
buf := new(bytes.Buffer)
|
|
for i := range filtered {
|
|
buf.WriteString(formatter(&filtered[i]))
|
|
}
|
|
|
|
editConf := tgbotapi.NewEditMessageText(chatID, msgID, buf.String())
|
|
editConf.ParseMode = tgbotapi.ModeMarkdown
|
|
b.api.Send(editConf)
|
|
}
|
|
}
|
|
|
|
func (b *Bot) liveUpdateActive(chatID int64, msgID int) {
|
|
for i := 0; i < b.cfg.Duration; i++ {
|
|
time.Sleep(b.cfg.Interval)
|
|
torrents, err := b.client.GetTorrents()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents {
|
|
if torrents[i].RateDownload > 0 || torrents[i].RateUpload > 0 {
|
|
buf.WriteString(formatter.FormatTorrentDetailed(&torrents[i]))
|
|
}
|
|
}
|
|
|
|
editConf := tgbotapi.NewEditMessageText(chatID, msgID, buf.String())
|
|
editConf.ParseMode = tgbotapi.ModeMarkdown
|
|
b.api.Send(editConf)
|
|
}
|
|
|
|
time.Sleep(b.cfg.Interval)
|
|
torrents, _ := b.client.GetTorrents()
|
|
buf := new(bytes.Buffer)
|
|
for i := range torrents {
|
|
if torrents[i].RateDownload > 0 || torrents[i].RateUpload > 0 {
|
|
buf.WriteString(formatter.FormatTorrentActiveStopped(&torrents[i]))
|
|
}
|
|
}
|
|
|
|
editConf := tgbotapi.NewEditMessageText(chatID, msgID, buf.String())
|
|
editConf.ParseMode = tgbotapi.ModeMarkdown
|
|
b.api.Send(editConf)
|
|
}
|
|
|
|
func (b *Bot) liveUpdateInfo(chatID int64, msgID int, torrentID int, trackers string) {
|
|
for i := 0; i < b.cfg.Duration; i++ {
|
|
time.Sleep(b.cfg.Interval)
|
|
torrent, err := b.client.GetTorrent(torrentID)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
info := formatter.FormatTorrentInfo(torrent, trackers)
|
|
editConf := tgbotapi.NewEditMessageText(chatID, msgID, info)
|
|
editConf.ParseMode = tgbotapi.ModeMarkdown
|
|
b.api.Send(editConf)
|
|
}
|
|
|
|
time.Sleep(b.cfg.Interval)
|
|
torrent, _ := b.client.GetTorrent(torrentID)
|
|
info := formatter.FormatTorrentInfoStopped(torrent, trackers)
|
|
editConf := tgbotapi.NewEditMessageText(chatID, msgID, info)
|
|
editConf.ParseMode = tgbotapi.ModeMarkdown
|
|
b.api.Send(editConf)
|
|
}
|
|
|
|
func (b *Bot) liveUpdateSpeed(chatID int64, msgID int) {
|
|
for i := 0; i < b.cfg.Duration; i++ {
|
|
time.Sleep(b.cfg.Interval)
|
|
stats, err := b.client.GetStats()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
msg := fmt.Sprintf("↓ %s ↑ %s", humanize.Bytes(stats.DownloadSpeed), humanize.Bytes(stats.UploadSpeed))
|
|
editConf := tgbotapi.NewEditMessageText(chatID, msgID, msg)
|
|
b.api.Send(editConf)
|
|
time.Sleep(b.cfg.Interval)
|
|
}
|
|
|
|
time.Sleep(b.cfg.Interval)
|
|
editConf := tgbotapi.NewEditMessageText(chatID, msgID, "↓ - B ↑ - B")
|
|
b.api.Send(editConf)
|
|
}
|
|
|