Go-Filter-Bot / plugins /replace.go
Thaimozhi's picture
Fix gotgbot InputFileByID type in replace plugin
5350b4f
Raw History Blame Contribute Delete
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
}