// Package service — Telegram command registry and dispatch. package service import ( "context" "fmt" "strings" "time" "github.com/ShukeBta/MediaStationGo/internal/model" ) type telegramCommandHandler func(args []string) (telegramCommandReply, error) type telegramCommandDefinition struct { Aliases []string AdminOnly bool AdminOnlyText string GroupAllowed bool Handle telegramCommandHandler } func (s *TelegramBotService) telegramCommandDefinitions(ctx context.Context, channel *model.NotifyChannel, msg *TelegramMessage) []telegramCommandDefinition { adminOnly := "此命令仅管理员可用。" defs := s.telegramCoreCommandDefinitions(ctx, channel, msg) defs = append(defs, s.telegramSelfServiceCommandDefinitions(ctx, channel, msg)...) defs = append(defs, s.telegramAdminCoreCommandDefinitions(ctx, msg, adminOnly)...) defs = append(defs, s.telegramMgoUserCommandDefinitions(ctx, adminOnly)...) defs = append(defs, s.telegramMgoAuditCommandDefinitions(ctx, adminOnly)...) defs = append(defs, s.telegramMgoMaintenanceCommandDefinitions(ctx, channel, adminOnly)...) defs = append(defs, s.telegramMgoPolicyCommandDefinitions(ctx, channel, adminOnly)...) return defs } func (s *TelegramBotService) telegramCoreCommandDefinitions(ctx context.Context, channel *model.NotifyChannel, msg *TelegramMessage) []telegramCommandDefinition { return []telegramCommandDefinition{ {Aliases: []string{"/start"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { if len(args) == 0 { return s.mainMenu(ctx, channel, msg), nil } return s.cmdStart(ctx, msg, args), nil }}, {Aliases: []string{"/menu"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { return s.mainMenu(ctx, channel, msg), nil }}, {Aliases: []string{"/cancel"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { s.takePending(int64(msg.From.ID)) return telegramCommandReply{Text: "已取消当前操作。"}, nil }}, {Aliases: []string{"/help"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { return telegramCommandReply{Text: s.cmdHelp(ctx, msg)}, nil }}, } } func (s *TelegramBotService) telegramSelfServiceCommandDefinitions(ctx context.Context, channel *model.NotifyChannel, msg *TelegramMessage) []telegramCommandDefinition { return []telegramCommandDefinition{ {Aliases: []string{"/hideadult", "/hide_adult", "/adult"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdHideAdult(ctx, msg, args), nil }}, {Aliases: []string{"/account", "/me", "/myinfo"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { return s.replyAccount(ctx, msg), nil }}, {Aliases: []string{"/count"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdStats(ctx) }}, {Aliases: []string{"/signin", "/checkin"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { return s.replySignIn(ctx, msg), nil }}, {Aliases: []string{"/devices"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { return s.replyDevices(ctx, msg), nil }}, {Aliases: []string{"/kick"}, GroupAllowed: true, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdKick(ctx, msg, args), nil }}, {Aliases: []string{"/setname", "/rename"}, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdSetName(ctx, msg, args), nil }}, {Aliases: []string{"/setpass", "/passwd", "/password"}, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdSetPass(ctx, msg, args), nil }}, {Aliases: []string{"/redeem"}, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdRedeem(ctx, channel, msg, args), nil }}, {Aliases: []string{"/redeem_register"}, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdRedeemRegister(ctx, channel, msg, args), nil }}, {Aliases: []string{"/redeem_renew"}, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdRedeemRenew(ctx, msg, args), nil }}, {Aliases: []string{"/register", "/reg", "/signup"}, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdRegister(ctx, channel, msg, args), nil }}, } } func (s *TelegramBotService) telegramAdminCoreCommandDefinitions(ctx context.Context, msg *TelegramMessage, adminOnly string) []telegramCommandDefinition { return []telegramCommandDefinition{ {Aliases: []string{"/registration", "/reg_switch", "/openreg"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdRegistrationToggle(ctx, args), nil }}, {Aliases: []string{"/capacity"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.replyCapacity(ctx), nil }}, {Aliases: []string{"/users", "/kk"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.replyUserList(ctx), nil }}, {Aliases: []string{"/gencode"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdGenCode(ctx, msg, args), nil }}, {Aliases: []string{"/renew_user"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdUserRenew(ctx, args), nil }}, {Aliases: []string{"/delete_user"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdUserDelete(ctx, args), nil }}, {Aliases: []string{"/unbind"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdUnbind(ctx, args), nil }}, {Aliases: []string{"/unbind_duplicates"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdUnbindDuplicates(ctx), nil }}, {Aliases: []string{"/unbind_inactive"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdUnbindInactive(ctx, args), nil }}, {Aliases: []string{"/devicepolicy", "/policy"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdDevicePolicy(ctx, args), nil }}, {Aliases: []string{"/antishare"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdAntiShare(ctx, args), nil }}, {Aliases: []string{"/cleanup"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdCleanup(ctx, args), nil }}, {Aliases: []string{"/cleanup_mode"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdCleanupMode(ctx, args), nil }}, {Aliases: []string{"/cleanup_rule"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdCleanupRule(ctx, args), nil }}, {Aliases: []string{"/ban"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdUserBan(ctx, args, false), nil }}, {Aliases: []string{"/unban"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdUserBan(ctx, args, true), nil }}, {Aliases: []string{"/status"}, AdminOnly: true, AdminOnlyText: "此命令仅管理员可用。普通用户只能使用 /start 绑定账号,并通过按钮隐藏成人目录。", Handle: func(args []string) (telegramCommandReply, error) { return s.cmdStatus(ctx) }}, {Aliases: []string{"/search"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdSearch(ctx, args) }}, {Aliases: []string{"/downloads"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdDownloads(ctx) }}, {Aliases: []string{"/stats"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdStats(ctx) }}, {Aliases: []string{"/renew"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdUserRenew(ctx, args), nil }}, } } func (s *TelegramBotService) telegramMgoUserCommandDefinitions(ctx context.Context, adminOnly string) []telegramCommandDefinition { return []telegramCommandDefinition{ {Aliases: []string{"/ucr"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoCreateUser(ctx, args), nil }}, {Aliases: []string{"/uinfo"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoUserInfo(ctx, args), nil }}, {Aliases: []string{"/rmemby", "/urm", "/only_rm_emby"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoDeleteUser(ctx, args), nil }}, {Aliases: []string{"/only_rm_record"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoOnlyRemoveRecord(ctx, args), nil }}, {Aliases: []string{"/userip"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoUserIP(ctx, args), nil }}, } } func (s *TelegramBotService) telegramMgoAuditCommandDefinitions(ctx context.Context, adminOnly string) []telegramCommandDefinition { return []telegramCommandDefinition{ {Aliases: []string{"/udeviceid"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoAuditDevices(ctx, "udeviceid", args), nil }}, {Aliases: []string{"/auditip"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoAuditDevices(ctx, "auditip", args), nil }}, {Aliases: []string{"/auditdevice"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoAuditDevices(ctx, "auditdevice", args), nil }}, {Aliases: []string{"/auditclient"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoAuditDevices(ctx, "auditclient", args), nil }}, } } func (s *TelegramBotService) telegramMgoMaintenanceCommandDefinitions(ctx context.Context, channel *model.NotifyChannel, adminOnly string) []telegramCommandDefinition { return []telegramCommandDefinition{ {Aliases: []string{"/renewall"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoRenewAll(ctx, args), nil }}, {Aliases: []string{"/callall"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoCallAll(ctx, channel, args), nil }}, {Aliases: []string{"/syncunbound"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoSyncUnbound(ctx, args), nil }}, {Aliases: []string{"/syncgroupm"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoSyncGroup(ctx, channel, args), nil }}, {Aliases: []string{"/kick_not_emby"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoUnsupported("群内无号用户清理", "/syncgroupm 可检查已绑定账号是否仍在群内;Telegram Bot API 无法枚举全部群成员,因此不能可靠找出“在群但无号”的用户。"), nil }}, {Aliases: []string{"/scan_embyname"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoScanNames(ctx), nil }}, {Aliases: []string{"/check_ex"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoCheckExpired(ctx, args), nil }}, {Aliases: []string{"/deleted", "/low_activity"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdCleanup(ctx, []string{"run"}), nil }}, {Aliases: []string{"/uranks"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoRanks(ctx, 0, true), nil }}, {Aliases: []string{"/days_ranks"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoRanks(ctx, 24*time.Hour, false), nil }}, {Aliases: []string{"/week_ranks"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoRanks(ctx, 7*24*time.Hour, false), nil }}, } } func (s *TelegramBotService) telegramMgoPolicyCommandDefinitions(ctx context.Context, channel *model.NotifyChannel, adminOnly string) []telegramCommandDefinition { return []telegramCommandDefinition{ {Aliases: []string{"/embyadmin"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoAdminRole(ctx, args), nil }}, {Aliases: []string{"/unbanall"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoBanAll(ctx, true, args), nil }}, {Aliases: []string{"/banall"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoBanAll(ctx, false, args), nil }}, {Aliases: []string{"/embylibs_unblockall", "/extraembylibs_unblockall"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoMediaAccessAll(ctx, true), nil }}, {Aliases: []string{"/embylibs_blockall", "/extraembylibs_blockall"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoMediaAccessAll(ctx, false), nil }}, {Aliases: []string{"/proadmin"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoBotAdmin(ctx, channel, args, true), nil }}, {Aliases: []string{"/revadmin"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoBotAdmin(ctx, channel, args, false), nil }}, {Aliases: []string{"/backup_db"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoBackupDB(ctx), nil }}, {Aliases: []string{"/restore_from_db"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoRestoreDB(ctx, args), nil }}, {Aliases: []string{"/prouser"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoProtectedUser(ctx, args, true), nil }}, {Aliases: []string{"/revuser"}, AdminOnly: true, AdminOnlyText: adminOnly, Handle: func(args []string) (telegramCommandReply, error) { return s.cmdMgoProtectedUser(ctx, args, false), nil }}, } } func (s *TelegramBotService) telegramCommandRegistry(ctx context.Context, channel *model.NotifyChannel, msg *TelegramMessage) map[string]telegramCommandDefinition { defs := s.telegramCommandDefinitions(ctx, channel, msg) registry := make(map[string]telegramCommandDefinition, len(defs)*2) for _, def := range defs { for _, alias := range def.Aliases { registry[alias] = def } } return registry } // executeCommand parses and dispatches Telegram commands through a registry so // adding a command does not grow a monolithic switch. func (s *TelegramBotService) executeCommand(ctx context.Context, channel *model.NotifyChannel, msg *TelegramMessage, text string) (telegramCommandReply, error) { parts := strings.Fields(text) if len(parts) == 0 { return telegramCommandReply{}, nil } cmd := telegramCommandName(parts[0]) args := parts[1:] if msg.Chat.Type != "" && msg.Chat.Type != "private" && !s.telegramChatAllowed(channel, msg.Chat.ID) { return telegramCommandReply{Text: "此群组/频道未绑定到 Bot 管理入口,请在通知渠道里填写「绑定群组 ID」或「绑定频道 ID」。"}, nil } def, ok := s.telegramCommandRegistry(ctx, channel, msg)[cmd] if !ok { return telegramCommandReply{Text: fmt.Sprintf("未知命令: %s\n\n输入 /help 查看可用命令列表。", cmd)}, nil } if telegramIsGroupChat(msg.Chat.Type) && !def.GroupAllowed { if !def.AdminOnly || !s.telegramUserIsAdmin(ctx, channel, msg.From.ID) { return telegramCommandReply{}, nil } } if def.AdminOnly && !s.telegramUserIsAdmin(ctx, channel, msg.From.ID) { return telegramCommandReply{Text: def.AdminOnlyText}, nil } reply, err := def.Handle(args) if telegramIsGroupChat(msg.Chat.Type) && def.AdminOnly && !def.GroupAllowed { if !s.telegramUserIsAdmin(ctx, channel, msg.From.ID) { reply.Buttons = nil } } return reply, err } func telegramSupportedCommand(cmd string) bool { cmd = telegramCommandName(cmd) if cmd == "" { return false } _, ok := telegramSupportedCommandSet[cmd] return ok } var telegramSupportedCommandSet = map[string]struct{}{ "/start": {}, "/menu": {}, "/cancel": {}, "/help": {}, "/hideadult": {}, "/hide_adult": {}, "/adult": {}, "/account": {}, "/me": {}, "/myinfo": {}, "/count": {}, "/signin": {}, "/checkin": {}, "/devices": {}, "/kick": {}, "/setname": {}, "/rename": {}, "/setpass": {}, "/passwd": {}, "/password": {}, "/redeem": {}, "/redeem_register": {}, "/redeem_renew": {}, "/register": {}, "/reg": {}, "/signup": {}, "/registration": {}, "/reg_switch": {}, "/openreg": {}, "/capacity": {}, "/users": {}, "/kk": {}, "/gencode": {}, "/renew_user": {}, "/delete_user": {}, "/unbind": {}, "/unbind_duplicates": {}, "/unbind_inactive": {}, "/devicepolicy": {}, "/policy": {}, "/antishare": {}, "/cleanup": {}, "/cleanup_mode": {}, "/cleanup_rule": {}, "/ban": {}, "/unban": {}, "/status": {}, "/search": {}, "/downloads": {}, "/stats": {}, "/renew": {}, "/ucr": {}, "/uinfo": {}, "/rmemby": {}, "/urm": {}, "/only_rm_emby": {}, "/only_rm_record": {}, "/userip": {}, "/udeviceid": {}, "/auditip": {}, "/auditdevice": {}, "/auditclient": {}, "/renewall": {}, "/callall": {}, "/syncunbound": {}, "/syncgroupm": {}, "/kick_not_emby": {}, "/scan_embyname": {}, "/check_ex": {}, "/deleted": {}, "/low_activity": {}, "/uranks": {}, "/days_ranks": {}, "/week_ranks": {}, "/embyadmin": {}, "/unbanall": {}, "/banall": {}, "/embylibs_unblockall": {}, "/embylibs_blockall": {}, "/extraembylibs_unblockall": {}, "/extraembylibs_blockall": {}, "/proadmin": {}, "/revadmin": {}, "/backup_db": {}, "/restore_from_db": {}, "/prouser": {}, "/revuser": {}, } type telegramBotCommand struct { Command string `json:"command"` Description string `json:"description"` } func telegramBotCommandMenu() []telegramBotCommand { return telegramPrivateBotCommandMenu() } func telegramPrivateBotCommandMenu() []telegramBotCommand { return []telegramBotCommand{ {Command: "start", Description: "绑定账号或打开主菜单"}, {Command: "menu", Description: "打开功能菜单"}, {Command: "help", Description: "查看命令帮助"}, {Command: "account", Description: "查看账号状态"}, {Command: "signin", Description: "签到"}, {Command: "devices", Description: "查看登录设备"}, {Command: "kick", Description: "踢下线设备"}, {Command: "setname", Description: "修改用户名(需当前密码)"}, {Command: "setpass", Description: "修改密码(需当前密码)"}, {Command: "hideadult", Description: "隐藏/显示成人媒体库"}, {Command: "redeem", Description: "兑换注册码或续期码"}, {Command: "register", Description: "注册新账号"}, } } func telegramGroupBotCommandMenu() []telegramBotCommand { return []telegramBotCommand{ {Command: "start", Description: "打开群组自助菜单"}, {Command: "menu", Description: "打开群组自助菜单"}, {Command: "help", Description: "查看群组可用命令"}, {Command: "account", Description: "查看账号状态"}, {Command: "signin", Description: "签到"}, {Command: "devices", Description: "查看登录设备"}, {Command: "kick", Description: "踢下线设备"}, {Command: "hideadult", Description: "隐藏/显示成人媒体库"}, } } func telegramAdminBotCommandMenu() []telegramBotCommand { commands := append([]telegramBotCommand{}, telegramPrivateBotCommandMenu()...) commands = append(commands, telegramBotCommand{Command: "status", Description: "系统运行状态(管理员)"}, telegramBotCommand{Command: "search", Description: "搜索媒体库(管理员)"}, telegramBotCommand{Command: "downloads", Description: "下载列表(管理员)"}, telegramBotCommand{Command: "stats", Description: "媒体库统计(管理员)"}, telegramBotCommand{Command: "users", Description: "用户管理(管理员)"}, telegramBotCommand{Command: "cleanup", Description: "保号清理预览/确认(管理员)"}, telegramBotCommand{Command: "cleanup_mode", Description: "查看固定保号模式(管理员)"}, telegramBotCommand{Command: "cleanup_rule", Description: "Mgo保号规则管理(管理员)"}, ) commands = append(commands, telegramMgoAdminBotCommandMenu()...) return commands } func telegramMgoAdminBotCommandMenu() []telegramBotCommand { return []telegramBotCommand{ // 用户管理:保留 Sakura/Mgo 常用命令名,剔除 /urm、/only_rm_emby 等重复别名。 {Command: "ucr", Description: "Mgo用户: 创建账号"}, {Command: "uinfo", Description: "Mgo用户: 查询账号"}, {Command: "rmemby", Description: "Mgo用户: 删除账号"}, {Command: "only_rm_record", Description: "Mgo用户: 仅删Bot绑定"}, {Command: "renewall", Description: "Mgo用户: 批量续期"}, // 审计:按 IP、设备指纹、客户端和 Telegram 绑定信息排查共享。 {Command: "userip", Description: "Mgo审计: 查询用户IP"}, {Command: "auditip", Description: "Mgo审计: 按IP审计"}, {Command: "auditdevice", Description: "Mgo审计: 按设备审计"}, {Command: "auditclient", Description: "Mgo审计: 按客户端审计"}, {Command: "udeviceid", Description: "Mgo审计: 按设备ID审计"}, // 清理:/low_activity 是 /deleted 的兼容别名,不显示在命令栏。 {Command: "syncunbound", Description: "Mgo清理: 未绑定账号"}, {Command: "syncgroupm", Description: "Mgo清理: 校验群成员"}, {Command: "check_ex", Description: "Mgo清理: 检查过期账号"}, {Command: "deleted", Description: "Mgo清理: 保号清理预览"}, // 权限:批量禁用、保护用户、媒体库播放权限。 {Command: "embyadmin", Description: "Mgo权限: 设置管理员"}, {Command: "banall", Description: "Mgo权限: 批量禁用用户"}, {Command: "unbanall", Description: "Mgo权限: 批量解禁用户"}, {Command: "prouser", Description: "Mgo权限: 加入保护名单"}, {Command: "revuser", Description: "Mgo权限: 移出保护名单"}, {Command: "embylibs_blockall", Description: "Mgo权限: 批量禁用媒体库"}, {Command: "embylibs_unblockall", Description: "Mgo权限: 批量开放媒体库"}, // 运维:Bot 管理员与数据库备份恢复。 {Command: "proadmin", Description: "Mgo运维: 添加Bot管理员"}, {Command: "revadmin", Description: "Mgo运维: 移除Bot管理员"}, {Command: "backup_db", Description: "Mgo运维: 备份数据库"}, {Command: "restore_from_db", Description: "Mgo运维: 恢复数据库"}, } } func registerTelegramBotCommands(ctx context.Context, cfg map[string]string) error { if strings.TrimSpace(cfg["bot_token"]) == "" { return nil } normalizeTelegramConfig(cfg) if err := telegramSetBotCommands(ctx, cfg, telegramPrivateBotCommandMenu(), nil); err != nil { return err } if err := telegramSetBotCommands(ctx, cfg, telegramPrivateBotCommandMenu(), map[string]interface{}{"type": "all_private_chats"}); err != nil { return err } if err := telegramSetBotCommands(ctx, cfg, telegramGroupBotCommandMenu(), map[string]interface{}{"type": "all_group_chats"}); err != nil { return err } _ = telegramSetBotCommands(ctx, cfg, telegramAdminBotCommandMenu(), map[string]interface{}{"type": "all_chat_administrators"}) adminCommands := telegramAdminBotCommandMenu() for _, adminID := range telegramConfiguredUserIDs(cfg["admin_user_ids"]) { _ = telegramSetBotCommands(ctx, cfg, adminCommands, map[string]interface{}{"type": "chat", "chat_id": adminID}) } return nil } func telegramSetBotCommands(ctx context.Context, cfg map[string]string, commands []telegramBotCommand, scope map[string]interface{}) error { payload := map[string]interface{}{"commands": commands} if scope != nil { payload["scope"] = scope } return telegramPostJSON(ctx, cfg, "setMyCommands", payload, 15*time.Second) }