Files
NaviMigrate/internal/recovery/qobuzdl.go

113 lines
2.6 KiB
Go

package recovery
import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"sync"
)
type QobuzDL struct {
Path string
OutputDir string
Username string
Password string
Quality int
}
var cachedBinaries sync.Map
func (d QobuzDL) DownloadAlbum(ctx context.Context, albumID string) error {
albumID = strings.TrimSpace(albumID)
if albumID == "" {
return fmt.Errorf("album id must not be empty")
}
url := fmt.Sprintf("https://play.qobuz.com/album/%s", albumID)
args := []string{}
if strings.TrimSpace(d.OutputDir) != "" {
args = append(args, "--output", d.OutputDir)
}
if d.Quality > 0 {
args = append(args, "--quality", strconv.Itoa(d.Quality))
}
if strings.TrimSpace(d.Username) != "" {
args = append(args, "--user", strings.TrimSpace(d.Username))
}
if strings.TrimSpace(d.Password) != "" {
args = append(args, "--pass", d.Password)
}
args = append(args, "url", url)
name, cmdArgs, workdir, err := resolveCommand(ctx, strings.TrimSpace(d.Path), args)
if err != nil {
return err
}
cmd := exec.CommandContext(ctx, name, cmdArgs...)
if workdir != "" {
cmd.Dir = workdir
}
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("qobuz-dl failed: %w: %s", err, strings.TrimSpace(string(out)))
}
return nil
}
func resolveCommand(ctx context.Context, path string, args []string) (name string, cmdArgs []string, workdir string, err error) {
if path == "" {
return "qobuz-dl", args, "", nil
}
info, err := os.Stat(path)
if err == nil && info.IsDir() {
bin, err := ensureBuiltBinary(ctx, path)
if err != nil {
return "", nil, "", err
}
return bin, args, "", nil
}
if filepath.Base(path) == "." {
dir := filepath.Dir(path)
bin, err := ensureBuiltBinary(ctx, dir)
if err != nil {
return "", nil, "", err
}
return bin, args, "", nil
}
return path, args, "", nil
}
func ensureBuiltBinary(ctx context.Context, dir string) (string, error) {
dir = filepath.Clean(dir)
if v, ok := cachedBinaries.Load(dir); ok {
if bin, ok := v.(string); ok && strings.TrimSpace(bin) != "" {
if _, err := os.Stat(bin); err == nil {
return bin, nil
}
}
}
tmpDir := filepath.Join(os.TempDir(), "navimigrate-qobuzdl")
if err := os.MkdirAll(tmpDir, 0o755); err != nil {
return "", fmt.Errorf("create temp build directory: %w", err)
}
out := filepath.Join(tmpDir, "qobuz-dl")
build := exec.CommandContext(ctx, "go", "build", "-o", out, ".")
build.Dir = dir
b, err := build.CombinedOutput()
if err != nil {
return "", fmt.Errorf("build qobuz-dl in %s: %w: %s", dir, err, strings.TrimSpace(string(b)))
}
cachedBinaries.Store(dir, out)
return out, nil
}