diff --git a/client/bot/handlers/add_task.go b/client/bot/handlers/add_task.go index f692949..dee3415 100644 --- a/client/bot/handlers/add_task.go +++ b/client/bot/handlers/add_task.go @@ -43,7 +43,7 @@ func handleAddCallback(ctx *ext.Context, update *ext.Update) error { if !data.SettedDir && len(dirs) != 0 { // ask for directory selection - markup, err := msgelem.BuildSetDirKeyboard(dirs, dataid) + markup, err := msgelem.BuildSetDirMarkupForAdd(dirs, dataid) if err != nil { log.FromContext(ctx).Errorf("Failed to build directory keyboard: %s", err) ctx.AnswerCallback(msgelem.AlertCallbackAnswer(queryID, "目录键盘构建失败: "+err.Error())) diff --git a/client/bot/handlers/link.go b/client/bot/handlers/link.go index 4ac0e54..107530a 100644 --- a/client/bot/handlers/link.go +++ b/client/bot/handlers/link.go @@ -6,6 +6,7 @@ import ( "github.com/celestix/gotgproto/dispatcher" "github.com/celestix/gotgproto/ext" "github.com/charmbracelet/log" + "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" "github.com/krau/SaveAny-Bot/pkg/tcbdata" @@ -56,7 +57,7 @@ func handleSilentSaveLink(ctx *ext.Context, update *ext.Update) error { } userId := update.GetUserChat().GetID() if len(files) == 1 { - return shortcut.CreateAndAddTGFileTaskWithEdit(ctx, userId, stor, "", files[0], replied.ID) + return shortcut.CreateAndAddTGFileTaskWithEdit(ctx, userId, stor, dirutil.PathFromContext(ctx), files[0], replied.ID) } - return shortcut.CreateAndAddBatchTGFileTaskWithEdit(ctx, userId, stor, "", files, replied.ID) + return shortcut.CreateAndAddBatchTGFileTaskWithEdit(ctx, userId, stor, dirutil.PathFromContext(ctx), files, replied.ID) } diff --git a/client/bot/handlers/media.go b/client/bot/handlers/media.go index b9c8237..9891af5 100644 --- a/client/bot/handlers/media.go +++ b/client/bot/handlers/media.go @@ -9,6 +9,7 @@ import ( "github.com/celestix/gotgproto/ext" "github.com/charmbracelet/log" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/mediautil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" @@ -32,12 +33,6 @@ func handleMediaMessage(ctx *ext.Context, update *ext.Update) error { if err != nil { return err } - // tfOpts := make([]tfile.TGFileOption, 0) - // switch userDB.FilenameStrategy { - // case fnamest.Message.String(): - // tfOpts = append(tfOpts, tfile.WithName(tgutil.GenFileNameFromMessage(*message))) - // default: - // } tfOpts := mediautil.TfileOptions(ctx, userDB, message) msg, file, err := shortcut.GetFileFromMessageWithReply(ctx, update, message, tfOpts...) if err != nil { @@ -74,18 +69,12 @@ func handleSilentSaveMedia(ctx *ext.Context, update *ext.Update) error { if err != nil { return err } - // tfOpts := make([]tfile.TGFileOption, 0) - // switch userDB.FilenameStrategy { - // case fnamest.Message.String(): - // tfOpts = append(tfOpts, tfile.WithName(tgutil.GenFileNameFromMessage(*message))) - // default: - // } tfOpts := mediautil.TfileOptions(ctx, userDB, message) msg, file, err := shortcut.GetFileFromMessageWithReply(ctx, update, message, tfOpts...) if err != nil { return err } - return shortcut.CreateAndAddTGFileTaskWithEdit(ctx, userID, stor, "", file, msg.ID) + return shortcut.CreateAndAddTGFileTaskWithEdit(ctx, userID, stor, dirutil.PathFromContext(ctx), file, msg.ID) } type MediaGroupHandler struct { diff --git a/client/bot/handlers/middleware.go b/client/bot/handlers/middleware.go index c00e73f..1840f10 100644 --- a/client/bot/handlers/middleware.go +++ b/client/bot/handlers/middleware.go @@ -4,6 +4,7 @@ import ( "github.com/celestix/gotgproto/dispatcher" "github.com/celestix/gotgproto/ext" "github.com/duke-git/lancet/v2/slice" + "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" "github.com/krau/SaveAny-Bot/config" "github.com/krau/SaveAny-Bot/database" "github.com/krau/SaveAny-Bot/storage" @@ -43,6 +44,14 @@ func handleSilentMode(next func(*ext.Context, *ext.Update) error, handler func(* ctx.Reply(update, ext.ReplyTextString("获取默认存储失败: "+err.Error()), nil) return dispatcher.EndGroups } + if user.DefaultDir != 0 { + dir, err := database.GetDirByID(ctx, user.DefaultDir) + if err != nil { + ctx.Reply(update, ext.ReplyTextString("获取默认文件夹失败: "+err.Error()), nil) + return next(ctx, update) + } + ctx.Context = dirutil.WithContext(ctx.Context, dir) + } ctx.Context = storage.WithContext(ctx.Context, stor) return handler(ctx, update) } diff --git a/client/bot/handlers/parse.go b/client/bot/handlers/parse.go index 26352aa..79b299b 100644 --- a/client/bot/handlers/parse.go +++ b/client/bot/handlers/parse.go @@ -4,12 +4,14 @@ package handlers import ( "errors" + "path" "strings" "github.com/celestix/gotgproto/dispatcher" "github.com/celestix/gotgproto/ext" "github.com/charmbracelet/log" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" "github.com/krau/SaveAny-Bot/common/utils/fsutil" @@ -117,5 +119,8 @@ func handleSilentSaveText(ctx *ext.Context, u *ext.Update) error { if len(item.Resources) > 1 { dirPath = fsutil.NormalizePathname(item.Title) } + if p := dirutil.PathFromContext(ctx); p != "" { + dirPath = path.Join(p, dirPath) + } return shortcut.CreateAndAddParsedTaskWithEdit(ctx, stor, dirPath, item, msg.ID, userID) } diff --git a/client/bot/handlers/save.go b/client/bot/handlers/save.go index ca94918..eba2f31 100644 --- a/client/bot/handlers/save.go +++ b/client/bot/handlers/save.go @@ -9,6 +9,7 @@ import ( "github.com/celestix/gotgproto/ext" "github.com/charmbracelet/log" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/mediautil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" @@ -87,17 +88,6 @@ func handleSilentSaveReplied(ctx *ext.Context, update *ext.Update) error { ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgSaveHelpText)), nil) return dispatcher.EndGroups } - // genFilename := func() string { - // if len(args) > 1 { - // return args[1] - // } - // filename := tgutil.GenFileNameFromMessage(*replyTo.Message) - // return filename - // }() - // option := tfile.WithNameIfEmpty(genFilename) - // if len(args) > 1 { - // option = tfile.WithName(genFilename) - // } userDB, err := database.GetUserByChatID(ctx, update.GetUserChat().GetID()) if err != nil { return err @@ -111,7 +101,7 @@ func handleSilentSaveReplied(ctx *ext.Context, update *ext.Update) error { if err != nil { return err } - return shortcut.CreateAndAddTGFileTaskWithEdit(ctx, update.GetUserChat().GetID(), stor, "", file, msg.GetID()) + return shortcut.CreateAndAddTGFileTaskWithEdit(ctx, update.GetUserChat().GetID(), stor, dirutil.PathFromContext(ctx), file, msg.GetID()) } func handleBatchSave(ctx *ext.Context, update *ext.Update, args []string) error { diff --git a/client/bot/handlers/silent.go b/client/bot/handlers/silent.go index 53c46bb..ef63320 100644 --- a/client/bot/handlers/silent.go +++ b/client/bot/handlers/silent.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "strings" "github.com/celestix/gotgproto/dispatcher" @@ -36,51 +37,71 @@ func handleSilentCmd(ctx *ext.Context, update *ext.Update) error { func handleSetDefaultCallback(ctx *ext.Context, update *ext.Update) error { dataid := strings.Split(string(update.CallbackQuery.Data), " ")[1] data, ok := cache.Get[tcbdata.SetDefaultStorage](dataid) - if !ok { + + failedAnswer := func(message string) error { ctx.AnswerCallback(&tg.MessagesSetBotCallbackAnswerRequest{ QueryID: update.CallbackQuery.GetQueryID(), Alert: true, - Message: "数据已过期", + Message: message, CacheTime: 5, }) return dispatcher.EndGroups } + + if !ok { + return failedAnswer("数据已过期") + } userID := update.CallbackQuery.GetUserID() storageName := data.StorageName selectedStorage, err := storage.GetStorageByUserIDAndName(ctx, userID, storageName) if err != nil { - ctx.AnswerCallback(&tg.MessagesSetBotCallbackAnswerRequest{ - QueryID: update.CallbackQuery.GetQueryID(), - Alert: true, - Message: "存储获取失败: " + err.Error(), - CacheTime: 5, - }) - return dispatcher.EndGroups + return failedAnswer("存储获取失败: " + err.Error()) } user, err := database.GetUserByChatID(ctx, userID) if err != nil { - ctx.AnswerCallback(&tg.MessagesSetBotCallbackAnswerRequest{ - QueryID: update.CallbackQuery.GetQueryID(), - Alert: true, - Message: "获取用户信息失败: " + err.Error(), - CacheTime: 5, - }) - return dispatcher.EndGroups + return failedAnswer("获取用户信息失败: " + err.Error()) + } + var dir *database.Dir + if data.DirID != 0 { + // 已经选择了文件夹 + var err error + dir, err = database.GetDirByID(ctx, data.DirID) + if err != nil { + return failedAnswer("获取文件夹信息失败: " + err.Error()) + } + user.DefaultDir = dir.ID + } else { + // 检查是否有可用的文件夹 + dirs, err := database.GetDirsByUserIDAndStorageName(ctx, user.ID, storageName) + if err != nil { + return failedAnswer("获取目录失败: " + err.Error()) + } + if len(dirs) > 0 { + // 要求选择文件夹 + markup, err := msgelem.BuildSetDefaultDirMarkup(ctx, storageName, dirs) + if err != nil { + return failedAnswer("构建目录选择失败: " + err.Error()) + } + ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ + ID: update.CallbackQuery.GetMsgID(), + Message: "请选择要保存到的默认文件夹", + ReplyMarkup: markup, + }) + return dispatcher.EndGroups + } } user.DefaultStorage = selectedStorage.Name() if err := database.UpdateUser(ctx, user); err != nil { - ctx.AnswerCallback(&tg.MessagesSetBotCallbackAnswerRequest{ - QueryID: update.CallbackQuery.GetQueryID(), - Alert: true, - Message: "更新用户信息失败: " + err.Error(), - CacheTime: 5, - }) - return dispatcher.EndGroups + return failedAnswer("更新用户信息失败: " + err.Error()) + } + msg := fmt.Sprintf("已将默认存储位置设为: %s", selectedStorage.Name()) + if dir != nil { + msg += fmt.Sprintf(":/%s", strings.TrimPrefix(dir.Path, "/")) } ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ ID: update.CallbackQuery.GetMsgID(), - Message: "已将默认存储位置设置为: " + selectedStorage.Name(), + Message: msg, }) return dispatcher.EndGroups } @@ -92,7 +113,7 @@ func handleStorageCmd(ctx *ext.Context, update *ext.Update) error { ctx.Reply(update, ext.ReplyTextString("无可用的存储"), nil) return nil } - markup, err := msgelem.BuildSetDefaultStorageMarkup(ctx, userID, storages) + markup, err := msgelem.BuildSetDefaultStorageMarkup(ctx, storages) if err != nil { ctx.Reply(update, ext.ReplyTextString("获取存储失败: "+err.Error()), nil) return nil diff --git a/client/bot/handlers/telegraph.go b/client/bot/handlers/telegraph.go index 6a660f6..ce2227e 100644 --- a/client/bot/handlers/telegraph.go +++ b/client/bot/handlers/telegraph.go @@ -2,6 +2,7 @@ package handlers import ( "fmt" + "path" "github.com/celestix/gotgproto/dispatcher" "github.com/celestix/gotgproto/ext" @@ -9,6 +10,7 @@ import ( "github.com/gotd/td/telegram/message/entity" "github.com/gotd/td/telegram/message/styling" "github.com/gotd/td/tg" + "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/dirutil" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem" "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/shortcut" "github.com/krau/SaveAny-Bot/pkg/enums/tasktype" @@ -71,6 +73,10 @@ func handleSilentSaveTelegraph(ctx *ext.Context, update *ext.Update) error { return err } userID := update.GetUserChat().GetID() - return shortcut.CreateAndAddtelegraphWithEdit(ctx, userID, result.Page, result.TphDir, result.Pics, stor, msg.ID) + dirpath := result.TphDir + if p := dirutil.PathFromContext(ctx); p != "" { + dirpath = path.Join(p, dirpath) + } + return shortcut.CreateAndAddtelegraphWithEdit(ctx, userID, result.Page, dirpath, result.Pics, stor, msg.ID) } diff --git a/client/bot/handlers/utils/dirutil/context.go b/client/bot/handlers/utils/dirutil/context.go new file mode 100644 index 0000000..95eabd4 --- /dev/null +++ b/client/bot/handlers/utils/dirutil/context.go @@ -0,0 +1,37 @@ +package dirutil + +import ( + "context" + + "github.com/krau/SaveAny-Bot/database" +) + +type contextKey struct{} + +var dirContextKey = contextKey{} + +func WithContext(ctx context.Context, dir *database.Dir) context.Context { + if dir == nil { + return ctx + } + return context.WithValue(ctx, dirContextKey, dir) +} + +func FromContext(ctx context.Context) *database.Dir { + dir, ok := ctx.Value(dirContextKey).(*database.Dir) + if !ok { + return nil + } + return dir +} + +// PathFromContext returns the directory path stored in the context. +// +// If no directory is found, an empty string is returned. +func PathFromContext(ctx context.Context) string { + dir := FromContext(ctx) + if dir == nil { + return "" + } + return dir.Path +} diff --git a/client/bot/handlers/utils/msgelem/storage.go b/client/bot/handlers/utils/msgelem/storage.go index c8d0822..e66899b 100644 --- a/client/bot/handlers/utils/msgelem/storage.go +++ b/client/bot/handlers/utils/msgelem/storage.go @@ -94,7 +94,10 @@ func BuildAddOneSelectStorageMessage(ctx context.Context, stors []storage.Storag }, nil } -func BuildSetDefaultStorageMarkup(ctx context.Context, userID int64, stors []storage.Storage) (*tg.ReplyInlineMarkup, error) { +// Builds the inline keyboard for setting default storage +func BuildSetDefaultStorageMarkup( + ctx context.Context, + stors []storage.Storage) (*tg.ReplyInlineMarkup, error) { buttons := make([]tg.KeyboardButtonClass, 0) for _, storage := range stors { data := tcbdata.SetDefaultStorage{ @@ -119,7 +122,35 @@ func BuildSetDefaultStorageMarkup(ctx context.Context, userID int64, stors []sto return markup, nil } -func BuildSetDirKeyboard(dirs []database.Dir, dataid string) (*tg.ReplyInlineMarkup, error) { +func BuildSetDefaultDirMarkup(ctx context.Context, + seletedStorage string, + dirs []database.Dir) (*tg.ReplyInlineMarkup, error) { + buttons := make([]tg.KeyboardButtonClass, 0) + for _, dir := range dirs { + dataid := xid.New().String() + data := tcbdata.SetDefaultStorage{ + StorageName: seletedStorage, + DirID: dir.ID, + } + err := cache.Set(dataid, data) + if err != nil { + return nil, err + } + buttons = append(buttons, &tg.KeyboardButtonCallback{ + Text: dir.Path, + Data: fmt.Appendf(nil, "%s %s", tcbdata.TypeSetDefault, dataid), + }) + } + markup := &tg.ReplyInlineMarkup{} + for i := 0; i < len(buttons); i += 3 { + row := tg.KeyboardButtonRow{} + row.Buttons = buttons[i:min(i+3, len(buttons))] + markup.Rows = append(markup.Rows, row) + } + return markup, nil +} + +func BuildSetDirMarkupForAdd(dirs []database.Dir, dataid string) (*tg.ReplyInlineMarkup, error) { data, ok := cache.Get[tcbdata.Add](dataid) if !ok { return nil, fmt.Errorf("failed to get data from cache: %s", dataid) diff --git a/database/model.go b/database/model.go index ab24cd8..7c249b3 100644 --- a/database/model.go +++ b/database/model.go @@ -9,6 +9,7 @@ type User struct { ChatID int64 `gorm:"uniqueIndex;not null"` Silent bool DefaultStorage string + DefaultDir uint // Dir.ID Dirs []Dir ApplyRule bool Rules []Rule diff --git a/pkg/tcbdata/data.go b/pkg/tcbdata/data.go index 3816aa9..980823d 100644 --- a/pkg/tcbdata/data.go +++ b/pkg/tcbdata/data.go @@ -10,7 +10,7 @@ import ( const ( TypeAdd = "add" TypeSetDefault = "setdefault" - TypeConfig = "config" + TypeConfig = "config" TypeCancel = "cancel" ) @@ -47,4 +47,5 @@ type Add struct { type SetDefaultStorage struct { StorageName string + DirID uint }