feat: support S3 media processing pipeline
This commit is contained in:
@@ -114,7 +114,49 @@ func (j *MediaProcessWorker) Work(ctx context.Context, job *river.Job[args.Media
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Warn("non-local provider, skipping ffmpeg processing")
|
||||
tempDir, err := os.MkdirTemp("", "media-process-")
|
||||
if err != nil {
|
||||
log.Errorf("create temp dir failed: %v", err)
|
||||
finalStatus = consts.MediaAssetStatusFailed
|
||||
} else {
|
||||
defer os.RemoveAll(tempDir)
|
||||
ext := path.Ext(asset.ObjectKey)
|
||||
inputFile := filepath.Join(tempDir, "source"+ext)
|
||||
if err := j.storage.Download(ctx, asset.ObjectKey, inputFile); err != nil {
|
||||
log.Errorf("download media file failed: %s, err=%v", asset.ObjectKey, err)
|
||||
finalStatus = consts.MediaAssetStatusFailed
|
||||
} else if _, err := exec.LookPath("ffmpeg"); err != nil {
|
||||
log.Warn("ffmpeg not found, skipping real transcoding")
|
||||
} else {
|
||||
coverFile := filepath.Join(tempDir, "cover.jpg")
|
||||
cmd := exec.CommandContext(
|
||||
ctx,
|
||||
"ffmpeg",
|
||||
"-y",
|
||||
"-i",
|
||||
inputFile,
|
||||
"-ss",
|
||||
"00:00:00.000",
|
||||
"-vframes",
|
||||
"1",
|
||||
"-vf",
|
||||
"format=yuv420p",
|
||||
"-update",
|
||||
"1",
|
||||
coverFile,
|
||||
)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
log.Errorf("ffmpeg failed: %s, output: %s", err, string(out))
|
||||
finalStatus = consts.MediaAssetStatusFailed
|
||||
} else {
|
||||
log.Infof("Generated cover: %s", coverFile)
|
||||
if err := j.registerCoverAsset(ctx, asset, coverFile); err != nil {
|
||||
log.Errorf("register cover failed: %s", err)
|
||||
finalStatus = consts.MediaAssetStatusFailed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,21 +217,27 @@ func (j *MediaProcessWorker) registerCoverAsset(ctx context.Context, asset *mode
|
||||
coverName := coverFilename(filename)
|
||||
objectKey := buildObjectKey(tenant, hash, coverName)
|
||||
|
||||
// 本地存储将文件移动到目标 objectKey 位置,保持路径规范。
|
||||
localPath := j.storage.Config.LocalPath
|
||||
if localPath == "" {
|
||||
localPath = "./storage"
|
||||
}
|
||||
dstPath := filepath.Join(localPath, filepath.FromSlash(objectKey))
|
||||
if coverFile != dstPath {
|
||||
if err := os.MkdirAll(filepath.Dir(dstPath), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := os.Stat(dstPath); err == nil {
|
||||
_ = os.Remove(coverFile)
|
||||
} else if err := os.Rename(coverFile, dstPath); err != nil {
|
||||
if strings.ToLower(asset.Provider) == "local" {
|
||||
localPath := j.storage.Config.LocalPath
|
||||
if localPath == "" {
|
||||
localPath = "./storage"
|
||||
}
|
||||
dstPath := filepath.Join(localPath, filepath.FromSlash(objectKey))
|
||||
if coverFile != dstPath {
|
||||
if err := os.MkdirAll(filepath.Dir(dstPath), 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := os.Stat(dstPath); err == nil {
|
||||
_ = os.Remove(coverFile)
|
||||
} else if err := os.Rename(coverFile, dstPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := j.storage.PutObject(ctx, objectKey, coverFile, "image/jpeg"); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = os.Remove(coverFile)
|
||||
}
|
||||
|
||||
coverAsset := &models.MediaAsset{
|
||||
|
||||
Reference in New Issue
Block a user