vodular/video/video.go

69 lines
1.4 KiB
Go
Raw Normal View History

2026-01-28 10:48:14 +00:00
package video
import (
"encoding/json"
"fmt"
"os"
"path"
"strconv"
"arimelody.space/live-vod-uploader/youtube"
ffmpeg "github.com/u2takey/ffmpeg-go"
)
type (
probeFormat struct {
Duration string `json:"duration"`
}
probeData struct {
Format probeFormat `json:"format"`
}
)
2026-01-28 12:50:11 +00:00
func ConcatVideo(video *youtube.Video, vodFiles []string, verbose bool) error {
2026-01-28 10:48:14 +00:00
fileListPath := path.Join(
path.Dir(video.Filename),
"files.txt",
)
totalDuration := float64(0.0)
fileListString := ""
for _, file := range vodFiles {
fileListString += fmt.Sprintf("file '%s'\n", file)
jsonProbe, err := ffmpeg.Probe(path.Join(path.Dir(video.Filename), file))
if err != nil {
return fmt.Errorf("failed to probe file `%s`: %v", file, err)
}
probe := probeData{}
json.Unmarshal([]byte(jsonProbe), &probe)
duration, err := strconv.ParseFloat(probe.Format.Duration, 64)
if err != nil {
return fmt.Errorf("failed to parse duration of file `%s`: %v", file, err)
}
totalDuration += duration
}
err := os.WriteFile(
fileListPath,
[]byte(fileListString),
2026-01-28 12:50:11 +00:00
0644,
2026-01-28 10:48:14 +00:00
)
if err != nil {
return fmt.Errorf("failed to write file list: %v", err)
}
2026-01-28 12:50:11 +00:00
stream := ffmpeg.Input(fileListPath, ffmpeg.KwArgs{
2026-01-28 10:48:14 +00:00
"f": "concat",
"safe": "0",
}).Output(video.Filename, ffmpeg.KwArgs{
"c": "copy",
2026-01-28 12:50:11 +00:00
}).OverWriteOutput()
if verbose { stream = stream.ErrorToStdOut() }
err = stream.Run()
2026-01-28 10:48:14 +00:00
if err != nil {
return fmt.Errorf("ffmpeg error: %v", err)
}
return nil
}