From c54aae2daf8d64fb521656a5628474c37ad75d5e Mon Sep 17 00:00:00 2001 From: "jiaji.H" Date: Thu, 26 Mar 2026 15:28:02 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Updata=EF=BC=9A=E6=9B=B4=E6=96=B0=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/service/file/file.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/service/file/file.go b/pkg/service/file/file.go index 66700ac3..1217c03a 100644 --- a/pkg/service/file/file.go +++ b/pkg/service/file/file.go @@ -210,7 +210,7 @@ func TusUpload(ctx *gin.Context) { return } if !isLikelyMP4(b) { - service.Error(ctx, errors.New("mp4机器码校验失败")) + service.Error(ctx, errors.New(".mp4机器码校验错误,该文件可能不是标准的.mp4文件")) //删除对应空文件 _, err = service.FilesProvider.Delete(ctx, &files.DeleteReq{ Path: ctx.DefaultQuery("path", "/"), From ef07239dc6bce5c0a7d4e70b0545826c206f4bd9 Mon Sep 17 00:00:00 2001 From: "jiaji.H" Date: Thu, 26 Mar 2026 15:54:06 +0800 Subject: [PATCH 2/2] =?UTF-8?q?Updata=EF=BC=9A=E5=A2=9E=E5=8A=A0=E5=88=86?= =?UTF-8?q?=E7=89=87=E4=B8=8A=E4=BC=A0=E6=B5=8B=E8=AF=95=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/router/router.go | 1 + pkg/service/file/file.go | 80 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/pkg/router/router.go b/pkg/router/router.go index 9fb1c2ff..a5a93c29 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -171,6 +171,7 @@ func NewRouter() *gin.Engine { resourceRoute.POST("/upload", file.Upload) resourceRoute.POST("/tus/create", file.TusCreate) resourceRoute.POST("/tus/upload", file.TusUpload) + resourceRoute.POST("/tus/upload/mp4", file.TusUploadMP4) v1.Group("/resource").GET("/raw/*path", file.Raw) resourceRoute.GET("/dir/raw", file.DirDownload) resourceRoute.GET("/preview/:size/*path", file.Preview) diff --git a/pkg/service/file/file.go b/pkg/service/file/file.go index 1217c03a..cef8480b 100644 --- a/pkg/service/file/file.go +++ b/pkg/service/file/file.go @@ -12,6 +12,7 @@ import ( "io" "net/http" "net/url" + "os" "strconv" "strings" "time" @@ -238,6 +239,85 @@ func TusUpload(ctx *gin.Context) { service.Success(ctx, nil) } +func TusUploadMP4(ctx *gin.Context) { + //读取传入的本地路径文件 + var req files.TusCreateReq + if err := ctx.ShouldBindJSON(&req); err != nil { + service.Error(ctx, err) + return + } + userPath := req.UserSpacePath + req.UserSpacePath = getUserSpacePath(ctx) + fileInfo, err := os.Stat(userPath) + if err != nil { + service.Error(ctx, errors.New(common.GetFileInfoFailed)) + return + } + if fileInfo.IsDir() { + service.Error(ctx, errors.New("localPath 不能是目录")) + return + } + totalSize := fileInfo.Size() + if totalSize <= 0 { + service.Error(ctx, errors.New("文件为空")) + return + } + //如果是.mp4文件则判断文件大小 + if strings.HasSuffix(strings.ToLower(req.Path), ".mp4") && fileInfo.Size() > 1024*1024 { + //大于1mb的文件进行分块上传 + f, err := os.Open(userPath) + if err != nil { + service.Error(ctx, errors.New(common.ERROR_OPEN_FILE)) + return + } + defer f.Close() + const chunkSize int64 = 2*1024*1024 - 100 + + for offset := int64(0); offset < totalSize; { + end := offset + chunkSize + if end > totalSize { + end = totalSize + } + n := end - offset + buf := make([]byte, n) + // 用 ReadAt 读指定偏移的分片 + readN, readErr := f.ReadAt(buf, offset) + if readErr != nil && readErr != io.EOF { + service.Error(ctx, errors.New(common.ERROR_OPEN_FILE)) + return + } + if int64(readN) != n { + service.Error(ctx, errors.New("读取分片长度不一致")) + return + } + // 4) 首包 MP4 机器码校验(offset==0) + if offset == 0 { + if !isLikelyMP4(buf) { + service.Error(ctx, errors.New("mp4机器码校验失败,该文件可能不是标准 mp4")) + return + } + } + // 5) TusUpload 写入当前分片 + _, err = service.FilesProvider.TusUpload(ctx, &files.TusUploadReq{ + Path: req.Path, + UploadOffset: offset, + Content: buf, + UserSpacePath: req.UserSpacePath, + }) + if err != nil { + service.Error(ctx, errors.New(common.TusUploadFailed)) + return + } + offset = end + } + service.Success(ctx, gin.H{ + "destPath": req.Path, + "localPath": userPath, + "uploadLength": totalSize, + }) + } +} + func Preview(ctx *gin.Context) { var size int size, err := strconv.Atoi(ctx.Param("size"))