forked from carrydela/mygoTgChanBot
增加功能:删除选择;相册转发
This commit is contained in:
@@ -3,6 +3,8 @@ package telegram
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"tgchanbot/internal/storage"
|
||||
|
||||
@@ -14,6 +16,14 @@ const (
|
||||
cbPrefixConfirm = "confirm:"
|
||||
cbPrefixTitle = "title:"
|
||||
cbCancel = "cancel"
|
||||
|
||||
albumCollectDelay = 500 * time.Millisecond // 等待相册其他消息的时间
|
||||
)
|
||||
|
||||
// 相册收集定时器
|
||||
var (
|
||||
albumTimers = make(map[int64]*time.Timer)
|
||||
albumTimersMu sync.Mutex
|
||||
)
|
||||
|
||||
func (b *Bot) handlePost(c tele.Context) error {
|
||||
@@ -107,8 +117,10 @@ func (b *Bot) handleTextInput(c tele.Context) error {
|
||||
|
||||
// 私聊收到转发消息,直接启动投稿流程(无需先 /post)
|
||||
if isForwarded && b.cfg.IsAdmin(c.Sender().ID) {
|
||||
if state == nil || state.Step == StepAwaitForward {
|
||||
if state == nil {
|
||||
b.states.StartPost(c.Sender().ID)
|
||||
}
|
||||
if state == nil || state.Step == StepAwaitForward {
|
||||
return b.handleForwarded(c)
|
||||
}
|
||||
}
|
||||
@@ -141,8 +153,43 @@ func (b *Bot) handleForwarded(c tele.Context) error {
|
||||
return c.Reply("❌ 这不是一条转发消息,请转发一条消息给我")
|
||||
}
|
||||
|
||||
b.states.SetForwarded(c.Sender().ID, msg)
|
||||
userID := c.Sender().ID
|
||||
|
||||
// 相册消息处理
|
||||
if msg.AlbumID != "" {
|
||||
b.states.AddAlbumMessage(userID, msg)
|
||||
b.scheduleAlbumFinalize(c, userID)
|
||||
return nil // 等待收集完成
|
||||
}
|
||||
|
||||
// 单条消息
|
||||
b.states.SetForwarded(userID, msg)
|
||||
return b.showCategorySelection(c)
|
||||
}
|
||||
|
||||
// scheduleAlbumFinalize 延迟完成相册收集
|
||||
func (b *Bot) scheduleAlbumFinalize(c tele.Context, userID int64) {
|
||||
albumTimersMu.Lock()
|
||||
defer albumTimersMu.Unlock()
|
||||
|
||||
// 取消之前的定时器
|
||||
if timer, exists := albumTimers[userID]; exists {
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// 设置新定时器
|
||||
albumTimers[userID] = time.AfterFunc(albumCollectDelay, func() {
|
||||
albumTimersMu.Lock()
|
||||
delete(albumTimers, userID)
|
||||
albumTimersMu.Unlock()
|
||||
|
||||
b.states.FinalizeAlbum(userID)
|
||||
b.showCategorySelectionAsync(c, userID)
|
||||
})
|
||||
}
|
||||
|
||||
// showCategorySelection 显示分类选择
|
||||
func (b *Bot) showCategorySelection(c tele.Context) error {
|
||||
categories, err := b.storage.ListCategories()
|
||||
if err != nil {
|
||||
b.states.Delete(c.Sender().ID)
|
||||
@@ -154,10 +201,48 @@ func (b *Bot) handleForwarded(c tele.Context) error {
|
||||
return c.Reply("❌ 暂无分类,请先使用 /cat_add 创建分类")
|
||||
}
|
||||
|
||||
state := b.states.Get(c.Sender().ID)
|
||||
msgCount := 1
|
||||
if state != nil && len(state.ForwardedMsgs) > 0 {
|
||||
msgCount = len(state.ForwardedMsgs)
|
||||
}
|
||||
|
||||
keyboard := b.buildCategoryKeyboard(categories)
|
||||
if msgCount > 1 {
|
||||
return c.Reply(fmt.Sprintf("📁 已收到 %d 条消息(相册),请选择分类:", msgCount), keyboard)
|
||||
}
|
||||
return c.Reply("📁 请选择分类:", keyboard)
|
||||
}
|
||||
|
||||
// showCategorySelectionAsync 异步显示分类选择(用于定时器回调)
|
||||
func (b *Bot) showCategorySelectionAsync(c tele.Context, userID int64) {
|
||||
categories, err := b.storage.ListCategories()
|
||||
if err != nil {
|
||||
b.states.Delete(userID)
|
||||
c.Bot().Send(c.Chat(), fmt.Sprintf("❌ 获取分类失败: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
if len(categories) == 0 {
|
||||
b.states.Delete(userID)
|
||||
c.Bot().Send(c.Chat(), "❌ 暂无分类,请先使用 /cat_add 创建分类")
|
||||
return
|
||||
}
|
||||
|
||||
state := b.states.Get(userID)
|
||||
msgCount := 1
|
||||
if state != nil && len(state.ForwardedMsgs) > 0 {
|
||||
msgCount = len(state.ForwardedMsgs)
|
||||
}
|
||||
|
||||
keyboard := b.buildCategoryKeyboard(categories)
|
||||
if msgCount > 1 {
|
||||
c.Bot().Send(c.Chat(), fmt.Sprintf("📁 已收到 %d 条消息(相册),请选择分类:", msgCount), keyboard)
|
||||
} else {
|
||||
c.Bot().Send(c.Chat(), "📁 请选择分类:", keyboard)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bot) buildCategoryKeyboard(categories []storage.Category) *tele.ReplyMarkup {
|
||||
menu := &tele.ReplyMarkup{}
|
||||
var rows []tele.Row
|
||||
@@ -208,6 +293,14 @@ func (b *Bot) handleCallback(c tele.Context) error {
|
||||
case strings.HasPrefix(data, cbPrefixConfirm):
|
||||
action := strings.TrimPrefix(data, cbPrefixConfirm)
|
||||
return b.handleConfirmCallback(c, userID, action)
|
||||
|
||||
case strings.HasPrefix(data, cbPrefixDelWithMsg):
|
||||
entryID := strings.TrimPrefix(data, cbPrefixDelWithMsg)
|
||||
return b.handleDeleteEntryCallback(c, entryID, true)
|
||||
|
||||
case strings.HasPrefix(data, cbPrefixDelOnlyToc):
|
||||
entryID := strings.TrimPrefix(data, cbPrefixDelOnlyToc)
|
||||
return b.handleDeleteEntryCallback(c, entryID, false)
|
||||
}
|
||||
|
||||
return c.Respond()
|
||||
@@ -325,12 +418,20 @@ func (b *Bot) handleConfirmCallback(c tele.Context, userID int64, action string)
|
||||
|
||||
defer b.states.Delete(userID)
|
||||
|
||||
msg := state.ForwardedMsg
|
||||
title := state.Title
|
||||
|
||||
// 复制消息内容发送到频道(非转发,可编辑)
|
||||
channel := &tele.Chat{ID: b.cfg.Channel.ID}
|
||||
channelMsg, err := b.sendMessageCopy(channel, msg)
|
||||
|
||||
var channelMsg *tele.Message
|
||||
var err error
|
||||
|
||||
// 相册消息
|
||||
if len(state.ForwardedMsgs) > 1 {
|
||||
channelMsg, err = b.sendAlbumCopy(channel, state.ForwardedMsgs)
|
||||
} else {
|
||||
// 单条消息
|
||||
channelMsg, err = b.sendMessageCopy(channel, state.ForwardedMsg)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
c.Edit(fmt.Sprintf("❌ 发送到频道失败: %v", err))
|
||||
return c.Respond(&tele.CallbackResponse{Text: "发送失败"})
|
||||
@@ -404,6 +505,47 @@ func (b *Bot) sendMessageCopy(to *tele.Chat, msg *tele.Message) (*tele.Message,
|
||||
return nil, fmt.Errorf("不支持的消息类型")
|
||||
}
|
||||
|
||||
// sendAlbumCopy 复制相册发送到频道,返回第一条消息
|
||||
func (b *Bot) sendAlbumCopy(to *tele.Chat, msgs []*tele.Message) (*tele.Message, error) {
|
||||
if len(msgs) == 0 {
|
||||
return nil, fmt.Errorf("相册为空")
|
||||
}
|
||||
|
||||
var album tele.Album
|
||||
for i, msg := range msgs {
|
||||
var caption string
|
||||
if i == 0 {
|
||||
// 只有第一条消息带 caption
|
||||
caption = msg.Caption
|
||||
}
|
||||
|
||||
if msg.Photo != nil {
|
||||
album = append(album, &tele.Photo{File: msg.Photo.File, Caption: caption})
|
||||
} else if msg.Video != nil {
|
||||
album = append(album, &tele.Video{File: msg.Video.File, Caption: caption})
|
||||
} else if msg.Document != nil {
|
||||
album = append(album, &tele.Document{File: msg.Document.File, Caption: caption})
|
||||
} else if msg.Audio != nil {
|
||||
album = append(album, &tele.Audio{File: msg.Audio.File, Caption: caption})
|
||||
}
|
||||
}
|
||||
|
||||
if len(album) == 0 {
|
||||
return nil, fmt.Errorf("相册中没有支持的媒体类型")
|
||||
}
|
||||
|
||||
sentMsgs, err := b.bot.SendAlbum(to, album, tele.ModeHTML)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(sentMsgs) == 0 {
|
||||
return nil, fmt.Errorf("发送相册失败")
|
||||
}
|
||||
|
||||
return &sentMsgs[0], nil
|
||||
}
|
||||
|
||||
func buildChannelLink(channelID int64, msgID int) string {
|
||||
chatID := channelID
|
||||
if chatID < 0 {
|
||||
|
||||
Reference in New Issue
Block a user