package config import ( "os" "strconv" "strings" "time" ) type Config struct { // Matrix MatrixHomeserver string MatrixUserID string MatrixAccessToken string MatrixDeviceID string MatrixEncryption bool // Search & Download SearchLimit int SearchTimeout time.Duration DownloadTimeout time.Duration AudioFormat string AudioQualityPreview int AudioQualityFinal int PreviewTTL time.Duration AllowedUsers []string // Proxy ProxyEnabled bool ProxyURL string // Paths MusicDir string MusicSubdir string TmpDir string YtdlpPath string // Logging LogLevel string // HTTP ListenAddr string } func Load() *Config { return &Config{ MatrixHomeserver: getEnv("MATRIX_HOMESERVER", ""), MatrixUserID: getEnv("MATRIX_USER_ID", ""), MatrixAccessToken: getEnv("MATRIX_ACCESS_TOKEN", ""), MatrixDeviceID: getEnv("MATRIX_DEVICE_ID", "YTDLBOT"), MatrixEncryption: getEnvBool("MATRIX_ENCRYPTION", false), SearchLimit: getEnvInt("SEARCH_LIMIT", 10), SearchTimeout: getEnvDuration("SEARCH_TIMEOUT", 10*time.Second), DownloadTimeout: getEnvDuration("DOWNLOAD_TIMEOUT", 120*time.Second), AudioFormat: getEnv("AUDIO_FORMAT", "opus"), AudioQualityPreview: getEnvInt("AUDIO_QUALITY_PREVIEW", 5), AudioQualityFinal: getEnvInt("AUDIO_QUALITY_FINAL", 0), PreviewTTL: getEnvDuration("PREVIEW_TTL", 10*time.Minute), AllowedUsers: getEnvSlice("ALLOWED_USERS", nil), ProxyEnabled: getEnvBool("PROXY_ENABLED", true), ProxyURL: getEnv("PROXY_URL", "socks5://localhost:1080"), MusicDir: getEnv("MUSIC_DIR", "/music"), MusicSubdir: getEnv("MUSIC_SUBDIR", "ytdlp"), TmpDir: getEnv("TMP_DIR", "/tmp/ytdlp-previews"), YtdlpPath: getEnv("YTDLP_PATH", "yt-dlp"), LogLevel: getEnv("LOG_LEVEL", "INFO"), ListenAddr: getEnv("LISTEN_ADDR", ":8080"), } } func (c *Config) MusicCollectionDir() string { return strings.TrimRight(c.MusicDir, "/") + "/" + c.MusicSubdir } func getEnv(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback } func getEnvInt(key string, fallback int) int { v := os.Getenv(key) if v == "" { return fallback } n, err := strconv.Atoi(v) if err != nil { return fallback } return n } func getEnvBool(key string, fallback bool) bool { v := os.Getenv(key) if v == "" { return fallback } switch strings.ToLower(v) { case "true", "1", "yes": return true default: return false } } func getEnvDuration(key string, fallback time.Duration) time.Duration { v := os.Getenv(key) if v == "" { return fallback } d, err := time.ParseDuration(v) if err != nil { return fallback } return d } func getEnvSlice(key string, fallback []string) []string { v := os.Getenv(key) if v == "" { return fallback } parts := strings.Split(v, ",") for i := range parts { parts[i] = strings.TrimSpace(parts[i]) } return parts }