增加功能:删除选择;相册转发
This commit is contained in:
@@ -10,6 +10,9 @@
|
|||||||
- **交互式按钮投稿** - Inline Keyboard 选择分类
|
- **交互式按钮投稿** - Inline Keyboard 选择分类
|
||||||
- **快捷回复投稿** - 回复消息直接添加到目录
|
- **快捷回复投稿** - 回复消息直接添加到目录
|
||||||
- **内容同步发布** - 转发的内容会复制发送到频道(非转发,可编辑)
|
- **内容同步发布** - 转发的内容会复制发送到频道(非转发,可编辑)
|
||||||
|
- **相册/多文件支持** - 自动收集相册消息,一次性发送到频道
|
||||||
|
- **目录封面图** - 可配置封面图片美化目录展示
|
||||||
|
- **交互式删除** - 删除条目时可选择是否同步删除频道消息
|
||||||
- **防抖目录更新** - 多次操作合并为一次渲染,避免限流
|
- **防抖目录更新** - 多次操作合并为一次渲染,避免限流
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
@@ -38,6 +41,7 @@ database:
|
|||||||
|
|
||||||
toc:
|
toc:
|
||||||
debounce_seconds: 3
|
debounce_seconds: 3
|
||||||
|
cover_image: "./assets/cover.jpg" # 可选,目录封面图片
|
||||||
```
|
```
|
||||||
|
|
||||||
## 运行
|
## 运行
|
||||||
@@ -57,7 +61,7 @@ toc:
|
|||||||
| `/post` | 开始投稿流程 |
|
| `/post` | 开始投稿流程 |
|
||||||
| `/post <分类> /tt <标题>` | 快捷投稿 (回复消息时使用) |
|
| `/post <分类> /tt <标题>` | 快捷投稿 (回复消息时使用) |
|
||||||
| `/list [分类]` | 查看条目 |
|
| `/list [分类]` | 查看条目 |
|
||||||
| `/del <ID>` | 删除条目(同时删除频道消息) |
|
| `/del <ID>` | 删除条目(可选是否删除频道消息) |
|
||||||
| `/edit <ID> <新标题>` | 修改标题 |
|
| `/edit <ID> <新标题>` | 修改标题 |
|
||||||
| `/move <ID> <新分类>` | 移动条目到其他分类 |
|
| `/move <ID> <新分类>` | 移动条目到其他分类 |
|
||||||
| `/refresh` | 手动刷新频道目录 |
|
| `/refresh` | 手动刷新频道目录 |
|
||||||
@@ -112,6 +116,7 @@ Bot 会将消息内容复制发送到频道,目录链接指向频道中的新
|
|||||||
- ✅ 动图(带说明文字)
|
- ✅ 动图(带说明文字)
|
||||||
- ✅ 语音
|
- ✅ 语音
|
||||||
- ✅ 贴纸
|
- ✅ 贴纸
|
||||||
|
- ✅ 相册/多文件(自动收集并合并发送)
|
||||||
|
|
||||||
## 目录结构
|
## 目录结构
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ import (
|
|||||||
tele "gopkg.in/telebot.v3"
|
tele "gopkg.in/telebot.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cbPrefixDelEntry = "del:"
|
||||||
|
cbPrefixDelWithMsg = "delwithmsg:"
|
||||||
|
cbPrefixDelOnlyToc = "delonlytoc:"
|
||||||
|
)
|
||||||
|
|
||||||
func (b *Bot) handleEntryDel(c tele.Context) error {
|
func (b *Bot) handleEntryDel(c tele.Context) error {
|
||||||
id := strings.TrimSpace(c.Message().Payload)
|
id := strings.TrimSpace(c.Message().Payload)
|
||||||
if id == "" {
|
if id == "" {
|
||||||
@@ -19,26 +25,18 @@ func (b *Bot) handleEntryDel(c tele.Context) error {
|
|||||||
return c.Reply(fmt.Sprintf("❌ %v", err))
|
return c.Reply(fmt.Sprintf("❌ %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试删除频道消息
|
menu := &tele.ReplyMarkup{}
|
||||||
msgDeleted := false
|
delWithMsgBtn := menu.Data("🗑 删除条目+频道消息", cbPrefixDelWithMsg+id)
|
||||||
if msgID := parseMessageIDFromLink(entry.Link); msgID != 0 {
|
delOnlyTocBtn := menu.Data("📝 仅删除目录条目", cbPrefixDelOnlyToc+id)
|
||||||
channel := &tele.Chat{ID: b.cfg.Channel.ID}
|
cancelBtn := menu.Data("❌ 取消", cbCancel)
|
||||||
msg := &tele.Message{ID: msgID, Chat: channel}
|
menu.Inline(
|
||||||
if err := b.bot.Delete(msg); err == nil {
|
menu.Row(delWithMsgBtn),
|
||||||
msgDeleted = true
|
menu.Row(delOnlyTocBtn),
|
||||||
}
|
menu.Row(cancelBtn),
|
||||||
}
|
)
|
||||||
|
|
||||||
if err := b.storage.DeleteEntry(id); err != nil {
|
text := fmt.Sprintf("🗑 确认删除?\n\n分类: %s\n标题: %s\n\n请选择删除方式:", entry.Category, entry.Title)
|
||||||
return c.Reply(fmt.Sprintf("❌ 删除失败: %v", err))
|
return c.Reply(text, menu)
|
||||||
}
|
|
||||||
|
|
||||||
b.toc.TriggerUpdate()
|
|
||||||
|
|
||||||
if msgDeleted {
|
|
||||||
return c.Reply(fmt.Sprintf("✅ 已删除: [%s] %s\n📨 频道消息已同步删除", entry.Category, entry.Title))
|
|
||||||
}
|
|
||||||
return c.Reply(fmt.Sprintf("✅ 已删除: [%s] %s", entry.Category, entry.Title))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) handleEntryEdit(c tele.Context) error {
|
func (b *Bot) handleEntryEdit(c tele.Context) error {
|
||||||
@@ -118,6 +116,46 @@ func (b *Bot) handleRefresh(c tele.Context) error {
|
|||||||
return c.Reply("🔄 目录刷新已触发")
|
return c.Reply("🔄 目录刷新已触发")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleDeleteEntryCallback 处理删除条目的回调
|
||||||
|
func (b *Bot) handleDeleteEntryCallback(c tele.Context, entryID string, deleteChannelMsg bool) error {
|
||||||
|
entry, err := b.storage.GetEntry(entryID)
|
||||||
|
if err != nil {
|
||||||
|
c.Edit(fmt.Sprintf("❌ %v", err))
|
||||||
|
return c.Respond(&tele.CallbackResponse{Text: "条目不存在"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据用户选择决定是否删除频道消息
|
||||||
|
msgDeleted := false
|
||||||
|
if deleteChannelMsg {
|
||||||
|
if msgID := parseMessageIDFromLink(entry.Link); msgID != 0 {
|
||||||
|
channel := &tele.Chat{ID: b.cfg.Channel.ID}
|
||||||
|
msg := &tele.Message{ID: msgID, Chat: channel}
|
||||||
|
if err := b.bot.Delete(msg); err == nil {
|
||||||
|
msgDeleted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.storage.DeleteEntry(entryID); err != nil {
|
||||||
|
c.Edit(fmt.Sprintf("❌ 删除失败: %v", err))
|
||||||
|
return c.Respond(&tele.CallbackResponse{Text: "删除失败"})
|
||||||
|
}
|
||||||
|
|
||||||
|
b.toc.TriggerUpdate()
|
||||||
|
|
||||||
|
var text string
|
||||||
|
if deleteChannelMsg && msgDeleted {
|
||||||
|
text = fmt.Sprintf("✅ 已删除: [%s] %s\n📨 频道消息已同步删除", entry.Category, entry.Title)
|
||||||
|
} else if deleteChannelMsg && !msgDeleted {
|
||||||
|
text = fmt.Sprintf("✅ 已删除: [%s] %s\n⚠️ 频道消息删除失败(可能已被删除)", entry.Category, entry.Title)
|
||||||
|
} else {
|
||||||
|
text = fmt.Sprintf("✅ 已删除: [%s] %s\n📝 频道消息已保留", entry.Category, entry.Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Edit(text)
|
||||||
|
return c.Respond(&tele.CallbackResponse{Text: "删除成功"})
|
||||||
|
}
|
||||||
|
|
||||||
// parseMessageIDFromLink 从链接中解析消息ID
|
// parseMessageIDFromLink 从链接中解析消息ID
|
||||||
// 支持格式: https://t.me/c/123456/789 或 https://t.me/username/789
|
// 支持格式: https://t.me/c/123456/789 或 https://t.me/username/789
|
||||||
func parseMessageIDFromLink(link string) int {
|
func parseMessageIDFromLink(link string) int {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package telegram
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"tgchanbot/internal/storage"
|
"tgchanbot/internal/storage"
|
||||||
|
|
||||||
@@ -14,6 +16,14 @@ const (
|
|||||||
cbPrefixConfirm = "confirm:"
|
cbPrefixConfirm = "confirm:"
|
||||||
cbPrefixTitle = "title:"
|
cbPrefixTitle = "title:"
|
||||||
cbCancel = "cancel"
|
cbCancel = "cancel"
|
||||||
|
|
||||||
|
albumCollectDelay = 500 * time.Millisecond // 等待相册其他消息的时间
|
||||||
|
)
|
||||||
|
|
||||||
|
// 相册收集定时器
|
||||||
|
var (
|
||||||
|
albumTimers = make(map[int64]*time.Timer)
|
||||||
|
albumTimersMu sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *Bot) handlePost(c tele.Context) error {
|
func (b *Bot) handlePost(c tele.Context) error {
|
||||||
@@ -107,8 +117,10 @@ func (b *Bot) handleTextInput(c tele.Context) error {
|
|||||||
|
|
||||||
// 私聊收到转发消息,直接启动投稿流程(无需先 /post)
|
// 私聊收到转发消息,直接启动投稿流程(无需先 /post)
|
||||||
if isForwarded && b.cfg.IsAdmin(c.Sender().ID) {
|
if isForwarded && b.cfg.IsAdmin(c.Sender().ID) {
|
||||||
if state == nil || state.Step == StepAwaitForward {
|
if state == nil {
|
||||||
b.states.StartPost(c.Sender().ID)
|
b.states.StartPost(c.Sender().ID)
|
||||||
|
}
|
||||||
|
if state == nil || state.Step == StepAwaitForward {
|
||||||
return b.handleForwarded(c)
|
return b.handleForwarded(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,8 +153,43 @@ func (b *Bot) handleForwarded(c tele.Context) error {
|
|||||||
return c.Reply("❌ 这不是一条转发消息,请转发一条消息给我")
|
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()
|
categories, err := b.storage.ListCategories()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.states.Delete(c.Sender().ID)
|
b.states.Delete(c.Sender().ID)
|
||||||
@@ -154,10 +201,48 @@ func (b *Bot) handleForwarded(c tele.Context) error {
|
|||||||
return c.Reply("❌ 暂无分类,请先使用 /cat_add 创建分类")
|
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)
|
keyboard := b.buildCategoryKeyboard(categories)
|
||||||
|
if msgCount > 1 {
|
||||||
|
return c.Reply(fmt.Sprintf("📁 已收到 %d 条消息(相册),请选择分类:", msgCount), keyboard)
|
||||||
|
}
|
||||||
return c.Reply("📁 请选择分类:", 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 {
|
func (b *Bot) buildCategoryKeyboard(categories []storage.Category) *tele.ReplyMarkup {
|
||||||
menu := &tele.ReplyMarkup{}
|
menu := &tele.ReplyMarkup{}
|
||||||
var rows []tele.Row
|
var rows []tele.Row
|
||||||
@@ -208,6 +293,14 @@ func (b *Bot) handleCallback(c tele.Context) error {
|
|||||||
case strings.HasPrefix(data, cbPrefixConfirm):
|
case strings.HasPrefix(data, cbPrefixConfirm):
|
||||||
action := strings.TrimPrefix(data, cbPrefixConfirm)
|
action := strings.TrimPrefix(data, cbPrefixConfirm)
|
||||||
return b.handleConfirmCallback(c, userID, action)
|
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()
|
return c.Respond()
|
||||||
@@ -325,12 +418,20 @@ func (b *Bot) handleConfirmCallback(c tele.Context, userID int64, action string)
|
|||||||
|
|
||||||
defer b.states.Delete(userID)
|
defer b.states.Delete(userID)
|
||||||
|
|
||||||
msg := state.ForwardedMsg
|
|
||||||
title := state.Title
|
title := state.Title
|
||||||
|
|
||||||
// 复制消息内容发送到频道(非转发,可编辑)
|
|
||||||
channel := &tele.Chat{ID: b.cfg.Channel.ID}
|
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 {
|
if err != nil {
|
||||||
c.Edit(fmt.Sprintf("❌ 发送到频道失败: %v", err))
|
c.Edit(fmt.Sprintf("❌ 发送到频道失败: %v", err))
|
||||||
return c.Respond(&tele.CallbackResponse{Text: "发送失败"})
|
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("不支持的消息类型")
|
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 {
|
func buildChannelLink(channelID int64, msgID int) string {
|
||||||
chatID := channelID
|
chatID := channelID
|
||||||
if chatID < 0 {
|
if chatID < 0 {
|
||||||
|
|||||||
@@ -17,12 +17,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PostState struct {
|
type PostState struct {
|
||||||
UserID int64
|
UserID int64
|
||||||
ForwardedMsg *tele.Message
|
ForwardedMsg *tele.Message // 单条消息
|
||||||
SelectedCat string
|
ForwardedMsgs []*tele.Message // 相册消息
|
||||||
Title string
|
AlbumID string // 相册ID
|
||||||
Step PostStep
|
SelectedCat string
|
||||||
CreatedAt time.Time
|
Title string
|
||||||
|
Step PostStep
|
||||||
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type StateManager struct {
|
type StateManager struct {
|
||||||
@@ -74,6 +76,51 @@ func (sm *StateManager) SetForwarded(userID int64, msg *tele.Message) *PostState
|
|||||||
}
|
}
|
||||||
|
|
||||||
state.ForwardedMsg = msg
|
state.ForwardedMsg = msg
|
||||||
|
state.ForwardedMsgs = nil
|
||||||
|
state.AlbumID = ""
|
||||||
|
state.Step = StepAwaitCategory
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAlbumMessage 添加相册消息,返回是否应该继续等待更多消息
|
||||||
|
func (sm *StateManager) AddAlbumMessage(userID int64, msg *tele.Message) (shouldWait bool) {
|
||||||
|
sm.mu.Lock()
|
||||||
|
defer sm.mu.Unlock()
|
||||||
|
|
||||||
|
state := sm.states[userID]
|
||||||
|
if state == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一条相册消息
|
||||||
|
if state.AlbumID == "" {
|
||||||
|
state.AlbumID = msg.AlbumID
|
||||||
|
state.ForwardedMsgs = []*tele.Message{msg}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同一相册的后续消息
|
||||||
|
if state.AlbumID == msg.AlbumID {
|
||||||
|
state.ForwardedMsgs = append(state.ForwardedMsgs, msg)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// FinalizeAlbum 完成相册收集
|
||||||
|
func (sm *StateManager) FinalizeAlbum(userID int64) *PostState {
|
||||||
|
sm.mu.Lock()
|
||||||
|
defer sm.mu.Unlock()
|
||||||
|
|
||||||
|
state := sm.states[userID]
|
||||||
|
if state == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(state.ForwardedMsgs) > 0 {
|
||||||
|
state.ForwardedMsg = state.ForwardedMsgs[0] // 用第一条提取标题
|
||||||
|
}
|
||||||
state.Step = StepAwaitCategory
|
state.Step = StepAwaitCategory
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user