113 lines
2.6 KiB
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
|
|
}
|