新增功能: 重名文件时选择保存策略 - 重命名,覆盖,跳过#204
Open
Rain-kl wants to merge 2 commits into
Open
Conversation
feat: implement conflict resolution strategy for file uploads
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR adds duplicate-name handling for Telegram file downloads by prompting the user to choose a save strategy when a target filename already exists.
Changes:
- Adds conflict-strategy selection (
rename,overwrite,skip) to the add-task flow and persists the choice through callback data. - Propagates overwrite behavior into storage backends and adds skipped-file reporting to batch task messages/progress.
- Adds new i18n strings and context keys needed for the conflict prompt and result summaries.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| storage/webdav/webdav.go | Updates WebDAV save logic to honor overwrite mode and refactors existence checks. |
| storage/s3/s3.go | Updates S3 save logic to skip renaming when overwrite is selected. |
| storage/rclone/rclone.go | Gates the existing rename loop behind the overwrite flag for rclone storage. |
| storage/minio/client.go | Adds overwrite-aware save behavior and a helper for object existence checks. |
| storage/local/local.go | Adds overwrite-aware local save behavior and refactors path existence checks. |
| storage/context.go | Adds context helpers for setting and reading overwrite mode. |
| storage/alist/alist.go | Adds overwrite-aware save behavior and refactors existence checks for Alist. |
| pkg/tcbdata/data.go | Extends callback payload data with conflict-strategy and selected directory path. |
| pkg/enums/ctxkey/context_key_enum.go | Registers the new overwrite-existing context key. |
| pkg/enums/ctxkey/context_key.go | Updates enum source definition for the new context key. |
| core/tasks/batchtfile/progress.go | Adds skipped-file reporting to batch progress completion output. |
| common/i18n/locale/zh-Hans.yaml | Adds Chinese strings for conflict prompts/buttons and skipped-file notices. |
| common/i18n/locale/en.yaml | Adds English strings for conflict prompts/buttons and skipped-file notices. |
| common/i18n/i18nk/keys.go | Adds i18n key constants for the new conflict-related messages. |
| client/bot/handlers/utils/shortcut/tftask.go | Adds conflict prompting, skip/overwrite handling, and skipped-file summaries in task creation helpers. |
| client/bot/handlers/utils/msgelem/storage.go | Adds inline keyboard generation for conflict-strategy selection. |
| client/bot/handlers/add_task.go | Adds conflict pre-checking in the add-task callback flow before creating TG file tasks. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+61
to
+63
| if overwrite, _ := ctx.Value(ctxkey.OverwriteExisting).(bool); !overwrite { | ||
| for i := 1; w.existsPath(ctx, candidate); i++ { | ||
| candidate = fmt.Sprintf("%s_%d%s", base, i, ext) |
Comment on lines
+85
to
89
| return w.existsPath(ctx, w.JoinStoragePath(storagePath)) | ||
| } | ||
|
|
||
| func (w *Webdav) existsPath(ctx context.Context, storagePath string) bool { | ||
| exists, err := w.client.Exists(ctx, storagePath) |
Comment on lines
+73
to
+76
| if overwrite, _ := ctx.Value(ctxkey.OverwriteExisting).(bool); !overwrite { | ||
| // Unique filename | ||
| for i := 1; m.existsKey(ctx, candidate); i++ { | ||
| candidate = fmt.Sprintf("%s_%d%s", base, i, ext) |
Comment on lines
+104
to
+108
| return m.existsKey(ctx, m.JoinStoragePath(storagePath)) | ||
| } | ||
|
|
||
| func (m *S3) existsKey(ctx context.Context, key string) bool { | ||
| return m.client.Exists(ctx, key) |
Comment on lines
+84
to
+86
| if overwrite, _ := ctx.Value(ctxkey.OverwriteExisting).(bool); !overwrite { | ||
| for i := 1; m.existsObject(ctx, candidate); i++ { | ||
| candidate = fmt.Sprintf("%s_%d%s", base, i, ext) |
Comment on lines
+84
to
+102
| conflicts, err := findTGFileConflicts(ctx, userID, selectedStorage, dirPath, data.Files) | ||
| if err != nil { | ||
| ctx.AnswerCallback(msgelem.AlertCallbackAnswer(queryID, err.Error())) | ||
| return dispatcher.EndGroups | ||
| } | ||
| if len(conflicts) > 0 && data.ConflictStrategy == "" { | ||
| markup, err := msgelem.BuildConflictStrategyMarkup(data) | ||
| if err != nil { | ||
| ctx.AnswerCallback(msgelem.AlertCallbackAnswer(queryID, i18n.T(i18nk.BotMsgCommonErrorBuildStorageSelectKeyboardFailed, map[string]any{ | ||
| "Error": err.Error(), | ||
| }))) | ||
| return dispatcher.EndGroups | ||
| } | ||
| ctx.EditMessage(userID, &tg.MessagesEditMessageRequest{ | ||
| ID: update.CallbackQuery.GetMsgID(), | ||
| Message: i18n.T(i18nk.BotMsgCommonPromptSelectConflictStrategy, map[string]any{"Files": formatConflictFiles(conflicts)}), | ||
| ReplyMarkup: markup, | ||
| }) | ||
| return dispatcher.EndGroups |
Comment on lines
+105
to
+107
| return shortcut.CreateAndAddBatchTGFileTaskWithEdit(ctx, userID, selectedStorage, dirPath, data.Files, msgID, data.ConflictStrategy) | ||
| } | ||
| return shortcut.CreateAndAddTGFileTaskWithEdit(ctx, userID, selectedStorage, dirPath, data.Files[0], msgID) | ||
| return shortcut.CreateAndAddTGFileTaskWithEdit(ctx, userID, selectedStorage, dirPath, data.Files[0], msgID, data.ConflictStrategy) |
| if len(conflicts) > 0 && data.ConflictStrategy == "" { | ||
| markup, err := msgelem.BuildConflictStrategyMarkup(data) | ||
| if err != nil { | ||
| ctx.AnswerCallback(msgelem.AlertCallbackAnswer(queryID, i18n.T(i18nk.BotMsgCommonErrorBuildStorageSelectKeyboardFailed, map[string]any{ |
Comment on lines
+329
to
+332
| return i18n.T(i18nk.BotMsgCommonInfoBatchTasksAddedWithSkipped, map[string]any{ | ||
| "Count": count, | ||
| "Skipped": strings.Join(skipped, "\n"), | ||
| }) |
Comment on lines
+160
to
+162
| return styling.Plain("\n\n" + i18n.T(i18nk.BotMsgCommonInfoConflictFilesSkipped, map[string]any{ | ||
| "Skipped": strings.Join(p.skippedFiles, "\n"), | ||
| })) |
Owner
|
hi, 感谢贡献. 该功能在本地已经测试过了吗? 有没有增加把某个策略设为默认的选项呢? (比如某些频道的几乎所有文件的文件名完全一样, 保存它们的时候如果要一一选择会不太方便) |
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


bot 下载文件前先检查文件名是否存在重复, 如果重复则要求用户选择保存策略
重命名: 现有策略-重命名文件末尾加_1
覆盖: 覆盖文件
跳过: 不处理