Spaces:
Sleeping
Sleeping
Download plugins/replace.go from Thaimozhi/Go-Filter-Bot: direct link, hf CLI and curl.
- Browser
- Download file 7.46 kB
-
https://huggingface.co/spaces/Thaimozhi/Go-Filter-Bot/resolve/refs%2Fpr%2F2/plugins/replace.go
- Command line
-
hf download hf://spaces/Thaimozhi/Go-Filter-Bot@refs/pr/2/plugins/replace.go
-
curl -L -o replace.go https://huggingface.co/spaces/Thaimozhi/Go-Filter-Bot/resolve/refs%2Fpr%2F2/plugins/replace.go
7.46 kB
| package plugins | |
| import ( | |
| "fmt" | |
| "regexp" | |
| "strconv" | |
| "strings" | |
| "time" | |
| "github.com/Jisin0/Go-Filter-Bot/utils" | |
| "github.com/PaulSonOfLars/gotgbot/v2" | |
| "github.com/PaulSonOfLars/gotgbot/v2/ext" | |
| ) | |
| var ( | |
| // Matches t.me/c/1234567/89 or t.me/username/89 | |
| tgLinkRegex = regexp.MustCompile(`t\.me/(?:c/)?([^/]+)/(\d+)`) | |
| ) | |
| func parseTelegramLink(link string) (int64, int64, error) { | |
| matches := tgLinkRegex.FindStringSubmatch(link) | |
| if len(matches) != 3 { | |
| return 0, 0, fmt.Errorf("invalid telegram link format") | |
| } | |
| chatStr := matches[1] | |
| msgIDStr := matches[2] | |
| msgID, err := strconv.ParseInt(msgIDStr, 10, 64) | |
| if err != nil { | |
| return 0, 0, fmt.Errorf("invalid message ID") | |
| } | |
| // Channel ID in t.me/c/123456/789 format | |
| chatID, err := strconv.ParseInt(chatStr, 10, 64) | |
| if err != nil { | |
| return 0, 0, fmt.Errorf("invalid channel ID in link") | |
| } | |
| if chatID > 0 { | |
| chatID, _ = strconv.ParseInt("-100"+chatStr, 10, 64) | |
| } | |
| return chatID, msgID, nil | |
| } | |
| func ReplaceCommand(bot *gotgbot.Bot, ctx *ext.Context) error { | |
| if !utils.IsAdmin(ctx.EffectiveUser.Id) { | |
| ctx.Message.Reply(bot, "Only admins can use this command.", nil) | |
| return nil | |
| } | |
| args := ctx.Args()[1:] | |
| if len(args) < 1 { | |
| ctx.Message.Reply(bot, "Please provide the target Telegram post link.\nUsage: `/replace https://t.me/channel/123` (replying to a file)", &gotgbot.SendMessageOpts{ParseMode: "Markdown"}) | |
| return nil | |
| } | |
| replyMsg := ctx.Message.ReplyToMessage | |
| if replyMsg == nil || (replyMsg.Document == nil && replyMsg.Video == nil && replyMsg.Audio == nil && replyMsg.Photo == nil) { | |
| ctx.Message.Reply(bot, "Please reply to a file (Document/Video/Audio/Photo) to replace the destination post.", nil) | |
| return nil | |
| } | |
| link := args[0] | |
| chatID, msgID, err := parseTelegramLink(link) | |
| if err != nil { | |
| ctx.Message.Reply(bot, "Failed to parse link: "+err.Error(), nil) | |
| return nil | |
| } | |
| var inputMedia gotgbot.InputMedia | |
| var fileID string | |
| if replyMsg.Document != nil { | |
| fileID = replyMsg.Document.FileId | |
| inputMedia = gotgbot.InputMediaDocument{ | |
| Media: gotgbot.InputFileByID(fileID), | |
| Caption: replyMsg.Caption, | |
| CaptionEntities: replyMsg.CaptionEntities, | |
| } | |
| } else if replyMsg.Video != nil { | |
| fileID = replyMsg.Video.FileId | |
| inputMedia = gotgbot.InputMediaVideo{ | |
| Media: gotgbot.InputFileByID(fileID), | |
| Caption: replyMsg.Caption, | |
| CaptionEntities: replyMsg.CaptionEntities, | |
| } | |
| } else if replyMsg.Audio != nil { | |
| fileID = replyMsg.Audio.FileId | |
| inputMedia = gotgbot.InputMediaAudio{ | |
| Media: gotgbot.InputFileByID(fileID), | |
| Caption: replyMsg.Caption, | |
| CaptionEntities: replyMsg.CaptionEntities, | |
| } | |
| } else if len(replyMsg.Photo) > 0 { | |
| fileID = replyMsg.Photo[len(replyMsg.Photo)-1].FileId | |
| inputMedia = gotgbot.InputMediaPhoto{ | |
| Media: gotgbot.InputFileByID(fileID), | |
| Caption: replyMsg.Caption, | |
| CaptionEntities: replyMsg.CaptionEntities, | |
| } | |
| } | |
| _, _, err = bot.EditMessageMedia(inputMedia, &gotgbot.EditMessageMediaOpts{ | |
| ChatId: chatID, | |
| MessageId: msgID, | |
| }) | |
| if err != nil { | |
| ctx.Message.Reply(bot, "Failed to replace media. Make sure I am an admin in that channel with edit rights.\nError: `"+err.Error()+"`", &gotgbot.SendMessageOpts{ParseMode: "Markdown"}) | |
| return nil | |
| } | |
| ctx.Message.Reply(bot, "✅ Successfully replaced the file in the target post!", nil) | |
| return nil | |
| } | |
| // BatchReplace will ask for the count and base link, then expect the next 'count' messages to be files. | |
| var BatchReplaceState = make(map[int64]*BatchState) | |
| type BatchState struct { | |
| ChatID int64 | |
| StartMsgID int64 | |
| Count int | |
| CurrentIndex int | |
| AdminID int64 | |
| } | |
| func BatchReplaceCommand(bot *gotgbot.Bot, ctx *ext.Context) error { | |
| if !utils.IsAdmin(ctx.EffectiveUser.Id) { | |
| ctx.Message.Reply(bot, "Only admins can use this command.", nil) | |
| return nil | |
| } | |
| args := ctx.Args()[1:] | |
| if len(args) < 2 { | |
| ctx.Message.Reply(bot, "Usage: `/batchreplace <count> <base_telegram_link>`\nExample: `/batchreplace 20 https://t.me/c/12345/100`", &gotgbot.SendMessageOpts{ParseMode: "Markdown"}) | |
| return nil | |
| } | |
| count, err := strconv.Atoi(args[0]) | |
| if err != nil || count <= 0 { | |
| ctx.Message.Reply(bot, "Invalid count. Must be a positive number.", nil) | |
| return nil | |
| } | |
| link := args[1] | |
| chatID, startMsgID, err := parseTelegramLink(link) | |
| if err != nil { | |
| ctx.Message.Reply(bot, "Failed to parse link: "+err.Error(), nil) | |
| return nil | |
| } | |
| BatchReplaceState[ctx.EffectiveUser.Id] = &BatchState{ | |
| ChatID: chatID, | |
| StartMsgID: startMsgID, | |
| Count: count, | |
| CurrentIndex: 0, | |
| AdminID: ctx.EffectiveUser.Id, | |
| } | |
| ctx.Message.Reply(bot, fmt.Sprintf("✅ Batch replace started for %d files.\nTarget starting at post ID: %d\n\nPlease send or forward the %d new files here. I will automatically replace them one by one.", count, startMsgID, count), nil) | |
| return nil | |
| } | |
| func BatchReplaceHandler(bot *gotgbot.Bot, ctx *ext.Context) error { | |
| if ctx.Message == nil { | |
| return ext.ContinueGroups | |
| } | |
| state, exists := BatchReplaceState[ctx.EffectiveUser.Id] | |
| if !exists { | |
| return ext.ContinueGroups | |
| } | |
| // Check if message is a command like /cancel | |
| if strings.HasPrefix(ctx.Message.Text, "/cancel") { | |
| delete(BatchReplaceState, ctx.EffectiveUser.Id) | |
| ctx.Message.Reply(bot, "❌ Batch replace cancelled.", nil) | |
| return ext.ContinueGroups | |
| } | |
| // We only care about media messages | |
| msg := ctx.Message | |
| if msg.Document == nil && msg.Video == nil && msg.Audio == nil && msg.Photo == nil { | |
| // Not a media message, ignore or warn? | |
| return ext.ContinueGroups | |
| } | |
| targetMsgID := state.StartMsgID + int64(state.CurrentIndex) | |
| var inputMedia gotgbot.InputMedia | |
| var fileID string | |
| if msg.Document != nil { | |
| fileID = msg.Document.FileId | |
| inputMedia = gotgbot.InputMediaDocument{ | |
| Media: gotgbot.InputFileByID(fileID), | |
| Caption: msg.Caption, | |
| CaptionEntities: msg.CaptionEntities, | |
| } | |
| } else if msg.Video != nil { | |
| fileID = msg.Video.FileId | |
| inputMedia = gotgbot.InputMediaVideo{ | |
| Media: gotgbot.InputFileByID(fileID), | |
| Caption: msg.Caption, | |
| CaptionEntities: msg.CaptionEntities, | |
| } | |
| } else if msg.Audio != nil { | |
| fileID = msg.Audio.FileId | |
| inputMedia = gotgbot.InputMediaAudio{ | |
| Media: gotgbot.InputFileByID(fileID), | |
| Caption: msg.Caption, | |
| CaptionEntities: msg.CaptionEntities, | |
| } | |
| } else if len(msg.Photo) > 0 { | |
| fileID = msg.Photo[len(msg.Photo)-1].FileId | |
| inputMedia = gotgbot.InputMediaPhoto{ | |
| Media: gotgbot.InputFileByID(fileID), | |
| Caption: msg.Caption, | |
| CaptionEntities: msg.CaptionEntities, | |
| } | |
| } | |
| // Sleep slightly to avoid floodwaits if they forward an album (which arrives instantly) | |
| time.Sleep(500 * time.Millisecond) | |
| _, _, err := bot.EditMessageMedia(inputMedia, &gotgbot.EditMessageMediaOpts{ | |
| ChatId: state.ChatID, | |
| MessageId: targetMsgID, | |
| }) | |
| if err != nil { | |
| ctx.Message.Reply(bot, fmt.Sprintf("❌ Failed to replace media for post ID %d: %s\nBatch replace aborted.", targetMsgID, err.Error()), nil) | |
| delete(BatchReplaceState, ctx.EffectiveUser.Id) | |
| return ext.ContinueGroups | |
| } | |
| state.CurrentIndex++ | |
| if state.CurrentIndex >= state.Count { | |
| ctx.Message.Reply(bot, fmt.Sprintf("✅ Batch replace successfully completed! %d files replaced.", state.Count), nil) | |
| delete(BatchReplaceState, ctx.EffectiveUser.Id) | |
| } else { | |
| // Send a progress message? Maybe too spammy. | |
| } | |
| return ext.ContinueGroups | |
| } | |