package config import ( "errors" "os" "time" "gopkg.in/yaml.v3" ) // Config holds the application configuration type Config struct { Yandex YandexConfig `yaml:"yandex"` Artists []Artist `yaml:"artists"` Storage StorageConfig `yaml:"storage"` Monitor MonitorConfig `yaml:"monitor"` Debug bool `yaml:"debug"` } // YandexConfig holds Yandex Music API credentials type YandexConfig struct { Token string `yaml:"token"` Username string `yaml:"username"` Password string `yaml:"password"` } // Artist represents an artist to monitor type Artist struct { ID int `yaml:"id"` } // StorageConfig holds storage settings type StorageConfig struct { Path string `yaml:"path"` Organize bool `yaml:"organize"` } // MonitorConfig holds monitor settings type MonitorConfig struct { Interval string `yaml:"interval"` } // Load loads configuration from a YAML file func Load(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, err } var cfg Config if err := yaml.Unmarshal(data, &cfg); err != nil { return nil, err } if err := cfg.Validate(); err != nil { return nil, err } return &cfg, nil } // Validate validates the configuration func (c *Config) Validate() error { if len(c.Artists) == 0 { return errors.New("at least one artist must be configured") } for _, a := range c.Artists { if a.ID <= 0 { return errors.New("artist ID must be positive") } } if c.Storage.Path == "" { return errors.New("storage path is required") } if c.Yandex.Token == "" && (c.Yandex.Username == "" || c.Yandex.Password == "") { return errors.New("either yandex.token or yandex.username/password must be provided") } if _, err := time.ParseDuration(c.Monitor.Interval); err != nil { return errors.New("monitor.interval must be a valid duration (e.g., 24h, 1h, 7d)") } return nil } // GetMonitorInterval returns the parsed monitor interval func (c *Config) GetMonitorInterval() (time.Duration, error) { return time.ParseDuration(c.Monitor.Interval) }