Files
torrserver/server/tgbot/admin_settings.go
T
nkozobrod 616c6b1c62
Release Docker multi arch / docker (push) Has been cancelled
Test Install Script / Test Script Syntax (push) Has been cancelled
Test Install Script / Test on almalinux-10 (default) (push) Has been cancelled
Test Install Script / Test on almalinux-10 (root) (push) Has been cancelled
Test Install Script / Test on almalinux-8 (default) (push) Has been cancelled
Test Install Script / Test on almalinux-8 (root) (push) Has been cancelled
Test Install Script / Test on almalinux-9 (default) (push) Has been cancelled
Test Install Script / Test on almalinux-9 (root) (push) Has been cancelled
Test Install Script / Test on amazonlinux-2 (default) (push) Has been cancelled
Test Install Script / Test on amazonlinux-2 (root) (push) Has been cancelled
Test Install Script / Test on debian-11 (default) (push) Has been cancelled
Test Install Script / Test on debian-11 (root) (push) Has been cancelled
Test Install Script / Test on debian-12 (default) (push) Has been cancelled
Test Install Script / Test on debian-12 (root) (push) Has been cancelled
Test Install Script / Test on debian-13 (default) (push) Has been cancelled
Test Install Script / Test on debian-13 (root) (push) Has been cancelled
Test Install Script / Test on fedora-latest (default) (push) Has been cancelled
Test Install Script / Test on fedora-latest (root) (push) Has been cancelled
Test Install Script / Test on rocky-10 (default) (push) Has been cancelled
Test Install Script / Test on rocky-10 (root) (push) Has been cancelled
Test Install Script / Test on rocky-8 (default) (push) Has been cancelled
Test Install Script / Test on rocky-8 (root) (push) Has been cancelled
Test Install Script / Test on rocky-9 (default) (push) Has been cancelled
Test Install Script / Test on rocky-9 (root) (push) Has been cancelled
Test Install Script / Test on ubuntu-22.04 (default) (push) Has been cancelled
Test Install Script / Test on ubuntu-22.04 (root) (push) Has been cancelled
Test Install Script / Test on ubuntu-24.04 (default) (push) Has been cancelled
Test Install Script / Test on ubuntu-24.04 (root) (push) Has been cancelled
Initial commit: docker compose config
2026-05-30 12:07:11 +00:00

