// Package config resolves where godeez reads its session from and writes its // downloads to. There is no config file: the output directory defaults to // ~/Music/GoDeez but can be overridden with GODEEZ_OUTPUT_DIR, and the only // other setting is the DEEZER_ARL environment variable, which exists as an // escape hatch for users who would rather not store credentials in the system // keyring. package config import ( "fmt" "os" "path/filepath" "strings" "github.com/mathismqn/godeez/internal/fsutil" ) type Config struct { ARLCookie string OutputDir string } // Load resolves the configuration and creates the output directory. // // An empty ARLCookie is normal and not an error: it means fall back to the // stored credentials, which is the usual path. Creating the directory here // rather than at first write means a bad path fails immediately instead of // after the first track has been fetched. func Load() (*Config, error) { arl := os.Getenv("DEEZER_ARL") outputDir, err := resolveOutputDir() if err != nil { return nil, err } if err := fsutil.EnsureDir(outputDir); err != nil { return nil, fmt.Errorf("failed to create output directory: %w", err) } return &Config{ ARLCookie: arl, OutputDir: outputDir, }, nil } // resolveOutputDir honours GODEEZ_OUTPUT_DIR when set, falling back to // ~/Music/GoDeez otherwise. // // A leading "~" is expanded by hand because the shell only does that for // unquoted arguments, not for values read out of the environment, so users // setting this in a profile file would otherwise end up with a literal "~" // directory. func resolveOutputDir() (string, error) { homeDir, err := os.UserHomeDir() if err != nil { return "", fmt.Errorf("failed to get home directory: %w", err) } if dir := strings.TrimSpace(os.Getenv("GODEEZ_OUTPUT_DIR")); dir != "" { if dir == "~" { return homeDir, nil } if rest, ok := strings.CutPrefix(dir, "~/"); ok { return filepath.Join(homeDir, rest), nil } return dir, nil } return filepath.Join(homeDir, "Music", "GoDeez"), nil }