EasyAudioEncode/internal/web/api/update.go

134 lines
4.2 KiB
Go
Raw Normal View History

2025-12-25 17:01:46 +08:00
package api
import (
"easyaudioencode/internal/core/audioencode"
2025-12-31 11:29:58 +08:00
"easyaudioencode/pkg/ffmpeg"
2025-12-25 17:01:46 +08:00
"fmt"
"git.lnton.com/lnton/pkg/reason"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"io"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strings"
)
// 配置常量
const (
// 最大上传文件大小 100MB
maxUploadSize = 100 * 1024 * 1024
// 文件保存目录
uploadDir = "./uploads"
sourceDir = "source"
encodeDir = "encode"
)
var (
// 允许的文件扩展名
allowedExts = map[string]bool{
".mp3": true,
".wav": true,
}
// 允许的 MIME 类型
allowedMimeTypes = map[string]bool{
"audio/mpeg": true, // MP3
"audio/wav": true, // WAV
"audio/x-wav": true, // WAV 另一种常见 MIME
"audio/x-pn-wav": true,
}
)
// uploadAudioHandler 处理音频文件上传
func (a AudioEncodeAPI) uploadAudioHandler(c *gin.Context, _ *struct{}) (any, error) {
if err := os.MkdirAll(filepath.Join(uploadDir, sourceDir), 0755); err != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf("创建上传目录失败: %v", err.Error()))
}
2025-12-31 11:29:58 +08:00
if err := os.MkdirAll(filepath.Join(uploadDir, encodeDir), 0755); err != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf("创建转码目录失败: %v", err.Error()))
}
2025-12-25 17:01:46 +08:00
// 限制请求体大小
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxUploadSize)
if err := c.Request.ParseMultipartForm(maxUploadSize); err != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf("文件过大(最大 %dMB或解析失败: %v", maxUploadSize/1024/1024, err))
}
// 获取上传的文件
file, fileHeader, err := c.Request.FormFile("audio")
if err != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf("获取文件失败: %v", err))
}
defer file.Close()
// 1. 校验文件扩展名
fileExt := strings.ToLower(filepath.Ext(fileHeader.Filename))
sourceFileName := strings.TrimSuffix(fileHeader.Filename, fileExt)
if !allowedExts[fileExt] {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf("不支持的文件类型,仅允许 MP3/WAV当前扩展名: %s", fileExt))
}
// 2. 校验文件 MIME 类型
//mimeType, err := getFileMimeType(file)
//if err != nil {
// return nil, reason.ErrServer.SetMsg(fmt.Sprintf("获取文件 MIME 类型失败: %v", err))
//}
//if !allowedMimeTypes[mimeType] {
// return nil, reason.ErrServer.SetMsg(fmt.Sprintf("文件类型校验失败,实际 MIME: %s仅允许 MP3/WAV", mimeType))
//}
uuidStr := uuid.New().String()
// 生成唯一文件名(避免覆盖)
fileName := fmt.Sprintf("%s%s", uuidStr, fileExt)
filePath := filepath.Join(uploadDir, sourceDir, fileName)
2025-12-31 11:29:58 +08:00
outputFile := filepath.Join(uploadDir, encodeDir, fmt.Sprintf("%s.g711a", uuidStr))
2025-12-25 17:01:46 +08:00
// 创建目标文件
dstFile, err := os.Create(filePath)
if err != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf("创建文件失败: %v", err))
}
defer dstFile.Close()
// 复制文件内容
if _, err := io.Copy(dstFile, file); err != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf("保存文件失败: %v", err.Error()))
}
2025-12-31 11:29:58 +08:00
2025-12-25 17:01:46 +08:00
in := &audioencode.AddAudioEncodeInput{
2025-12-31 11:29:58 +08:00
Name: sourceFileName,
FileName: fileName,
Size: fileHeader.Size,
SourceUrl: filePath,
EncodeUrl: outputFile,
Mode: fileExt,
EncodeStatus: audioencode.EncodeStatusPing,
2025-12-25 17:01:46 +08:00
}
2025-12-31 11:29:58 +08:00
duration, _, err := ffmpeg.GetAudioDuration(filePath)
if err == nil {
in.Duration = int64(duration.Seconds())
}
info, err := a.core.AddAudioEncode(c.Request.Context(), in)
2025-12-25 17:01:46 +08:00
if err != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`add audioencode err [%s]`, err.Error()))
}
2025-12-31 11:29:58 +08:00
a.transcodeCore.StartAudioEncode(filePath, outputFile, info.ID)
2026-02-02 15:09:13 +08:00
return gin.H{"data": "上传成功!", "filePath": filePath, "filename": fileName, "size": fileHeader.Size, "ID": info.ID}, err
2025-12-25 17:01:46 +08:00
}
// getFileMimeType 获取文件的真实 MIME 类型(通过读取文件前几个字节)
func getFileMimeType(file multipart.File) (string, error) {
// 读取文件前 512 字节用于检测 MIME 类型
buffer := make([]byte, 512)
n, err := file.Read(buffer)
if err != nil && err != io.EOF {
return "", err
}
// 重置文件指针到开头
if _, err := file.Seek(0, io.SeekStart); err != nil {
return "", err
}
// 检测 MIME 类型
return http.DetectContentType(buffer[:n]), nil
}