Files
trbot/plugins/saved_message/utils.go

557 lines
15 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package saved_message
import (
"context"
"fmt"
"os"
"path/filepath"
"strconv"
"trbot/utils"
"trbot/utils/consts"
"trbot/utils/plugin_utils"
"trbot/utils/type/message_utils"
"trbot/utils/yaml"
"github.com/go-telegram/bot/models"
"github.com/rs/zerolog"
)
var SavedMessageSet map[int64]SavedMessage
var SavedMessageErr error
var SavedMessagePath string = filepath.Join(consts.YAMLDataBaseDir, "savedmessage/", consts.YAMLFileName)
var textExpandableLength int = 150
type SavedMessage struct {
DiscussionID int64 `yaml:"DiscussionID,omitempty"`
// IsChannelMode bool `yaml:"IsChannelMode,omitempty"`
ByUserID int64 `yaml:"ByUserID,omitempty"`
Count int `yaml:"Count"` // 当前存储的数量
SavedTimes int `yaml:"SavedTimes,omitempty"` // 一共存过多少个
Limit int `yaml:"Limit,omitempty"`
AgreePrivacyPolicy bool `yaml:"AgreePrivacyPolicy,omitempty"`
Item SavedMessageItems `yaml:"Item,omitempty"`
}
func SaveSavedMessageList(ctx context.Context) error {
logger := zerolog.Ctx(ctx).
With().
Str("pluginName", "Saved Message").
Str("funcName", "SaveSavedMessageList").
Logger()
err := yaml.SaveYAML(SavedMessagePath, &SavedMessageSet)
if err != nil {
logger.Error().
Err(err).
Str("path", SavedMessagePath).
Msg("Failed to save savedmessage list")
SavedMessageErr = fmt.Errorf("failed to save savedmessage list: %w", err)
} else {
SavedMessageErr = nil
}
return SavedMessageErr
}
func ReadSavedMessageList(ctx context.Context) error {
logger := zerolog.Ctx(ctx).
With().
Str("pluginName", "Saved Message").
Str("funcName", "ReadSavedMessageList").
Logger()
err := yaml.LoadYAML(SavedMessagePath, &SavedMessageSet)
if err != nil {
if os.IsNotExist(err) {
logger.Warn().
Err(err).
Str("path", SavedMessagePath).
Msg("Not found savedmessage list file. Created new one")
// 如果是找不到文件,新建一个
err = yaml.SaveYAML(SavedMessagePath, &SavedMessageSet)
if err != nil {
logger.Error().
Err(err).
Str("path", SavedMessagePath).
Msg("Failed to create empty savedmessage list file")
SavedMessageErr = fmt.Errorf("failed to create empty savedmessage list file: %w", err)
}
} else {
logger.Error().
Err(err).
Str("path", SavedMessagePath).
Msg("Failed to load savedmessage list file")
SavedMessageErr = fmt.Errorf("failed to load savedmessage list file: %w", err)
}
} else {
SavedMessageErr = nil
}
if SavedMessageSet == nil {
SavedMessageSet = map[int64]SavedMessage{}
}
buildSavedMessageByMessageHandlers()
return SavedMessageErr
}
type sortstruct struct {
sharedData *SavedMessageSharedData // 存放一些标准列表里没有的数据,方便搜索
onlyText *models.InlineQueryResultArticle
audio *models.InlineQueryResultCachedAudio
document *models.InlineQueryResultCachedDocument
gif *models.InlineQueryResultCachedGif
photo *models.InlineQueryResultCachedPhoto
sticker *models.InlineQueryResultCachedSticker
video *models.InlineQueryResultCachedVideo
videoNote *models.InlineQueryResultCachedDocument
voice *models.InlineQueryResultCachedVoice
mpeg4gif *models.InlineQueryResultCachedMpeg4Gif
}
type SavedMessageItems struct {
OnlyText []SavedMessageTypeCachedOnlyText `yaml:"OnlyText,omitempty"`
Audio []SavedMessageTypeCachedAudio `yaml:"Audio,omitempty"`
Document []SavedMessageTypeCachedDocument `yaml:"Document,omitempty"`
Gif []SavedMessageTypeCachedGif `yaml:"Gif,omitempty"`
Mpeg4gif []SavedMessageTypeCachedMpeg4Gif `yaml:"Mpeg4Gif,omitempty"`
Photo []SavedMessageTypeCachedPhoto `yaml:"Photo,omitempty"`
Sticker []SavedMessageTypeCachedSticker `yaml:"Sticker,omitempty"`
Video []SavedMessageTypeCachedVideo `yaml:"Video,omitempty"`
VideoNote []SavedMessageTypeCachedVideoNote `yaml:"VideoNote,omitempty"`
Voice []SavedMessageTypeCachedVoice `yaml:"Voice,omitempty"`
}
func (s *SavedMessageItems) All() []sortstruct {
// var all []models.InlineQueryResult
var list []sortstruct
// = make([]sortstruct, 100)
for _, v := range s.OnlyText {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].onlyText != nil {
fmt.Println("duplicate id", v.ID)
continue
}
// var pendingTitle string
// if len(v.TitleAndMessageText) > 20 {
// pendingTitle = v.TitleAndMessageText[:20] + "..."
// }
list[index].onlyText = &models.InlineQueryResultArticle{
ID: v.ID,
Title: v.TitleAndMessageText,
Description: v.Description,
InputMessageContent: &models.InputTextMessageContent{
MessageText: v.TitleAndMessageText,
Entities: v.Entities,
LinkPreviewOptions: v.LinkPreviewOptions,
},
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
}
for _, v := range s.Audio {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].audio != nil {
fmt.Println("duplicate id", v.ID)
continue
}
list[index].audio = &models.InlineQueryResultCachedAudio{
ID: v.ID,
AudioFileID: v.FileID,
Caption: v.Caption,
CaptionEntities: v.CaptionEntities,
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
list[index].sharedData = &SavedMessageSharedData{
Title: v.Title,
FileName: v.FileName,
Description: v.Description,
}
}
for _, v := range s.Document {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].document != nil {
fmt.Println("duplicate id", v.ID)
continue
}
list[index].document = &models.InlineQueryResultCachedDocument{
ID: v.ID,
DocumentFileID: v.FileID,
Title: v.Title,
Description: v.Description,
Caption: v.Caption,
CaptionEntities: v.CaptionEntities,
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
}
for _, v := range s.Gif {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].gif != nil {
fmt.Println("duplicate id", v.ID)
continue
}
list[index].gif = &models.InlineQueryResultCachedGif{
ID: v.ID,
GifFileID: v.FileID,
Title: v.Title,
Caption: v.Caption,
CaptionEntities: v.CaptionEntities,
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
list[index].sharedData = &SavedMessageSharedData{
Description: v.Description,
}
}
for _, v := range s.Mpeg4gif {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].mpeg4gif != nil {
fmt.Println("duplicate id", v.ID)
continue
}
list[index].mpeg4gif = &models.InlineQueryResultCachedMpeg4Gif{
ID: v.ID,
Mpeg4FileID: v.FileID,
Title: v.Title,
Caption: v.Caption,
CaptionEntities: v.CaptionEntities,
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
list[index].sharedData = &SavedMessageSharedData{
Description: v.Description,
}
}
for _, v := range s.Photo {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].photo != nil {
fmt.Println("duplicate id", v.ID)
continue
}
list[index].photo = &models.InlineQueryResultCachedPhoto{
ID: v.ID,
PhotoFileID: v.FileID,
Title: v.Title,
Description: v.Description,
Caption: v.Caption,
CaptionEntities: v.CaptionEntities,
ShowCaptionAboveMedia: v.CaptionAboveMedia,
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
}
for _, v := range s.Sticker {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].sticker != nil {
fmt.Println("duplicate id", v.ID)
continue
}
list[index].sticker = &models.InlineQueryResultCachedSticker{
ID: v.ID,
StickerFileID: v.FileID,
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
list[index].sharedData = &SavedMessageSharedData{
Name: v.SetName,
Title: v.SetTitle,
Description: v.Description,
FileName: v.Emoji,
}
}
for _, v := range s.Video {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].video != nil {
fmt.Println("duplicate id", v.ID)
continue
}
if v.Title == "" {
v.Title = "video.mp4"
}
list[index].video = &models.InlineQueryResultCachedVideo{
ID: v.ID,
VideoFileID: v.FileID,
Title: v.Title,
Description: v.Description,
Caption: v.Caption,
CaptionEntities: v.CaptionEntities,
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
}
for _, v := range s.VideoNote {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].document != nil {
fmt.Println("duplicate id", v.ID)
continue
}
list[index].document = &models.InlineQueryResultCachedDocument{
ID: v.ID,
DocumentFileID: v.FileID,
Title: v.Title,
Description: v.Description,
Caption: v.Caption,
CaptionEntities: v.CaptionEntities,
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
}
for _, v := range s.Voice {
index, err := strconv.Atoi(v.ID)
if err != nil {
fmt.Println("no an valid id", err)
continue
}
if len(list) <= index {
list = append(list, make([]sortstruct, index-len(list)+1)...)
}
if list[index].voice != nil {
fmt.Println("duplicate id", v.ID)
continue
}
if v.Title == "" {
v.Title = "audio"
}
list[index].voice = &models.InlineQueryResultCachedVoice{
ID: v.ID,
VoiceFileID: v.FileID,
Title: v.Title,
Caption: v.Caption,
CaptionEntities: v.CaptionEntities,
ReplyMarkup: buildFromInfoButton(v.OriginInfo),
}
list[index].sharedData = &SavedMessageSharedData{
Description: v.Description,
}
}
// for _, n := range list {
// if n.audio != nil {
// all = append(all, n.audio)
// } else if n.document != nil {
// all = append(all, n.document)
// } else if n.gif != nil {
// all = append(all, n.gif)
// } else if n.photo != nil {
// all = append(all, n.photo)
// } else if n.sticker != nil {
// all = append(all, n.sticker)
// } else if n.video != nil {
// all = append(all, n.video)
// } else if n.voice != nil {
// all = append(all, n.voice)
// } else if n.mpeg4gif != nil {
// all = append(all, n.mpeg4gif)
// }
// }
return list
}
func getMessageOriginData(msgOrigin *models.MessageOrigin) *OriginInfo {
if msgOrigin == nil { return nil }
switch msgOrigin.Type {
case models.MessageOriginTypeUser:
return &OriginInfo{
FromName: utils.ShowUserName(&msgOrigin.MessageOriginUser.SenderUser),
FromID: msgOrigin.MessageOriginUser.SenderUser.ID,
}
// 不再保存匿名的来源,已在调用处排除
case models.MessageOriginTypeHiddenUser:
return &OriginInfo{
FromName: msgOrigin.MessageOriginHiddenUser.SenderUserName,
}
case models.MessageOriginTypeChat:
return &OriginInfo{
FromName: utils.ShowChatName(&msgOrigin.MessageOriginChat.SenderChat),
FromID: msgOrigin.MessageOriginChat.SenderChat.ID,
}
case models.MessageOriginTypeChannel:
return &OriginInfo{
FromName: utils.ShowChatName(&msgOrigin.MessageOriginChannel.Chat),
FromID: msgOrigin.MessageOriginChannel.Chat.ID,
MessageID: msgOrigin.MessageOriginChannel.MessageID,
}
default:
return nil
}
}
func getMessageLink(msg *models.Message) *OriginInfo {
// if msg.From.ID == msg.Chat.ID {
// }
attr := message_utils.GetMessageAttribute(msg)
if attr.IsFromLinkedChannel || attr.IsFromAnonymous || attr.IsUserAsChannel {
return &OriginInfo{
FromName: utils.ShowChatName(msg.SenderChat),
FromID: msg.SenderChat.ID,
ChatID: msg.Chat.ID,
MessageID: msg.ReplyToMessage.ID,
}
} else {
return &OriginInfo{
FromName: utils.ShowUserName(msg.ReplyToMessage.From),
FromID: msg.ReplyToMessage.From.ID,
ChatID: msg.Chat.ID,
MessageID: msg.ReplyToMessage.ID,
}
}
}
type OriginInfo struct {
FromName string `yaml:"FromName,omitempty"`
FromID int64 `yaml:"FromID,omitempty"`
// FromChatID int64 `yaml:"FromChatID,omitempty"`
// 用于查看消息来源
ChatID int64 `yaml:"ChatID,omitempty"`
MessageID int `yaml:"MessageID,omitempty"`
}
func buildFromInfoButton(o *OriginInfo) models.ReplyMarkup {
if o == nil {
return nil
}
var buttons []models.InlineKeyboardButton
if o.FromID != 0 {
if o.FromID < 0 {
// -100 开头的 ID为群组或频道
buttons = append(buttons, models.InlineKeyboardButton{
Text: "来自 " + o.FromName,
URL: fmt.Sprintf("https://t.me/c/%s/0", utils.RemoveIDPrefix(o.FromID)),
})
} else {
buttons = append(buttons, models.InlineKeyboardButton{
Text: "来自用户 " + o.FromName,
URL: fmt.Sprintf("https://t.me/@id%d", o.FromID),
})
}
}
if o.MessageID != 0 {
if o.ChatID == 0 {
// 保存来源是频道
buttons = append(buttons, models.InlineKeyboardButton{
Text: "查看消息",
URL: fmt.Sprintf("https://t.me/c/%s/%d", utils.RemoveIDPrefix(o.FromID), o.MessageID),
})
} else {
// 从群组中保存的消息
buttons = append(buttons, models.InlineKeyboardButton{
Text: "查看消息",
URL: fmt.Sprintf("https://t.me/c/%s/%d", utils.RemoveIDPrefix(o.ChatID), o.MessageID),
})
}
}
return &models.InlineKeyboardMarkup{
InlineKeyboard: [][]models.InlineKeyboardButton{
buttons,
},
}
}
func buildSavedMessageByMessageHandlers() {
msgTypeList := []message_utils.Type{
message_utils.OnlyText,
message_utils.Audio,
message_utils.Animation,
message_utils.Document,
message_utils.Photo,
message_utils.Sticker,
message_utils.Video,
message_utils.VideoNote,
message_utils.Voice,
}
for chatID := range SavedMessageSet {
for _, msgType := range msgTypeList {
plugin_utils.RemoveHandlerByMessageTypeHandler(
models.ChatTypePrivate,
msgType,
chatID,
"保存消息到收藏夹",
)
}
}
for chatID, user := range SavedMessageSet {
if user.AgreePrivacyPolicy {
for _, msgType := range msgTypeList {
plugin_utils.AddHandlerByMessageTypeHandlers(plugin_utils.ByMessageTypeHandler{
PluginName: "保存消息到收藏夹",
ChatType: models.ChatTypePrivate,
ForChatID: chatID,
MessageType: msgType,
MessageHandler: saveMessageFromCallbackQueryHandler,
})
}
}
}
}