mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-05-12 02:09:43 +08:00
feat: implement transfer command for file transfers between storages
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
@@ -84,15 +85,15 @@ func (t *Task) processElement(ctx context.Context, elem TaskElement) error {
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
// Build Telegram storage path: /<chat_id>/<filename>
|
||||
storagePath := fmt.Sprintf("/%d/%s", elem.TargetChatID, elem.FileInfo.Name)
|
||||
// Build target storage path: /target_path/filename
|
||||
storagePath := path.Join(elem.TargetPath, elem.FileInfo.Name)
|
||||
|
||||
// 注入文件大小到 context
|
||||
// Inject file size into context
|
||||
ctx = context.WithValue(ctx, ctxkey.ContentLength, size)
|
||||
|
||||
if config.C().Stream {
|
||||
if err := elem.TargetStorage.Save(ctx, reader, storagePath); err != nil {
|
||||
return fmt.Errorf("failed to upload file to telegram: %w", err)
|
||||
return fmt.Errorf("failed to upload file to storage: %w", err)
|
||||
}
|
||||
} else {
|
||||
logger.Info("Downloading to temporary file for ReadSeeker support")
|
||||
@@ -107,9 +108,9 @@ func (t *Task) processElement(ctx context.Context, elem TaskElement) error {
|
||||
return fmt.Errorf("failed to seek temp file: %w", err)
|
||||
}
|
||||
|
||||
logger.Infof("Uploading file to Telegram storage (size: %d bytes)", size)
|
||||
logger.Infof("Uploading file to storage (size: %d bytes)", size)
|
||||
if err := elem.TargetStorage.Save(ctx, tempFile, storagePath); err != nil {
|
||||
return fmt.Errorf("failed to upload file to telegram: %w", err)
|
||||
return fmt.Errorf("failed to upload file to storage: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,14 +43,14 @@ func (p *Progress) OnStart(ctx context.Context, info TaskInfo) {
|
||||
log.FromContext(ctx).Debugf("Batch import task progress tracking started for message %d in chat %d", p.MessageID, p.ChatID)
|
||||
|
||||
sizeMB := float64(info.TotalSize()) / (1024 * 1024)
|
||||
statsText := i18n.T(i18nk.BotMsgImportStartStats, map[string]any{
|
||||
"SizeMB": fmt.Sprintf("%.2f", sizeMB),
|
||||
"Count": info.Count(),
|
||||
statsText := i18n.T(i18nk.BotMsgTransferStartStats, map[string]any{
|
||||
"SizeMB": fmt.Sprintf("%.2f", sizeMB),
|
||||
"Count": info.Count(),
|
||||
})
|
||||
|
||||
entityBuilder := entity.Builder{}
|
||||
if err := styling.Perform(&entityBuilder,
|
||||
styling.Plain(i18n.T(i18nk.BotMsgProgressImportStartPrefix, nil)),
|
||||
styling.Plain(i18n.T(i18nk.BotMsgProgressTransferStartPrefix, nil)),
|
||||
styling.Code(statsText),
|
||||
); err != nil {
|
||||
log.FromContext(ctx).Errorf("Failed to build entities: %s", err)
|
||||
@@ -94,9 +94,9 @@ func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
||||
entityBuilder := entity.Builder{}
|
||||
var progressText strings.Builder
|
||||
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressImportProgressPrefix, nil))
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressTransferProgressPrefix, nil))
|
||||
progressText.WriteString(fmt.Sprintf("%d%%", percent))
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressImportUploadedPrefix, nil))
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressTransferUploadedPrefix, nil))
|
||||
progressText.WriteString(fmt.Sprintf("%.2f MB / %.2f MB",
|
||||
float64(info.Uploaded())/(1024*1024),
|
||||
float64(info.TotalSize())/(1024*1024)))
|
||||
@@ -104,22 +104,22 @@ func (p *Progress) OnProgress(ctx context.Context, info TaskInfo) {
|
||||
if p.start.Unix() > 0 {
|
||||
elapsed := time.Since(p.start)
|
||||
speed := float64(info.Uploaded()) / elapsed.Seconds()
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressImportSpeedPrefix, nil))
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressTransferSpeedPrefix, nil))
|
||||
progressText.WriteString(dlutil.FormatSize(int64(speed)) + "/s")
|
||||
|
||||
if info.Uploaded() > 0 {
|
||||
remaining := time.Duration(float64(info.TotalSize()-info.Uploaded()) / speed * float64(time.Second))
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressImportRemainingTimePrefix, nil))
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressTransferRemainingTimePrefix, nil))
|
||||
progressText.WriteString(formatDuration(remaining))
|
||||
}
|
||||
}
|
||||
|
||||
processing := info.Processing()
|
||||
if len(processing) > 0 {
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressImportProcessingPrefix, nil))
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressTransferProcessingPrefix, nil))
|
||||
for i, elem := range processing {
|
||||
if i >= 3 {
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressImportProcessingMore, map[string]any{"Count": len(processing) - 3}))
|
||||
progressText.WriteString(i18n.T(i18nk.BotMsgProgressTransferProcessingMore, map[string]any{"Count": len(processing) - 3}))
|
||||
break
|
||||
}
|
||||
fmt.Fprintf(&progressText, "- %s\n", elem.FileName())
|
||||
@@ -162,36 +162,36 @@ func (p *Progress) OnDone(ctx context.Context, info TaskInfo, err error) {
|
||||
var resultText strings.Builder
|
||||
|
||||
if err != nil {
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressImportFailedPrefix, nil))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressTransferFailedPrefix, nil))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressErrorPrefix, nil))
|
||||
fmt.Fprintf(&resultText, "%v\n", err)
|
||||
} else {
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressImportSuccessPrefix, nil))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressTransferSuccessPrefix, nil))
|
||||
}
|
||||
|
||||
elapsed := time.Since(p.start)
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressImportTotalFilesPrefix, nil))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressTransferTotalFilesPrefix, nil))
|
||||
fmt.Fprintf(&resultText, "%d\n", info.Count())
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressImportTotalSizePrefix, nil))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressTransferTotalSizePrefix, nil))
|
||||
fmt.Fprintf(&resultText, "%.2f MB\n", float64(info.TotalSize())/(1024*1024))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressImportUploadedPrefix, nil))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressTransferUploadedPrefix, nil))
|
||||
fmt.Fprintf(&resultText, "%.2f MB\n", float64(info.Uploaded())/(1024*1024))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressImportElapsedTimePrefix, nil))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressTransferElapsedTimePrefix, nil))
|
||||
fmt.Fprintf(&resultText, "%s\n", formatDuration(elapsed))
|
||||
|
||||
if elapsed.Seconds() > 0 {
|
||||
avgSpeed := float64(info.Uploaded()) / elapsed.Seconds()
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressImportAvgSpeedPrefix, nil))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressTransferAvgSpeedPrefix, nil))
|
||||
fmt.Fprintf(&resultText, "%s/s\n", dlutil.FormatSize(int64(avgSpeed)))
|
||||
}
|
||||
|
||||
failedFiles := info.FailedFiles()
|
||||
if len(failedFiles) > 0 {
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressImportFailedFilesPrefix, nil))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressTransferFailedFilesPrefix, nil))
|
||||
fmt.Fprintf(&resultText, "%d\n", len(failedFiles))
|
||||
for i, name := range failedFiles {
|
||||
if i >= 5 {
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressImportProcessingMore, map[string]any{"Count": len(failedFiles) - 5}))
|
||||
resultText.WriteString(i18n.T(i18nk.BotMsgProgressTransferProcessingMore, map[string]any{"Count": len(failedFiles) - 5}))
|
||||
break
|
||||
}
|
||||
fmt.Fprintf(&resultText, "- %s\n", name)
|
||||
|
||||
@@ -21,7 +21,7 @@ type TaskElement struct {
|
||||
SourcePath string
|
||||
FileInfo storagetypes.FileInfo
|
||||
TargetStorage storage.Storage
|
||||
TargetChatID int64
|
||||
TargetPath string
|
||||
}
|
||||
|
||||
type Task struct {
|
||||
@@ -56,7 +56,7 @@ func NewTaskElement(
|
||||
sourceStorage storage.Storage,
|
||||
fileInfo storagetypes.FileInfo,
|
||||
targetStorage storage.Storage,
|
||||
targetChatID int64,
|
||||
targetPath string,
|
||||
) *TaskElement {
|
||||
id := xid.New().String()
|
||||
return &TaskElement{
|
||||
@@ -65,7 +65,7 @@ func NewTaskElement(
|
||||
SourcePath: fileInfo.Path,
|
||||
FileInfo: fileInfo,
|
||||
TargetStorage: targetStorage,
|
||||
TargetChatID: targetChatID,
|
||||
TargetPath: targetPath,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user