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, verbose bool) (int64, 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 0, 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 0, fmt.Errorf("failed to parse duration of file `%s`: %v", file, err) } totalDuration += duration } err := os.WriteFile( fileListPath, []byte(fileListString), 0644, ) if err != nil { return 0, fmt.Errorf("failed to write file list: %v", err) } stream := ffmpeg.Input(fileListPath, ffmpeg.KwArgs{ "f": "concat", "safe": "0", }).Output(video.Filename, ffmpeg.KwArgs{ "c": "copy", }).OverWriteOutput() if verbose { stream = stream.ErrorToStdOut() } err = stream.Run() if err != nil { return 0, fmt.Errorf("ffmpeg error: %v", err) } fileInfo, err := os.Stat(video.Filename) if err != nil { return 0, fmt.Errorf("failed to read output file: %v", err) } return fileInfo.Size(), nil }