package media import ( "os" "os/exec" "path/filepath" "runtime" ) type Binaries struct { FFmpeg string `json:"ffmpeg"` FFprobe string `json:"ffprobe"` Source string `json:"source"` // "custom", "bundled", "path", "winget", "missing" } func FindBinaries(customFFmpeg, customFFprobe string) Binaries { exeName := func(base string) string { if runtime.GOOS == "windows" { return base + ".exe" } return base } ff := findSingle(exeName("ffmpeg"), customFFmpeg) fp := findSingle(exeName("ffprobe"), customFFprobe) source := "missing" if ff.path != "" && fp.path != "" { source = ff.source } else if ff.path != "" || fp.path != "" { if ff.path != "" { source = ff.source } else { source = fp.source } } return Binaries{ FFmpeg: ff.path, FFprobe: fp.path, Source: source, } } type foundBin struct { path string source string } func findSingle(exeName, custom string) foundBin { if custom != "" { if st, err := os.Stat(custom); err == nil && !st.IsDir() { return foundBin{path: custom, source: "custom"} } } if exePath, err := os.Executable(); err == nil { dir := filepath.Dir(exePath) candidates := []string{ filepath.Join(dir, "bin", exeName), filepath.Join(dir, exeName), } for _, c := range candidates { if st, err := os.Stat(c); err == nil && !st.IsDir() { return foundBin{path: c, source: "bundled"} } } } if p, err := exec.LookPath(exeName); err == nil { return foundBin{path: p, source: "path"} } if runtime.GOOS == "windows" { if localAppData := os.Getenv("LOCALAPPDATA"); localAppData != "" { wg := filepath.Join(localAppData, "Microsoft", "WinGet", "Links", exeName) if st, err := os.Stat(wg); err == nil && !st.IsDir() { return foundBin{path: wg, source: "winget"} } } } return foundBin{} }