655 lines
23 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package tgbot
import (
"bytes"
"encoding/json"
"fmt"
"strings"
tele "gopkg.in/telebot.v4"
"server/dlna"
"server/rutor"
"server/settings"
"server/torr"
)
func cmdSettings(c tele.Context) error {
uid := c.Sender().ID
if settings.BTsets == nil {
return c.Send(tr(uid, "settings_not_loaded"))
}
return sendSettingsMenu(c, uid)
}
func sendSettingsMenu(c tele.Context, uid int64) error {
return sendSettingsMenuPage(c, uid, "1")
}
func sendSettingsMenuPage(c tele.Context, uid int64, page string) error {
msg := sendSettingsMenuText(c, uid, page)
kbd := sendSettingsMenuKbd(uid, page)
return c.Send(msg, kbd)
}
func sendSettingsMenuText(c tele.Context, uid int64, page string) string {
s := settings.BTsets
msg := "⚙️ <b>" + tr(uid, "settings_title") + "</b>"
switch page {
case "1":
msg += "\n\n"
msg += fmt.Sprintf("🔍 %s: RuTor %s · Torznab %s\n", tr(uid, "settings_section_search"), boolIcon(s.EnableRutorSearch), boolIcon(s.EnableTorznabSearch))
msg += fmt.Sprintf("📺 %s: DLNA %s · IPv6 %s · DHT %s · PEX %s · TCP %s · UTP %s\n", tr(uid, "settings_section_network"), boolIcon(s.EnableDLNA), boolIcon(s.EnableIPv6), boolIcon(!s.DisableDHT), boolIcon(!s.DisablePEX), boolIcon(!s.DisableTCP), boolIcon(!s.DisableUTP))
msg += fmt.Sprintf("📦 %s: CacheDrop %s · Proxy %s · UseDisk %s\n", tr(uid, "settings_section_other"), boolIcon(s.RemoveCacheOnDrop), boolIcon(s.EnableProxy), boolIcon(s.UseDisk))
case "1a":
msg += " — " + tr(uid, "settings_section_search")
msg += "\n\n"
msg += fmt.Sprintf("RuTor %s · Torznab %s", boolIcon(s.EnableRutorSearch), boolIcon(s.EnableTorznabSearch))
case "1b":
msg += " — " + tr(uid, "settings_section_network")
msg += "\n\n"
msg += fmt.Sprintf("DLNA %s · IPv6 %s · Upload %s · DHT %s · PEX %s\n", boolIcon(s.EnableDLNA), boolIcon(s.EnableIPv6), boolIcon(!s.DisableUpload), boolIcon(!s.DisableDHT), boolIcon(!s.DisablePEX))
msg += fmt.Sprintf("TCP %s · UTP %s · UPNP %s · Encrypt %s · Debug %s", boolIcon(!s.DisableTCP), boolIcon(!s.DisableUTP), boolIcon(!s.DisableUPNP), boolIcon(s.ForceEncrypt), boolIcon(s.EnableDebug))
case "1c":
msg += " — " + tr(uid, "settings_section_other")
msg += "\n\n"
msg += fmt.Sprintf("CacheDrop %s · Responsive %s · Proxy %s · UseDisk %s · FSActive %s", boolIcon(s.RemoveCacheOnDrop), boolIcon(s.ResponsiveMode), boolIcon(s.EnableProxy), boolIcon(s.UseDisk), boolIcon(s.ShowFSActiveTorr))
case "2":
msg += " — " + tr(uid, "settings_page2")
msg += "\n\n"
msg += fmt.Sprintf("💾 %s: %d MB · Preload %d%% · ReadAhead %d%%\n", tr(uid, "settings_limits_cache"), s.CacheSize/(1024*1024), s.PreloadCache, s.ReaderReadAHead)
msg += fmt.Sprintf("🔌 %s: %d · Port %s · Timeout %ds\n", tr(uid, "settings_limits_connections"), s.ConnectionsLimit, portStr(s.PeersListenPort), s.TorrentDisconnectTimeout)
msg += fmt.Sprintf("⬇️ %s: Down %s · Up %s · Retr %s\n", tr(uid, "settings_limits_speed"), rateStr(s.DownloadRateLimit), rateStr(s.UploadRateLimit), retrackersStr(s.RetrackersMode))
case "2a":
msg += " — " + tr(uid, "settings_page2") + " · " + tr(uid, "settings_limits_cache")
msg += "\n\n"
msg += fmt.Sprintf("Cache %d MB · Preload %d%% · ReadAhead %d%%", s.CacheSize/(1024*1024), s.PreloadCache, s.ReaderReadAHead)
case "2b":
msg += " — " + tr(uid, "settings_page2") + " · " + tr(uid, "settings_limits_connections")
msg += "\n\n"
msg += fmt.Sprintf("Connections %d · Port %s · Timeout %ds", s.ConnectionsLimit, portStr(s.PeersListenPort), s.TorrentDisconnectTimeout)
case "2c":
msg += " — " + tr(uid, "settings_page2") + " · " + tr(uid, "settings_limits_speed")
msg += "\n\n"
msg += fmt.Sprintf("Down %s · Up %s · Retrackers %s", rateStr(s.DownloadRateLimit), rateStr(s.UploadRateLimit), retrackersStr(s.RetrackersMode))
case "3":
msg += " — " + tr(uid, "settings_page3")
msg += "\n\n"
msg += fmt.Sprintf("📺 DLNA: %s · 💾 Path: %s\n", maskStr(s.FriendlyName, 25), maskVal(s.TorrentsSavePath))
msg += fmt.Sprintf("🔐 SSL: %s · 🔑 TMDB: %s · Torznab: %d\n", maskVal(s.SslCert), maskVal(s.TMDBSettings.APIKey), len(s.TorznabUrls))
msg += fmt.Sprintf("🌐 Proxy: %s", maskStr(strings.Join(s.ProxyHosts, ", "), 35))
case "4":
msg += " — " + tr(uid, "settings_page4")
msg += "\n\n"
msg += fmt.Sprintf("📄 %s: %s · 📺 %s: %s\n", tr(uid, "settings_storage_settings"), storageType(s.StoreSettingsInJson), tr(uid, "settings_storage_viewed"), storageType(s.StoreViewedInJson))
msg += fmt.Sprintf("🔑 TMDB: %s · 🖼 URL: %s", maskVal(s.TMDBSettings.APIKey), maskStr(s.TMDBSettings.ImageURL, 20))
}
return msg
}
func storageType(useJSON bool) string {
if useJSON {
return "json"
}
return "bbolt"
}
func rateStr(kb int) string {
if kb == 0 {
return "∞"
}
return fmt.Sprintf("%d", kb)
}
func portStr(port int) string {
if port == 0 {
return "auto"
}
return fmt.Sprintf("%d", port)
}
func maskStr(s string, maxLen int) string {
if s == "" {
return "—"
}
if len(s) > maxLen {
return s[:maxLen-3] + "..."
}
return s
}
func maskVal(s string) string {
if s == "" {
return "—"
}
return "***"
}
func retrackersStr(mode int) string {
switch mode {
case 0:
return "off"
case 1:
return "add"
case 2:
return "remove"
case 3:
return "replace"
default:
return "?"
}
}
func sendSettingsMenuKbd(uid int64, page string) *tele.ReplyMarkup {
s := settings.BTsets
var btns [][]tele.InlineButton
switch page {
case "1":
btns = [][]tele.InlineButton{
{
{Text: "🔍 " + tr(uid, "settings_section_search"), Unique: "fset", Data: "page|1a"},
{Text: "📺 " + tr(uid, "settings_section_network"), Unique: "fset", Data: "page|1b"},
{Text: "📦 " + tr(uid, "settings_section_other"), Unique: "fset", Data: "page|1c"},
},
{
{Text: "📥 " + tr(uid, "settings_export"), Unique: "fset", Data: "export"},
{Text: "📊 " + tr(uid, "settings_nav_cache"), Unique: "fset", Data: "page|2"},
{Text: "✏️ " + tr(uid, "settings_nav_paths"), Unique: "fset", Data: "page|3"},
{Text: "💾 " + tr(uid, "settings_nav_storage"), Unique: "fset", Data: "page|4"},
},
}
case "1a":
btns = [][]tele.InlineButton{
{
{Text: "◀️ " + tr(uid, "settings_back"), Unique: "fset", Data: "page|1"},
},
{
{Text: toggleBtn("RuTor", s.EnableRutorSearch), Unique: "fset", Data: "rutor|1a"},
{Text: toggleBtn("Torznab", s.EnableTorznabSearch), Unique: "fset", Data: "torznab|1a"},
},
}
case "1b":
btns = [][]tele.InlineButton{
{
{Text: "◀️ " + tr(uid, "settings_back"), Unique: "fset", Data: "page|1"},
},
{
{Text: toggleBtn("DLNA", s.EnableDLNA), Unique: "fset", Data: "dlna|1b"},
{Text: toggleBtn("IPv6", s.EnableIPv6), Unique: "fset", Data: "ipv6|1b"},
{Text: toggleBtn("Upload", !s.DisableUpload), Unique: "fset", Data: "upload|1b"},
},
{
{Text: toggleBtn("DHT", !s.DisableDHT), Unique: "fset", Data: "dht|1b"},
{Text: toggleBtn("PEX", !s.DisablePEX), Unique: "fset", Data: "pex|1b"},
{Text: toggleBtn("TCP", !s.DisableTCP), Unique: "fset", Data: "tcp|1b"},
{Text: toggleBtn("UTP", !s.DisableUTP), Unique: "fset", Data: "utp|1b"},
},
{
{Text: toggleBtn("UPNP", !s.DisableUPNP), Unique: "fset", Data: "upnp|1b"},
{Text: toggleBtn("Encrypt", s.ForceEncrypt), Unique: "fset", Data: "encrypt|1b"},
{Text: toggleBtn("Debug", s.EnableDebug), Unique: "fset", Data: "debug|1b"},
},
}
case "1c":
btns = [][]tele.InlineButton{
{
{Text: "◀️ " + tr(uid, "settings_back"), Unique: "fset", Data: "page|1"},
},
{
{Text: toggleBtn("CacheDrop", s.RemoveCacheOnDrop), Unique: "fset", Data: "cachedrop|1c"},
{Text: toggleBtn("Responsive", s.ResponsiveMode), Unique: "fset", Data: "responsive|1c"},
{Text: toggleBtn("Proxy", s.EnableProxy), Unique: "fset", Data: "proxy|1c"},
},
{
{Text: toggleBtn("UseDisk", s.UseDisk), Unique: "fset", Data: "usedisk|1c"},
{Text: toggleBtn("FSActive", s.ShowFSActiveTorr), Unique: "fset", Data: "fsactive|1c"},
},
}
case "2":
btns = [][]tele.InlineButton{
{
{Text: "💾 " + tr(uid, "settings_limits_cache"), Unique: "fset", Data: "page|2a"},
{Text: "🔌 " + tr(uid, "settings_limits_connections"), Unique: "fset", Data: "page|2b"},
{Text: "⬇️ " + tr(uid, "settings_limits_speed"), Unique: "fset", Data: "page|2c"},
},
{
{Text: "◀️ " + tr(uid, "settings_back"), Unique: "fset", Data: "page|1"},
{Text: "✏️ " + tr(uid, "settings_nav_paths"), Unique: "fset", Data: "page|3"},
{Text: "💾 " + tr(uid, "settings_nav_storage"), Unique: "fset", Data: "page|4"},
},
}
case "2a":
cacheMB := int(s.CacheSize / (1024 * 1024))
btns = [][]tele.InlineButton{
{
{Text: "◀️ " + tr(uid, "settings_back"), Unique: "fset", Data: "page|2"},
},
{
{Text: "💾 " + optBtn("64", cacheMB == 64), Unique: "fset", Data: "cache|64|2a"},
{Text: optBtn("128", cacheMB == 128), Unique: "fset", Data: "cache|128|2a"},
{Text: optBtn("256", cacheMB == 256), Unique: "fset", Data: "cache|256|2a"},
{Text: optBtn("512", cacheMB == 512), Unique: "fset", Data: "cache|512|2a"},
},
{
{Text: "📥 " + optBtn("25%", s.PreloadCache == 25), Unique: "fset", Data: "preload|25|2a"},
{Text: optBtn("50%", s.PreloadCache == 50), Unique: "fset", Data: "preload|50|2a"},
{Text: optBtn("75%", s.PreloadCache == 75), Unique: "fset", Data: "preload|75|2a"},
{Text: optBtn("95%", s.PreloadCache == 95), Unique: "fset", Data: "preload|95|2a"},
},
{
{Text: "📖 " + optBtn("50%", s.ReaderReadAHead == 50), Unique: "fset", Data: "readahead|50|2a"},
{Text: optBtn("75%", s.ReaderReadAHead == 75), Unique: "fset", Data: "readahead|75|2a"},
{Text: optBtn("95%", s.ReaderReadAHead == 95), Unique: "fset", Data: "readahead|95|2a"},
{Text: optBtn("100%", s.ReaderReadAHead == 100), Unique: "fset", Data: "readahead|100|2a"},
},
}
case "2b":
btns = [][]tele.InlineButton{
{
{Text: "◀️ " + tr(uid, "settings_back"), Unique: "fset", Data: "page|2"},
},
{
{Text: "🔌 " + optBtn("25", s.ConnectionsLimit == 25), Unique: "fset", Data: "conn|25|2b"},
{Text: optBtn("50", s.ConnectionsLimit == 50), Unique: "fset", Data: "conn|50|2b"},
{Text: optBtn("100", s.ConnectionsLimit == 100), Unique: "fset", Data: "conn|100|2b"},
},
{
{Text: "⏱ " + optBtn("15s", s.TorrentDisconnectTimeout == 15), Unique: "fset", Data: "timeout|15|2b"},
{Text: optBtn("30s", s.TorrentDisconnectTimeout == 30), Unique: "fset", Data: "timeout|30|2b"},
{Text: optBtn("60s", s.TorrentDisconnectTimeout == 60), Unique: "fset", Data: "timeout|60|2b"},
{Text: optBtn("120s", s.TorrentDisconnectTimeout == 120), Unique: "fset", Data: "timeout|120|2b"},
},
{
{Text: "🔌 " + optBtn("auto", s.PeersListenPort == 0), Unique: "fset", Data: "port|0|2b"},
{Text: optBtn("6881", s.PeersListenPort == 6881), Unique: "fset", Data: "port|6881|2b"},
{Text: optBtn("51413", s.PeersListenPort == 51413), Unique: "fset", Data: "port|51413|2b"},
},
}
case "2c":
btns = [][]tele.InlineButton{
{
{Text: "◀️ " + tr(uid, "settings_back"), Unique: "fset", Data: "page|2"},
},
{
{Text: "⬇️ " + optBtn("∞", s.DownloadRateLimit == 0), Unique: "fset", Data: "down|0|2c"},
{Text: optBtn("1M", s.DownloadRateLimit == 1024), Unique: "fset", Data: "down|1024|2c"},
{Text: optBtn("5M", s.DownloadRateLimit == 5120), Unique: "fset", Data: "down|5120|2c"},
{Text: optBtn("10M", s.DownloadRateLimit == 10240), Unique: "fset", Data: "down|10240|2c"},
},
{
{Text: "⬆️ " + optBtn("∞", s.UploadRateLimit == 0), Unique: "fset", Data: "up|0|2c"},
{Text: optBtn("1M", s.UploadRateLimit == 1024), Unique: "fset", Data: "up|1024|2c"},
{Text: optBtn("5M", s.UploadRateLimit == 5120), Unique: "fset", Data: "up|5120|2c"},
{Text: optBtn("10M", s.UploadRateLimit == 10240), Unique: "fset", Data: "up|10240|2c"},
},
{
{Text: "🔄 " + optBtn("off", s.RetrackersMode == 0), Unique: "fset", Data: "retr|0|2c"},
{Text: optBtn("add", s.RetrackersMode == 1), Unique: "fset", Data: "retr|1|2c"},
{Text: optBtn("rem", s.RetrackersMode == 2), Unique: "fset", Data: "retr|2|2c"},
{Text: optBtn("repl", s.RetrackersMode == 3), Unique: "fset", Data: "retr|3|2c"},
},
}
case "3":
btns = [][]tele.InlineButton{
{
{Text: "◀️ " + tr(uid, "settings_back"), Unique: "fset", Data: "page|1"},
{Text: "📊 " + tr(uid, "settings_nav_cache"), Unique: "fset", Data: "page|2"},
{Text: "💾 " + tr(uid, "settings_nav_storage"), Unique: "fset", Data: "page|4"},
},
{
{Text: "✏️ " + tr(uid, "settings_set_friendlyname"), Unique: "fset", Data: "ask|friendlyname"},
},
{
{Text: "✏️ " + tr(uid, "settings_set_path"), Unique: "fset", Data: "ask|torrentssavepath"},
},
{
{Text: "🔐 " + tr(uid, "settings_set_sslcert"), Unique: "fset", Data: "ask|sslcert"},
{Text: "🔑 " + tr(uid, "settings_set_sslkey"), Unique: "fset", Data: "ask|sslkey"},
},
{
{Text: "🎬 " + tr(uid, "settings_set_tmdbkey"), Unique: "fset", Data: "ask|tmdbkey"},
},
{
{Text: "🔍 " + tr(uid, "settings_torznab_test"), Unique: "fset", Data: "ask|torznab_test"},
{Text: " " + tr(uid, "settings_add_torznab"), Unique: "fset", Data: "ask|torznab_add"},
{Text: "🗑 " + tr(uid, "settings_clear_torznab"), Unique: "fset", Data: "torznab_clear"},
},
{
{Text: "✏️ " + tr(uid, "settings_set_proxyhosts"), Unique: "fset", Data: "ask|proxyhosts"},
},
}
case "4":
btns = [][]tele.InlineButton{
{
{Text: "◀️ " + tr(uid, "settings_back"), Unique: "fset", Data: "page|1"},
{Text: "📊 " + tr(uid, "settings_nav_cache"), Unique: "fset", Data: "page|2"},
{Text: "✏️ " + tr(uid, "settings_nav_paths"), Unique: "fset", Data: "page|3"},
},
{
{Text: "📄 " + optBtn("json", s.StoreSettingsInJson), Unique: "fset", Data: "storage_set|json"},
{Text: optBtn("bbolt", !s.StoreSettingsInJson), Unique: "fset", Data: "storage_set|bbolt"},
},
{
{Text: "📺 " + optBtn("json", s.StoreViewedInJson), Unique: "fset", Data: "storage_view|json"},
{Text: optBtn("bbolt", !s.StoreViewedInJson), Unique: "fset", Data: "storage_view|bbolt"},
},
{
{Text: "🔄 " + tr(uid, "settings_reset"), Unique: "fset", Data: "reset_confirm"},
},
}
}
return &tele.ReplyMarkup{InlineKeyboard: btns}
}
func boolIcon(v bool) string {
if v {
return "✅"
}
return "❌"
}
func toggleBtn(label string, on bool) string {
if on {
return label + " ✅"
}
return label + " ❌"
}
func optBtn(label string, isCurrent bool) string {
if isCurrent {
return label + " ✓"
}
return label
}
func settingsCallback(c tele.Context, action string) error {
uid := c.Sender().ID
if !isAdmin(uid) {
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "admin_only")})
}
if settings.BTsets == nil {
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_not_loaded")})
}
if action == "export" {
buf, err := json.MarshalIndent(settings.BTsets, "", " ")
if err != nil {
return c.Respond(&tele.CallbackResponse{Text: fmt.Sprintf(tr(uid, "settings_error"), err.Error())})
}
doc := &tele.Document{}
doc.FileName = "torrserver_settings.json"
doc.FileReader = bytes.NewReader(buf)
doc.Caption = "⚙️ " + tr(uid, "settings_export_caption")
_ = c.Send(doc)
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_exported")})
}
if action == "input_cancel" {
return cancelSettingsInput(c)
}
if action == "reset_confirm" {
btnYes := tele.InlineButton{Text: tr(uid, "btn_yes"), Unique: "fset", Data: "reset_def|1"}
btnNo := tele.InlineButton{Text: tr(uid, "btn_no"), Unique: "fset", Data: "reset_def|0"}
kbd := &tele.ReplyMarkup{InlineKeyboard: [][]tele.InlineButton{{btnYes, btnNo}}}
msg := sendSettingsMenuText(c, uid, "4") + "\n\n⚠️ " + tr(uid, "settings_reset_confirm")
if _, err := c.Bot().Edit(c.Callback().Message, msg, kbd, tele.ModeHTML); err != nil {
_ = c.Send(tr(uid, "settings_reset_confirm"), kbd)
}
return c.Respond(&tele.CallbackResponse{})
}
if len(action) > 9 && action[:9] == "reset_def|" {
if action[9:] != "1" {
msg := sendSettingsMenuText(c, uid, "4")
kbd := sendSettingsMenuKbd(uid, "4")
if _, err := c.Bot().Edit(c.Callback().Message, msg, kbd, tele.ModeHTML); err != nil {
_ = sendSettingsMenuPage(c, uid, "4")
}
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "canceled")})
}
if settings.ReadOnly {
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_readonly")})
}
torr.SetDefSettings()
dlna.Stop()
rutor.Stop()
rutor.Start()
msg := sendSettingsMenuText(c, uid, "4")
kbd := sendSettingsMenuKbd(uid, "4")
if _, err := c.Bot().Edit(c.Callback().Message, msg, kbd, tele.ModeHTML); err != nil {
_ = sendSettingsMenuPage(c, uid, "4")
}
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_reset_done")})
}
if len(action) > 12 && action[:12] == "storage_set|" {
if settings.ReadOnly {
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_readonly")})
}
val := action[12:]
prefs := map[string]interface{}{"settings": val}
if err := settings.SetStoragePreferences(prefs); err != nil {
return c.Respond(&tele.CallbackResponse{Text: fmt.Sprintf(tr(uid, "settings_error"), err.Error())})
}
page := "4"
msg := sendSettingsMenuText(c, uid, page)
kbd := sendSettingsMenuKbd(uid, page)
if _, err := c.Bot().Edit(c.Callback().Message, msg, kbd, tele.ModeHTML); err != nil {
_ = sendSettingsMenuPage(c, uid, page)
}
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_saved")})
}
if len(action) > 12 && action[:12] == "storage_view|" {
if settings.ReadOnly {
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_readonly")})
}
val := action[12:]
prefs := map[string]interface{}{"viewed": val}
if err := settings.SetStoragePreferences(prefs); err != nil {
return c.Respond(&tele.CallbackResponse{Text: fmt.Sprintf(tr(uid, "settings_error"), err.Error())})
}
page := "4"
msg := sendSettingsMenuText(c, uid, page)
kbd := sendSettingsMenuKbd(uid, page)
if _, err := c.Bot().Edit(c.Callback().Message, msg, kbd, tele.ModeHTML); err != nil {
_ = sendSettingsMenuPage(c, uid, page)
}
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_saved")})
}
if len(action) > 4 && action[:4] == "ask|" {
setting := action[4:]
var hint string
switch setting {
case "friendlyname":
hint = tr(uid, "settings_hint_friendlyname")
case "torrentssavepath":
hint = tr(uid, "settings_hint_path")
case "sslcert":
hint = tr(uid, "settings_hint_sslcert")
case "sslkey":
hint = tr(uid, "settings_hint_sslkey")
case "tmdbkey":
hint = tr(uid, "settings_hint_tmdbkey")
case "proxyhosts":
hint = tr(uid, "settings_hint_proxyhosts")
case "torznab_add":
hint = tr(uid, "settings_hint_torznab")
case "torznab_test":
hint = tr(uid, "settings_hint_torznab_test")
default:
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "callback_unknown")})
}
return sendSettingsInputPrompt(c, uid, setting, hint)
}
if len(action) > 5 && action[:5] == "page|" {
page := action[5:]
msg := sendSettingsMenuText(c, uid, page)
kbd := sendSettingsMenuKbd(uid, page)
if _, err := c.Bot().Edit(c.Callback().Message, msg, kbd, tele.ModeHTML); err != nil {
_ = sendSettingsMenuPage(c, uid, page)
}
return c.Respond(&tele.CallbackResponse{})
}
if settings.ReadOnly {
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_readonly")})
}
sets := new(settings.BTSets)
*sets = *settings.BTsets
page := "1"
// Extract return page from action (e.g. "rutor|1a" -> action "rutor", page "1a")
if idx := strings.Index(action, "|"); idx >= 0 {
suffix := action[idx+1:]
if suffix == "1a" || suffix == "1b" || suffix == "1c" {
page = suffix
action = action[:idx]
}
}
switch action {
case "rutor":
sets.EnableRutorSearch = !sets.EnableRutorSearch
case "torznab":
sets.EnableTorznabSearch = !sets.EnableTorznabSearch
case "dlna":
sets.EnableDLNA = !sets.EnableDLNA
case "ipv6":
sets.EnableIPv6 = !sets.EnableIPv6
case "upload":
sets.DisableUpload = !sets.DisableUpload
case "dht":
sets.DisableDHT = !sets.DisableDHT
case "pex":
sets.DisablePEX = !sets.DisablePEX
case "tcp":
sets.DisableTCP = !sets.DisableTCP
case "utp":
sets.DisableUTP = !sets.DisableUTP
case "upnp":
sets.DisableUPNP = !sets.DisableUPNP
case "encrypt":
sets.ForceEncrypt = !sets.ForceEncrypt
case "debug":
sets.EnableDebug = !sets.EnableDebug
case "cachedrop":
sets.RemoveCacheOnDrop = !sets.RemoveCacheOnDrop
case "responsive":
sets.ResponsiveMode = !sets.ResponsiveMode
case "proxy":
sets.EnableProxy = !sets.EnableProxy
case "usedisk":
sets.UseDisk = !sets.UseDisk
case "fsactive":
sets.ShowFSActiveTorr = !sets.ShowFSActiveTorr
case "storejson":
sets.StoreSettingsInJson = !sets.StoreSettingsInJson
case "viewedjson":
sets.StoreViewedInJson = !sets.StoreViewedInJson
case "torznab_clear":
if settings.ReadOnly {
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_readonly")})
}
sets.TorznabUrls = nil
page = "3"
torr.SetSettings(sets)
rutor.Stop()
rutor.Start()
msg := sendSettingsMenuText(c, uid, page)
kbd := sendSettingsMenuKbd(uid, page)
if _, err := c.Bot().Edit(c.Callback().Message, msg, kbd, tele.ModeHTML); err != nil {
_ = sendSettingsMenuPage(c, uid, page)
}
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_saved")})
default:
if parts := splitAction(action); len(parts) == 2 {
key, value := parts[0], parts[1]
page = "2"
if idx := strings.Index(value, "|"); idx >= 0 {
if ret := value[idx+1:]; ret == "2a" || ret == "2b" || ret == "2c" {
page = ret
}
value = value[:idx]
}
switch key {
case "cache":
if v := parseInt(value); v > 0 {
sets.CacheSize = int64(v) * 1024 * 1024
}
case "preload":
if v := parseInt(value); v >= 0 && v <= 100 {
sets.PreloadCache = v
}
case "readahead":
if v := parseInt(value); v >= 5 && v <= 100 {
sets.ReaderReadAHead = v
}
case "conn":
if v := parseInt(value); v > 0 {
sets.ConnectionsLimit = v
}
case "timeout":
if v := parseInt(value); v > 0 {
sets.TorrentDisconnectTimeout = v
}
case "port":
v := parseInt(value)
if v >= 0 && (v == 0 || (v >= 1024 && v <= 65535)) {
sets.PeersListenPort = v
}
case "down":
sets.DownloadRateLimit = parseInt(value)
case "up":
sets.UploadRateLimit = parseInt(value)
case "retr":
if v := parseInt(value); v >= 0 && v <= 3 {
sets.RetrackersMode = v
}
default:
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "callback_unknown")})
}
} else {
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "callback_unknown")})
}
}
torr.SetSettings(sets)
dlna.Stop()
if sets.EnableDLNA {
dlna.Start()
}
rutor.Stop()
rutor.Start()
msg := sendSettingsMenuText(c, uid, page)
kbd := sendSettingsMenuKbd(uid, page)
if _, err := c.Bot().Edit(c.Callback().Message, msg, kbd, tele.ModeHTML); err != nil {
_ = sendSettingsMenuPage(c, uid, page)
}
return c.Respond(&tele.CallbackResponse{Text: tr(uid, "settings_saved")})
}
func splitAction(action string) []string {
for i := 0; i < len(action); i++ {
if action[i] == '|' {
return []string{action[:i], action[i+1:]}
}
}
return nil
}
func parseInt(s string) int {
var n int
for _, c := range s {
if c >= '0' && c <= '9' {
n = n*10 + int(c-'0')
}
}
return n
}