main
Raw Download raw file
  1// Package config defines the configuration for the upvs CLI.
  2package config
  3
  4import (
  5	"errors"
  6	"fmt"
  7	"net/url"
  8	"os"
  9	"strings"
 10	"time"
 11)
 12
 13// Default values for configuration.
 14const (
 15	DefaultWorkers      = 4
 16	DefaultRetries      = 3
 17	DefaultTargetSecs   = 600 // 10 minutes
 18	DefaultFPS          = 30
 19	DefaultCRF          = 23
 20	DefaultPreset       = "medium"
 21	DefaultMinSpeedMult = 1.0
 22	DefaultMaxSpeedMult = 2000.0
 23)
 24
 25// Config holds all configuration for a pipeline run.
 26type Config struct {
 27	// Connection settings
 28	Host        string
 29	Username    string
 30	Password    string
 31	TLSInsecure bool
 32	DirectAPI   bool // Use /api instead of /proxy/protect/api
 33
 34	// Target selection
 35	Camera string
 36	Date   time.Time
 37
 38	// Output settings
 39	OutDir  string
 40	Verbose bool
 41
 42	// Fetch settings
 43	Workers int
 44	Retries int
 45
 46	// Render settings
 47	TargetSecs   int
 48	FPS          int
 49	CRF          int
 50	Preset       string
 51	MinSpeedMult float64
 52	MaxSpeedMult float64
 53}
 54
 55// New creates a Config with default values.
 56func New() *Config {
 57	return &Config{
 58		Workers:      DefaultWorkers,
 59		Retries:      DefaultRetries,
 60		TargetSecs:   DefaultTargetSecs,
 61		FPS:          DefaultFPS,
 62		CRF:          DefaultCRF,
 63		Preset:       DefaultPreset,
 64		MinSpeedMult: DefaultMinSpeedMult,
 65		MaxSpeedMult: DefaultMaxSpeedMult,
 66	}
 67}
 68
 69// Sentinel errors for configuration validation.
 70var (
 71	ErrMissingHost        = errors.New("host is required")
 72	ErrMissingCredentials = errors.New("username and password are required")
 73	ErrMissingCamera      = errors.New("camera is required")
 74	ErrMissingDate        = errors.New("date is required")
 75	ErrMissingOutDir      = errors.New("out directory is required")
 76	ErrInvalidHost        = errors.New("invalid host URL")
 77	ErrInvalidDate        = errors.New("invalid date format (expected YYYY-MM-DD)")
 78)
 79
 80// Validate checks that all required fields are set and valid.
 81func (c *Config) Validate() error {
 82	if c.Host == "" {
 83		return ErrMissingHost
 84	}
 85	_, err := url.Parse(c.Host)
 86	if err != nil {
 87		return fmt.Errorf("%w: %v", ErrInvalidHost, err)
 88	}
 89	if c.Username == "" || c.Password == "" {
 90		return ErrMissingCredentials
 91	}
 92	if c.Camera == "" {
 93		return ErrMissingCamera
 94	}
 95	if c.Date.IsZero() {
 96		return ErrMissingDate
 97	}
 98	if c.OutDir == "" {
 99		return ErrMissingOutDir
100	}
101	return nil
102}
103
104// LoadPasswordFromFile reads the password from a file if Password is empty.
105func (c *Config) LoadPasswordFromFile(path string) error {
106	if path == "" {
107		return nil
108	}
109	data, err := os.ReadFile(path)
110	if err != nil {
111		return fmt.Errorf("reading password-file: %w", err)
112	}
113	c.Password = strings.TrimSpace(string(data))
114	return nil
115}
116
117// ParseDate parses a date string in YYYY-MM-DD format.
118func ParseDate(s string) (time.Time, error) {
119	t, err := time.Parse("2006-01-02", s)
120	if err != nil {
121		return time.Time{}, ErrInvalidDate
122	}
123	return t, nil
124}
125
126// DateString returns the date formatted as YYYY-MM-DD.
127func (c *Config) DateString() string {
128	return c.Date.Format("2006-01-02")
129}