Compare commits

..

5 Commits

9 changed files with 139 additions and 57 deletions

View File

@@ -8,7 +8,6 @@ import (
"github.com/gotd/td/tg"
"github.com/krau/SaveAny-Bot/common"
"github.com/krau/SaveAny-Bot/dao"
"github.com/krau/SaveAny-Bot/storage"
"github.com/krau/SaveAny-Bot/types"
)
@@ -28,11 +27,11 @@ func handleFileMessage(ctx *ext.Context, update *ext.Update) error {
ctx.Reply(update, ext.ReplyTextString("获取用户失败"), nil)
return dispatcher.EndGroups
}
storages := storage.GetUserStorages(user.ChatID)
if len(storages) == 0 {
ctx.Reply(update, ext.ReplyTextString("无可用的存储"), nil)
return dispatcher.EndGroups
}
// storages := storage.GetUserStorages(user.ChatID)
// if len(storages) == 0 {
// ctx.Reply(update, ext.ReplyTextString("无可用的存储"), nil)
// return dispatcher.EndGroups
// }
msg, err := ctx.Reply(update, ext.ReplyTextString("正在获取文件信息..."), nil)
if err != nil {

View File

@@ -1,6 +1,7 @@
package bot
import (
"fmt"
"regexp"
"strconv"
"strings"
@@ -10,7 +11,6 @@ import (
"github.com/gotd/td/tg"
"github.com/krau/SaveAny-Bot/common"
"github.com/krau/SaveAny-Bot/dao"
"github.com/krau/SaveAny-Bot/storage"
"github.com/krau/SaveAny-Bot/types"
)
@@ -19,47 +19,47 @@ var (
linkRegex = regexp.MustCompile(linkRegexString)
)
func parseLink(ctx *ext.Context, link string) (chatID int64, messageID int, err error) {
strSlice := strings.Split(link, "/")
if len(strSlice) < 3 {
return 0, 0, fmt.Errorf("链接格式错误: %s", link)
}
messageID, err = strconv.Atoi(strSlice[len(strSlice)-1])
if err != nil {
return 0, 0, fmt.Errorf("无法解析消息 ID: %s", err)
}
if len(strSlice) == 3 {
chatUsername := strSlice[1]
linkChat, err := ctx.ResolveUsername(chatUsername)
if err != nil {
return 0, 0, fmt.Errorf("解析用户名失败: %s", err)
}
if linkChat == nil {
return 0, 0, fmt.Errorf("找不到该聊天: %s", chatUsername)
}
chatID = linkChat.GetID()
} else if len(strSlice) == 4 {
chatIDInt, err := strconv.Atoi(strSlice[2])
if err != nil {
return 0, 0, fmt.Errorf("无法解析 Chat ID: %s", err)
}
chatID = int64(chatIDInt)
} else {
return 0, 0, fmt.Errorf("无效的链接: %s", link)
}
return chatID, messageID, nil
}
func handleLinkMessage(ctx *ext.Context, update *ext.Update) error {
common.Log.Trace("Got link message")
link := linkRegex.FindString(update.EffectiveMessage.Text)
if link == "" {
return dispatcher.ContinueGroups
}
strSlice := strings.Split(link, "/")
if len(strSlice) < 3 {
return dispatcher.ContinueGroups
}
messageID, err := strconv.Atoi(strSlice[len(strSlice)-1])
linkChatID, messageID, err := parseLink(ctx, link)
if err != nil {
common.Log.Errorf("解析消息 ID 失败: %s", err)
ctx.Reply(update, ext.ReplyTextString("无法解析消息 ID"), nil)
return dispatcher.EndGroups
}
var linkChatID int64
if len(strSlice) == 3 {
chatUsername := strSlice[1]
linkChat, err := ctx.ResolveUsername(chatUsername)
if err != nil {
common.Log.Errorf("解析用户名失败: %s", err)
ctx.Reply(update, ext.ReplyTextString("解析用户名失败"), nil)
return dispatcher.EndGroups
}
if linkChat == nil {
common.Log.Errorf("无法找到聊天: %s", chatUsername)
ctx.Reply(update, ext.ReplyTextString("无法找到聊天"), nil)
return dispatcher.EndGroups
}
linkChatID = linkChat.GetID()
} else if len(strSlice) == 4 {
chatID, err := strconv.Atoi(strSlice[2])
if err != nil {
common.Log.Errorf("解析 Chat ID 失败: %s", err)
ctx.Reply(update, ext.ReplyTextString("解析 Chat ID 失败"), nil)
return dispatcher.EndGroups
}
linkChatID = int64(chatID)
} else {
ctx.Reply(update, ext.ReplyTextString("无法解析链接"), nil)
common.Log.Errorf("解析链接失败: %s", err)
ctx.Reply(update, ext.ReplyTextString("解析链接失败: "+err.Error()), nil)
return dispatcher.EndGroups
}
@@ -69,12 +69,13 @@ func handleLinkMessage(ctx *ext.Context, update *ext.Update) error {
ctx.Reply(update, ext.ReplyTextString("获取用户失败"), nil)
return dispatcher.EndGroups
}
storages := storage.GetUserStorages(user.ChatID)
if len(storages) == 0 {
ctx.Reply(update, ext.ReplyTextString("无可用的存储"), nil)
return dispatcher.EndGroups
}
// storages := storage.GetUserStorages(user.ChatID)
// if len(storages) == 0 {
// ctx.Reply(update, ext.ReplyTextString("无可用的存储"), nil)
// return dispatcher.EndGroups
// }
replied, err := ctx.Reply(update, ext.ReplyTextString("正在获取文件..."), nil)
if err != nil {
common.Log.Errorf("回复失败: %s", err)

View File

@@ -63,12 +63,11 @@ func saveCmd(ctx *ext.Context, update *ext.Update) error {
return dispatcher.EndGroups
}
storages := storage.GetUserStorages(user.ChatID)
if len(storages) == 0 {
ctx.Reply(update, ext.ReplyTextString("无可用的存储"), nil)
return dispatcher.EndGroups
}
// storages := storage.GetUserStorages(user.ChatID)
// if len(storages) == 0 {
// ctx.Reply(update, ext.ReplyTextString("无可用的存储"), nil)
// return dispatcher.EndGroups
// }
msg, err := GetTGMessage(ctx, update.EffectiveChat().GetID(), replyToMsgID)
if err != nil {

View File

@@ -9,6 +9,7 @@ import (
"github.com/gotd/contrib/middleware/floodwait"
"github.com/gotd/contrib/middleware/ratelimit"
"github.com/gotd/td/telegram"
"github.com/krau/SaveAny-Bot/common"
"github.com/krau/SaveAny-Bot/config"
"golang.org/x/time/rate"
)
@@ -30,8 +31,40 @@ const noPermissionText string = `
func checkPermission(ctx *ext.Context, update *ext.Update) error {
userID := update.GetUserChat().GetID()
if !slice.Contain(config.Cfg.GetUsersID(), userID) {
if config.Cfg.AsPublicCopyMediaBot {
tryCopyMedia(ctx, update)
return dispatcher.EndGroups
}
ctx.Reply(update, ext.ReplyTextString(noPermissionText), nil)
return dispatcher.EndGroups
}
return dispatcher.ContinueGroups
}
func tryCopyMedia(ctx *ext.Context, update *ext.Update) {
if !config.Cfg.AsPublicCopyMediaBot {
return
}
if update.EffectiveMessage == nil || update.EffectiveMessage.Message == nil {
return
}
common.Log.Tracef("Got copy media request from %d", update.EffectiveChat().GetID())
msg := update.EffectiveMessage.Message
if link := linkRegex.FindString(update.EffectiveMessage.Text); link != "" {
linkChatID, messageID, err := parseLink(ctx, link)
if err != nil {
return
}
fileMessage, err := GetTGMessage(ctx, linkChatID, messageID)
if err != nil {
return
}
if fileMessage == nil || fileMessage.Media == nil {
return
}
msg = fileMessage
}
if _, err := copyMediaToChat(ctx, msg, update.EffectiveChat().GetID()); err != nil {
common.Log.Errorf("Failed to copy media: %v", err)
}
}

View File

@@ -49,9 +49,9 @@ func getSelectStorageMarkup(userChatID int64, fileChatID, fileMessageID int) (*t
return nil, fmt.Errorf("failed to get user by chat ID: %d, error: %w", userChatID, err)
}
storages := storage.GetUserStorages(user.ChatID)
if len(storages) == 0 {
return nil, ErrNoStorages
}
// if len(storages) == 0 {
// return nil, ErrNoStorages
// }
buttons := make([]tg.KeyboardButtonClass, 0)
for _, storage := range storages {
@@ -216,7 +216,7 @@ func GetTGMessage(ctx *ext.Context, chatId int64, messageID int) (*tg.Message, e
if err == nil {
return cacheMessage, nil
}
common.Log.Debugf("Fetching message: %d", messageID)
common.Log.Debugf("Fetching message: %d:%d", chatId, messageID)
messages, err := ctx.GetMessages(chatId, []tg.InputMessageClass{&tg.InputMessageID{ID: messageID}})
if err != nil {
return nil, err

View File

@@ -17,6 +17,9 @@ type Config struct {
Threads int `toml:"threads" mapstructure:"threads" json:"threads"`
Stream bool `toml:"stream" mapstructure:"stream" json:"stream"`
// Experimental: 将拷贝媒体文件的功能设为公开可用
AsPublicCopyMediaBot bool `toml:"as_public_copy_media_bot" mapstructure:"as_public_copy_media_bot" json:"as_public_copy_media_bot"`
Users []userConfig `toml:"users" mapstructure:"users" json:"users"`
Temp tempConfig `toml:"temp" mapstructure:"temp"`

46
docs/docs/experimental.md Normal file
View File

@@ -0,0 +1,46 @@
# 实验性功能
这里的功能不太稳定, 且未来可能会被删除或修改。
## 存储规则
允许你为 Bot 在上传文件到存储时设置一些重定向规则, 用于自动整理所保存的文件.
见: https://github.com/krau/SaveAny-Bot/issues/28
目前支持的规则类型:
1. FILENAME-REGEX
2. MESSAGE-REGEX
添加规则的基本语法:
"规则类型 规则内容 存储名 路径"
注意空格的使用, 语法正确 bot 才能解析, 以下是一条合法的添加规则命令:
```
/rule add FILENAME-REGEX (?i)\.(mp4|mkv|ts|avi|flv)$ MyAlist /视频
```
此外, 规则中的存储名若使用 "CHOSEN" , 则表示存储到点击按钮选择的存储端的路径下
规则介绍:
### FILENAME-REGEX
根据文件名正则匹配, 规则内容要求为一个合法的正则表达式, 如
```
FILENAME-REGEX (?i)\.(mp4|mkv|ts|avi|flv)$ MyAlist /视频
```
表示将文件名后缀为 mp4,mkv,ts,avi,flv 的文件放到名为 MyAlist 存储下的 /视频 目录内 (同时受配置文件中的 `base_path` 影响)
### MESSAGE-REGEX
同上, 根据消息文本内容正则匹配
## 复制并发送媒体消息
将接收到的文件(媒体)消息, 或链接对应的消息原样发送到当前聊天, 点击选择存储按钮中的 "发送到当前聊天" 即可.

View File

@@ -35,4 +35,4 @@ Bot 接受两种消息: 文件和链接.
**不支持** Stream 模式的存储端:
- alist
- alist

View File

@@ -30,5 +30,6 @@ nav:
- index.md
- deploy.md
- help.md
- experimental.md
- faq.md
- contribute.md