package config import ( "archive/zip" "bytes" "io" "log" "os" "path/filepath" "strings" ) // ExtractBin copies an embedded binary to the bin directory if not already present. func (c *Config) ExtractBin(name string, embedded []byte) string { dest := filepath.Join(c.BinDir(), name) if _, err := os.Stat(dest); err == nil { return dest } log.Printf("[config] extracting %s ...", name) if err := os.WriteFile(dest, embedded, 0755); err != nil { log.Printf("[config] extract %s failed: %v", name, err) return "" } return dest } // ExtractZip extracts an embedded zip file to the bin directory. // Extracts ffmpeg.exe and ffprobe.exe from the zip, skipping if already present. func (c *Config) ExtractZip(embedded []byte) (ffmpegPath, ffprobePath string) { dir := c.BinDir() ffmpegPath = filepath.Join(dir, "ffmpeg.exe") ffprobePath = filepath.Join(dir, "ffprobe.exe") // If both exist, skip extraction if fileExists(ffmpegPath) && fileExists(ffprobePath) { return } reader, err := zip.NewReader(bytes.NewReader(embedded), int64(len(embedded))) if err != nil { log.Printf("[config] zip open failed: %v", err) return } for _, f := range reader.File { name := strings.ToLower(f.Name) name = filepath.Base(name) if name != "ffmpeg.exe" && name != "ffprobe.exe" { continue } dest := filepath.Join(dir, name) if fileExists(dest) { continue } log.Printf("[config] extracting %s (%d bytes)...", name, f.UncompressedSize64) rc, err := f.Open() if err != nil { log.Printf("[config] zip open %s: %v", name, err) continue } out, err := os.Create(dest) if err != nil { rc.Close() continue } _, err = io.Copy(out, rc) rc.Close() out.Close() if err != nil { os.Remove(dest) log.Printf("[config] extract %s failed: %v", name, err) } } return } func fileExists(path string) bool { _, err := os.Stat(path) return err == nil }