config.go
⎇
Raw
1package config
2
3import (
4 "fmt"
5 "log/slog"
6 "os"
7 "path/filepath"
8 "strconv"
9 "strings"
10)
11
12type Config struct {
13 Port int
14 DataDir string
15 DBPath string
16 LibraryDir string
17 TempDir string
18 YTDLPPath string
19 FFmpegPath string
20 FFprobePath string
21 BaseURL string
22 Workers int
23 SchedulerInterval int
24 LogLevel string
25 LogFormat string
26 Username string
27 PasswordHash string
28}
29
30func New() *Config {
31 dataDir := getEnv("VIDARCHIVE_DATA_DIR", "./data")
32
33 return &Config{
34 Port: getEnvInt("VIDARCHIVE_PORT", 8080, 1),
35 DataDir: dataDir,
36 DBPath: getEnv("VIDARCHIVE_DB_PATH", filepath.Join(dataDir, "vidarchive.db")),
37 LibraryDir: getEnv("VIDARCHIVE_LIBRARY_DIR", filepath.Join(dataDir, "library")),
38 TempDir: getEnv("VIDARCHIVE_TEMP_DIR", filepath.Join(dataDir, "temp")),
39 YTDLPPath: getEnv("VIDARCHIVE_YTDLP_PATH", "yt-dlp"),
40 FFmpegPath: getEnv("VIDARCHIVE_FFMPEG_PATH", "ffmpeg"),
41 FFprobePath: getEnv("VIDARCHIVE_FFPROBE_PATH", "ffprobe"),
42 BaseURL: getEnv("VIDARCHIVE_BASE_URL", ""),
43 Workers: getEnvInt("VIDARCHIVE_WORKERS", 2, 1),
44 SchedulerInterval: getEnvInt("VIDARCHIVE_SCHEDULER_INTERVAL", 60, 1),
45 LogLevel: getEnv("VIDARCHIVE_LOG_LEVEL", "info"),
46 LogFormat: getEnv("VIDARCHIVE_LOG_FORMAT", "text"),
47 Username: os.Getenv("VIDARCHIVE_USERNAME"),
48 PasswordHash: os.Getenv("VIDARCHIVE_PASSWORD_HASH"),
49 }
50}
51
52// SetupLogging installs the process-wide slog handler. slog.SetDefault also
53// redirects the stdlib log package through it, so output from dependencies is
54// formatted and levelled the same way.
55func (c *Config) SetupLogging() {
56 var level slog.Level
57 if err := level.UnmarshalText([]byte(c.LogLevel)); err != nil {
58 fmt.Fprintf(os.Stderr, "invalid VIDARCHIVE_LOG_LEVEL %q: %v, using info\n", c.LogLevel, err)
59 level = slog.LevelInfo
60 }
61
62 opts := &slog.HandlerOptions{Level: level}
63 var h slog.Handler = slog.NewTextHandler(os.Stderr, opts)
64 if strings.EqualFold(c.LogFormat, "json") {
65 h = slog.NewJSONHandler(os.Stderr, opts)
66 }
67 slog.SetDefault(slog.New(h))
68}
69
70func (c *Config) IsHTTPS() bool {
71 return strings.HasPrefix(c.BaseURL, "https://")
72}
73
74func getEnv(key, defaultVal string) string {
75 if v := os.Getenv(key); v != "" {
76 return v
77 }
78 return defaultVal
79}
80
81// getEnvInt reads an int with a lower bound. A value below min is rejected in
82// favour of the default: a zero or negative worker count, tick interval or port
83// would otherwise stall downloads, spin the scheduler or fail to bind.
84func getEnvInt(key string, defaultVal, min int) int {
85 v := os.Getenv(key)
86 if v == "" {
87 return defaultVal
88 }
89 i, err := strconv.Atoi(v)
90 if err != nil {
91 fmt.Fprintf(os.Stderr, "invalid %s: %v, using default %d\n", key, err, defaultVal)
92 return defaultVal
93 }
94 if i < min {
95 fmt.Fprintf(os.Stderr, "invalid %s: %d is below the minimum %d, using default %d\n", key, i, min, defaultVal)
96 return defaultVal
97 }
98 return i
99}
100