forked from carrydela/mygoTgChanBot
167 lines
3.2 KiB
Go
167 lines
3.2 KiB
Go
package toc
|
|
|
|
import (
|
|
"log"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"tgchanbot/internal/storage"
|
|
|
|
tele "gopkg.in/telebot.v3"
|
|
)
|
|
|
|
type Manager struct {
|
|
storage *storage.Storage
|
|
bot *tele.Bot
|
|
chanID int64
|
|
debounce time.Duration
|
|
coverImage string
|
|
|
|
mu sync.Mutex
|
|
pending bool
|
|
timer *time.Timer
|
|
stopCh chan struct{}
|
|
}
|
|
|
|
func NewManager(store *storage.Storage, bot *tele.Bot, chanID int64, debounce time.Duration, coverImage string) *Manager {
|
|
return &Manager{
|
|
storage: store,
|
|
bot: bot,
|
|
chanID: chanID,
|
|
debounce: debounce,
|
|
coverImage: coverImage,
|
|
stopCh: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
func (m *Manager) TriggerUpdate() {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
m.pending = true
|
|
|
|
if m.timer != nil {
|
|
m.timer.Stop()
|
|
}
|
|
|
|
m.timer = time.AfterFunc(m.debounce, func() {
|
|
m.doUpdate()
|
|
})
|
|
}
|
|
|
|
func (m *Manager) doUpdate() {
|
|
m.mu.Lock()
|
|
m.pending = false
|
|
m.mu.Unlock()
|
|
|
|
content, err := m.Render()
|
|
if err != nil {
|
|
log.Printf("TOC render error: %v", err)
|
|
return
|
|
}
|
|
|
|
if err := m.updateMessage(content); err != nil {
|
|
log.Printf("TOC update error: %v", err)
|
|
}
|
|
}
|
|
|
|
func (m *Manager) updateMessage(content string) error {
|
|
chat := &tele.Chat{ID: m.chanID}
|
|
|
|
msgID, err := m.storage.GetTocMsgID()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 带封面图片模式
|
|
if m.coverImage != "" {
|
|
return m.updateWithPhoto(chat, msgID, content)
|
|
}
|
|
|
|
// 纯文本模式
|
|
if msgID == 0 {
|
|
msg, err := m.bot.Send(chat, content, tele.ModeMarkdown, tele.NoPreview)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.storage.SetTocMsgID(msg.ID)
|
|
}
|
|
|
|
existingMsg := &tele.Message{
|
|
ID: msgID,
|
|
Chat: chat,
|
|
}
|
|
|
|
_, err = m.bot.Edit(existingMsg, content, tele.ModeMarkdown, tele.NoPreview)
|
|
if err != nil {
|
|
errMsg := err.Error()
|
|
// 内容未变化,忽略
|
|
if err == tele.ErrMessageNotModified || strings.Contains(errMsg, "message is not modified") {
|
|
return nil
|
|
}
|
|
if strings.Contains(errMsg, "message to edit not found") {
|
|
msg, err := m.bot.Send(chat, content, tele.ModeMarkdown, tele.NoPreview)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.storage.SetTocMsgID(msg.ID)
|
|
}
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Manager) updateWithPhoto(chat *tele.Chat, msgID int, content string) error {
|
|
photo := &tele.Photo{
|
|
File: tele.FromDisk(m.coverImage),
|
|
Caption: content,
|
|
}
|
|
|
|
if msgID == 0 {
|
|
msg, err := m.bot.Send(chat, photo, tele.ModeMarkdown)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.storage.SetTocMsgID(msg.ID)
|
|
}
|
|
|
|
existingMsg := &tele.Message{
|
|
ID: msgID,
|
|
Chat: chat,
|
|
}
|
|
|
|
// 编辑图片消息的 caption
|
|
_, err := m.bot.EditCaption(existingMsg, content, tele.ModeMarkdown)
|
|
if err != nil {
|
|
errMsg := err.Error()
|
|
if err == tele.ErrMessageNotModified || strings.Contains(errMsg, "message is not modified") {
|
|
return nil
|
|
}
|
|
// 旧消息不是图片或找不到,重新发送
|
|
if strings.Contains(errMsg, "message to edit not found") ||
|
|
strings.Contains(errMsg, "no caption") {
|
|
msg, err := m.bot.Send(chat, photo, tele.ModeMarkdown)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return m.storage.SetTocMsgID(msg.ID)
|
|
}
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Manager) Stop() {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
if m.timer != nil {
|
|
m.timer.Stop()
|
|
}
|
|
|
|
close(m.stopCh)
|
|
}
|