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"` } ) func ConcatVideo(video *youtube.Video, vodFiles []string) error { 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), 0o644, ) if err != nil { return fmt.Errorf("failed to write file list: %v", err) } err = ffmpeg.Input(fileListPath, ffmpeg.KwArgs{ "f": "concat", "safe": "0", }).Output(video.Filename, ffmpeg.KwArgs{ "c": "copy", }).OverWriteOutput().ErrorToStdOut().Run() if err != nil { return fmt.Errorf("ffmpeg error: %v", err) } return nil }