github.com/derat/nup@v0.0.0-20230418113745-15592ba7c620/cmd/nup/client/config.go (about) 1 // Copyright 2021 Daniel Erat. 2 // All rights reserved. 3 4 // Package client continues functionality shared across client binaries. 5 package client 6 7 import ( 8 "encoding/json" 9 "errors" 10 "fmt" 11 "net/url" 12 "os" 13 "path/filepath" 14 "strings" 15 ) 16 17 // Config holds configuration details for the nup client executable. 18 type Config struct { 19 // ServerURL contains the App Engine server URL. 20 ServerURL string `json:"serverUrl"` 21 // Username contains an HTTP basic auth username. 22 Username string `json:"username"` 23 // Password contains an HTTP basic auth password. 24 Password string `json:"password"` 25 26 // CoverDir is the base directory containing cover art. 27 CoverDir string `json:"coverDir"` 28 // MusicDir is the base directory containing song files. 29 MusicDir string `json:"musicDir"` 30 // MetadataDir is the base directory containing JSON files that override song metadata. 31 // $HOME/.nup/metadata will be used by default. 32 MetadataDir string `json:"metadataDir"` 33 // LastUpdateInfoFile is the path to a JSON file storing info about the last update. 34 // The file will be created if it does not already exist. 35 // $HOME/.nup/last_update_info.json will be used by default. 36 LastUpdateInfoFile string `json:"lastUpdateInfoFile"` 37 // ComputeGain indicates whether the mp3gain program should be used to compute per-song 38 // and per-album gain information so that volume can be normalized during playback. 39 ComputeGain bool `json:"computeGain"` 40 // ArtistRewrites maps from original ID3 tag artist names to replacement names that should 41 // be used for updates. This can be used to fix incorrectly-tagged files without needing to 42 // reupload them. 43 ArtistRewrites map[string]string `json:"artistRewrites"` 44 // AlbumIDRewrites maps from original ID3 tag album IDs (i.e. MusicBrainz UUIDs) to 45 // replacement IDs that should be used for updates. If the album name ends with the suffix 46 // " (disc [number])", the suffix will be removed and the song's disc number will be set 47 // accordingly. This can be used to fix split releases without needing to retag and reupload 48 // them. 49 AlbumIDRewrites map[string]string `json:"albumIdRewrites"` 50 } 51 52 // LoadConfig loads a JSON-marshaled Config from the file at p and updates dst. 53 func LoadConfig(p string, dst *Config) error { 54 f, err := os.Open(p) 55 if err != nil { 56 return err 57 } 58 defer f.Close() 59 60 d := json.NewDecoder(f) 61 if err = d.Decode(dst); err != nil { 62 return err 63 } 64 if err := dst.checkServerURL(); err != nil { 65 return err 66 } 67 dotDir := filepath.Join(os.Getenv("HOME"), ".nup") 68 if dst.MetadataDir == "" { 69 dst.MetadataDir = filepath.Join(dotDir, "metadata") 70 } 71 if dst.LastUpdateInfoFile == "" { 72 dst.LastUpdateInfoFile = filepath.Join(dotDir, "last_update_info.json") 73 } 74 return nil 75 } 76 77 // GetURL appends path to ServerURL. Query params should not be included. 78 func (cfg *Config) GetURL(path string) *url.URL { 79 u, _ := url.Parse(cfg.ServerURL) // checked in LoadConfig() 80 if u.Path == "" { 81 u.Path = "/" 82 } 83 u.Path = filepath.Join(u.Path, path) 84 return u 85 } 86 87 // checkServerURL returns an error if cfg.ServerURL is unset or malformed. 88 func (cfg *Config) checkServerURL() error { 89 if cfg.ServerURL == "" { 90 return errors.New("serverUrl not set") 91 } 92 if _, err := url.Parse(cfg.ServerURL); err != nil { 93 return fmt.Errorf("bad serverUrl %q: %v", cfg.ServerURL, err) 94 } 95 return nil 96 } 97 98 // ProjectID returns the GCP project ID as derived from cfg.ServerURL. 99 func (cfg *Config) ProjectID() (string, error) { 100 if su, err := url.Parse(cfg.ServerURL); err != nil { 101 return "", err 102 } else if !strings.HasSuffix(su.Host, ".appspot.com") { 103 return "", errors.New("server hostname doesn't end in appspot.com") 104 } else { 105 return strings.TrimSuffix(su.Host, ".appspot.com"), nil 106 } 107 }