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  }