feat: auto-install ffmpeg and yt-dlp during GUI installation
Add "Installing media tools" step to the installer that automatically installs ffmpeg and yt-dlp if not already present on the system. Uses winget (Windows), Homebrew (macOS), or apt-get (Linux). Non-critical step — installation continues even if this fails. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b07e47c517
commit
4ad39d2f17
@ -231,7 +231,8 @@ func (inst *Installer) runInstall(config InstallConfig) {
|
||||
{"Extracting scripts", 48, true, inst.stepExtractScripts},
|
||||
{"Configuring system", 55, false, inst.stepConfigureSystem},
|
||||
{"Setting up USB driver", 62, false, inst.stepSetupLibusb},
|
||||
{"Setting up Python environment", 72, false, inst.stepSetupPython},
|
||||
{"Setting up Python environment", 70, false, inst.stepSetupPython},
|
||||
{"Installing media tools", 78, false, inst.stepInstallFfmpeg},
|
||||
{"Writing configuration", 85, true, inst.stepWriteConfig},
|
||||
{"Verifying installation", 90, false, inst.stepVerify},
|
||||
{"Setting up auto-start launcher", 95, false, inst.stepAutoRestart},
|
||||
@ -519,6 +520,24 @@ func (inst *Installer) setupPythonVenv(installDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (inst *Installer) stepInstallFfmpeg(config InstallConfig) error {
|
||||
needFfmpeg := true
|
||||
if _, err := exec.LookPath("ffmpeg"); err == nil {
|
||||
needFfmpeg = false
|
||||
}
|
||||
|
||||
needYtdlp := true
|
||||
if _, err := exec.LookPath("yt-dlp"); err == nil {
|
||||
needYtdlp = false
|
||||
}
|
||||
|
||||
if !needFfmpeg && !needYtdlp {
|
||||
return nil // both already installed
|
||||
}
|
||||
|
||||
return installFfmpeg(inst, needFfmpeg, needYtdlp)
|
||||
}
|
||||
|
||||
func (inst *Installer) stepWriteConfig(config InstallConfig) error {
|
||||
cfgDir := platformConfigDir()
|
||||
if err := os.MkdirAll(cfgDir, 0755); err != nil {
|
||||
|
||||
@ -138,6 +138,39 @@ func installAutoRestart(installDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func installFfmpeg(inst *Installer, needFfmpeg, needYtdlp bool) error {
|
||||
if _, err := exec.LookPath("brew"); err != nil {
|
||||
return fmt.Errorf("Homebrew not found — install from https://brew.sh then run: brew install ffmpeg")
|
||||
}
|
||||
|
||||
if needFfmpeg {
|
||||
inst.emitProgress(ProgressEvent{
|
||||
Step: "ffmpeg",
|
||||
Message: "Installing ffmpeg via Homebrew (this may take a few minutes)...",
|
||||
Percent: 79,
|
||||
})
|
||||
cmd := exec.Command("brew", "install", "ffmpeg")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("brew install ffmpeg failed: %s — %w", string(out), err)
|
||||
}
|
||||
}
|
||||
|
||||
if needYtdlp {
|
||||
inst.emitProgress(ProgressEvent{
|
||||
Step: "ffmpeg",
|
||||
Message: "Installing yt-dlp via Homebrew...",
|
||||
Percent: 80,
|
||||
})
|
||||
cmd := exec.Command("brew", "install", "yt-dlp")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
// Non-fatal: yt-dlp is optional
|
||||
_ = out
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeAutoRestart() {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
|
||||
@ -109,6 +109,38 @@ func installAutoRestart(installDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func installFfmpeg(inst *Installer, needFfmpeg, needYtdlp bool) error {
|
||||
if _, err := exec.LookPath("apt-get"); err != nil {
|
||||
return fmt.Errorf("package manager not found — please install ffmpeg manually")
|
||||
}
|
||||
|
||||
if needFfmpeg {
|
||||
inst.emitProgress(ProgressEvent{
|
||||
Step: "ffmpeg",
|
||||
Message: "Installing ffmpeg via apt-get...",
|
||||
Percent: 79,
|
||||
})
|
||||
cmd := exec.Command("pkexec", "apt-get", "install", "-y", "ffmpeg")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("apt install ffmpeg failed: %s — %w", string(out), err)
|
||||
}
|
||||
}
|
||||
|
||||
if needYtdlp {
|
||||
inst.emitProgress(ProgressEvent{
|
||||
Step: "ffmpeg",
|
||||
Message: "Installing yt-dlp via pip...",
|
||||
Percent: 80,
|
||||
})
|
||||
cmd := exec.Command("pip3", "install", "yt-dlp")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
_ = out // Non-fatal
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeAutoRestart() {
|
||||
exec.Command("systemctl", "--user", "disable", "--now", systemdServiceName+".service").Run()
|
||||
|
||||
|
||||
@ -155,6 +155,53 @@ func installAutoRestart(installDir string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func installFfmpeg(inst *Installer, needFfmpeg, needYtdlp bool) error {
|
||||
if _, err := exec.LookPath("winget"); err != nil {
|
||||
return fmt.Errorf("winget not found — please install ffmpeg manually from https://ffmpeg.org")
|
||||
}
|
||||
|
||||
if needFfmpeg {
|
||||
inst.emitProgress(ProgressEvent{
|
||||
Step: "ffmpeg",
|
||||
Message: "Installing ffmpeg via winget...",
|
||||
Percent: 79,
|
||||
})
|
||||
cmd := exec.Command("winget", "install", "Gyan.FFmpeg",
|
||||
"--accept-source-agreements", "--accept-package-agreements", "--silent")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("winget install ffmpeg failed: %s — %w", string(out), err)
|
||||
}
|
||||
|
||||
// winget installs ffmpeg to a PATH that requires shell restart.
|
||||
// Add common install location to current process PATH so subsequent checks work.
|
||||
for _, dir := range []string{
|
||||
filepath.Join(os.Getenv("LOCALAPPDATA"), "Microsoft", "WinGet", "Links"),
|
||||
`C:\ffmpeg\bin`,
|
||||
filepath.Join(os.Getenv("ProgramFiles"), "FFmpeg", "bin"),
|
||||
} {
|
||||
if _, err := os.Stat(dir); err == nil {
|
||||
os.Setenv("PATH", dir+";"+os.Getenv("PATH"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if needYtdlp {
|
||||
inst.emitProgress(ProgressEvent{
|
||||
Step: "ffmpeg",
|
||||
Message: "Installing yt-dlp via winget...",
|
||||
Percent: 80,
|
||||
})
|
||||
cmd := exec.Command("winget", "install", "yt-dlp.yt-dlp",
|
||||
"--accept-source-agreements", "--accept-package-agreements", "--silent")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
// Non-fatal: yt-dlp is optional
|
||||
_ = out
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeAutoRestart() {
|
||||
// Remove Registry Run key
|
||||
exec.Command("reg", "delete",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user