fix(config): add media configuration schema and hardware decoding modes
- commit
- 94c2fc491c372039b648a2b70d4ccf5bc2c9759a
- author
- brice · · 2025-12-18 18:27 UTC
- parent
- 40983c7
- signature
- unsigned
3 files · +47 -0
M internal/infrastructure/config/defaults.go +5 -0
| @@ -186,6 +186,11 @@ func DefaultConfig() *Config { | |||
| 186 | 186 | Omnibox: OmniboxConfig{ | |
| 187 | 187 | InitialBehavior: defaultOmniboxInitialBehavior, | |
| 188 | 188 | }, | |
| 189 | + | Media: MediaConfig{ | |
| 190 | + | HardwareDecodingMode: HardwareDecodingAuto, // THE FIX: auto allows sw fallback | |
| 191 | + | PreferAV1: true, // AV1 is most efficient codec | |
| 192 | + | ShowDiagnosticsOnStartup: true, // Warn users if HW accel unavailable | |
| 193 | + | }, | |
| 189 | 194 | } | |
| 190 | 195 | } | |
| 191 | 196 | ||
| @@ -186,6 +186,11 @@ func DefaultConfig() *Config { | |||||
| 186 | Omnibox: OmniboxConfig{ | 186 | Omnibox: OmniboxConfig{ | ||
| 187 | InitialBehavior: defaultOmniboxInitialBehavior, | 187 | InitialBehavior: defaultOmniboxInitialBehavior, | ||
| 188 | }, | 188 | }, | ||
| 189 | + | Media: MediaConfig{ | |||
| 190 | + | HardwareDecodingMode: HardwareDecodingAuto, // THE FIX: auto allows sw fallback | |||
| 191 | + | PreferAV1: true, // AV1 is most efficient codec | |||
| 192 | + | ShowDiagnosticsOnStartup: true, // Warn users if HW accel unavailable | |||
| 193 | + | }, | |||
| 189 | } | 194 | } | ||
| 190 | } | 195 | } | ||
| 191 | 196 | ||||
M internal/infrastructure/config/loader.go +17 -0
| @@ -146,6 +146,18 @@ func (m *Manager) Load() error { | |||
| 146 | 146 | config.Appearance.ColorScheme = ThemeDefault | |
| 147 | 147 | } | |
| 148 | 148 | ||
| 149 | + | // Validate Media.HardwareDecodingMode using switch statement | |
| 150 | + | switch strings.ToLower(string(config.Media.HardwareDecodingMode)) { | |
| 151 | + | case "", string(HardwareDecodingAuto): | |
| 152 | + | config.Media.HardwareDecodingMode = HardwareDecodingAuto | |
| 153 | + | case string(HardwareDecodingForce): | |
| 154 | + | config.Media.HardwareDecodingMode = HardwareDecodingForce | |
| 155 | + | case string(HardwareDecodingDisable): | |
| 156 | + | config.Media.HardwareDecodingMode = HardwareDecodingDisable | |
| 157 | + | default: | |
| 158 | + | config.Media.HardwareDecodingMode = HardwareDecodingAuto | |
| 159 | + | } | |
| 160 | + | ||
| 149 | 161 | // Validate all config values | |
| 150 | 162 | if err := validateConfig(config); err != nil { | |
| 151 | 163 | return fmt.Errorf("configuration validation failed: %w", err) | |
| @@ -277,6 +289,11 @@ func (m *Manager) setDefaults() { | |||
| 277 | 289 | ||
| 278 | 290 | // Omnibox defaults | |
| 279 | 291 | m.viper.SetDefault("omnibox.initial_behavior", defaults.Omnibox.InitialBehavior) | |
| 292 | + | ||
| 293 | + | // Media defaults | |
| 294 | + | m.viper.SetDefault("media.hardware_decoding", string(defaults.Media.HardwareDecodingMode)) | |
| 295 | + | m.viper.SetDefault("media.prefer_av1", defaults.Media.PreferAV1) | |
| 296 | + | m.viper.SetDefault("media.show_diagnostics", defaults.Media.ShowDiagnosticsOnStartup) | |
| 280 | 297 | } | |
| 281 | 298 | ||
| 282 | 299 | // New returns a new default configuration instance. | |
| @@ -146,6 +146,18 @@ func (m *Manager) Load() error { | |||||
| 146 | config.Appearance.ColorScheme = ThemeDefault | 146 | config.Appearance.ColorScheme = ThemeDefault | ||
| 147 | } | 147 | } | ||
| 148 | 148 | ||||
| 149 | + | // Validate Media.HardwareDecodingMode using switch statement | |||
| 150 | + | switch strings.ToLower(string(config.Media.HardwareDecodingMode)) { | |||
| 151 | + | case "", string(HardwareDecodingAuto): | |||
| 152 | + | config.Media.HardwareDecodingMode = HardwareDecodingAuto | |||
| 153 | + | case string(HardwareDecodingForce): | |||
| 154 | + | config.Media.HardwareDecodingMode = HardwareDecodingForce | |||
| 155 | + | case string(HardwareDecodingDisable): | |||
| 156 | + | config.Media.HardwareDecodingMode = HardwareDecodingDisable | |||
| 157 | + | default: | |||
| 158 | + | config.Media.HardwareDecodingMode = HardwareDecodingAuto | |||
| 159 | + | } | |||
| 160 | + | ||||
| 149 | // Validate all config values | 161 | // Validate all config values | ||
| 150 | if err := validateConfig(config); err != nil { | 162 | if err := validateConfig(config); err != nil { | ||
| 151 | return fmt.Errorf("configuration validation failed: %w", err) | 163 | return fmt.Errorf("configuration validation failed: %w", err) | ||
| @@ -277,6 +289,11 @@ func (m *Manager) setDefaults() { | |||||
| 277 | 289 | ||||
| 278 | // Omnibox defaults | 290 | // Omnibox defaults | ||
| 279 | m.viper.SetDefault("omnibox.initial_behavior", defaults.Omnibox.InitialBehavior) | 291 | m.viper.SetDefault("omnibox.initial_behavior", defaults.Omnibox.InitialBehavior) | ||
| 292 | + | ||||
| 293 | + | // Media defaults | |||
| 294 | + | m.viper.SetDefault("media.hardware_decoding", string(defaults.Media.HardwareDecodingMode)) | |||
| 295 | + | m.viper.SetDefault("media.prefer_av1", defaults.Media.PreferAV1) | |||
| 296 | + | m.viper.SetDefault("media.show_diagnostics", defaults.Media.ShowDiagnosticsOnStartup) | |||
| 280 | } | 297 | } | ||
| 281 | 298 | ||||
| 282 | // New returns a new default configuration instance. | 299 | // New returns a new default configuration instance. | ||
M internal/infrastructure/config/schema.go +25 -0
| @@ -23,6 +23,8 @@ type Config struct { | |||
| 23 | 23 | ContentFiltering ContentFilteringConfig `mapstructure:"content_filtering" yaml:"content_filtering" toml:"content_filtering"` | |
| 24 | 24 | // Omnibox controls the omnibox behavior (initial history display) | |
| 25 | 25 | Omnibox OmniboxConfig `mapstructure:"omnibox" yaml:"omnibox" toml:"omnibox"` | |
| 26 | + | // Media controls video playback and hardware acceleration | |
| 27 | + | Media MediaConfig `mapstructure:"media" yaml:"media" toml:"media"` | |
| 26 | 28 | } | |
| 27 | 29 | ||
| 28 | 30 | // RenderingMode selects GPU vs CPU rendering. | |
| @@ -34,9 +36,32 @@ const ( | |||
| 34 | 36 | RenderingModeCPU RenderingMode = "cpu" | |
| 35 | 37 | ) | |
| 36 | 38 | ||
| 39 | + | // HardwareDecodingMode controls video hardware acceleration. | |
| 40 | + | type HardwareDecodingMode string | |
| 41 | + | ||
| 42 | + | const ( | |
| 43 | + | // HardwareDecodingAuto lets GStreamer choose (hw preferred, sw fallback) | |
| 44 | + | HardwareDecodingAuto HardwareDecodingMode = "auto" | |
| 45 | + | // HardwareDecodingForce requires hardware decoding (fails if unavailable) | |
| 46 | + | HardwareDecodingForce HardwareDecodingMode = "force" | |
| 47 | + | // HardwareDecodingDisable uses software decoding only | |
| 48 | + | HardwareDecodingDisable HardwareDecodingMode = "disable" | |
| 49 | + | ) | |
| 50 | + | ||
| 37 | 51 | // ThemeDefault is the default theme setting (follows system). | |
| 38 | 52 | const ThemeDefault = "default" | |
| 39 | 53 | ||
| 54 | + | // MediaConfig holds video playback and hardware acceleration preferences. | |
| 55 | + | type MediaConfig struct { | |
| 56 | + | // HardwareDecodingMode controls hardware vs software video decoding | |
| 57 | + | // Values: "auto" (default), "force", "disable" | |
| 58 | + | HardwareDecodingMode HardwareDecodingMode `mapstructure:"hardware_decoding" yaml:"hardware_decoding" toml:"hardware_decoding"` | |
| 59 | + | // PreferAV1 prioritizes AV1 codec (most efficient) when available | |
| 60 | + | PreferAV1 bool `mapstructure:"prefer_av1" yaml:"prefer_av1" toml:"prefer_av1"` | |
| 61 | + | // ShowDiagnosticsOnStartup shows media capability warnings at startup | |
| 62 | + | ShowDiagnosticsOnStartup bool `mapstructure:"show_diagnostics" yaml:"show_diagnostics" toml:"show_diagnostics"` | |
| 63 | + | } | |
| 64 | + | ||
| 40 | 65 | // DatabaseConfig holds database-related configuration. | |
| 41 | 66 | type DatabaseConfig struct { | |
| 42 | 67 | Path string `mapstructure:"path" yaml:"path" toml:"path"` | |
| @@ -23,6 +23,8 @@ type Config struct { | |||||
| 23 | ContentFiltering ContentFilteringConfig `mapstructure:"content_filtering" yaml:"content_filtering" toml:"content_filtering"` | 23 | ContentFiltering ContentFilteringConfig `mapstructure:"content_filtering" yaml:"content_filtering" toml:"content_filtering"` | ||
| 24 | // Omnibox controls the omnibox behavior (initial history display) | 24 | // Omnibox controls the omnibox behavior (initial history display) | ||
| 25 | Omnibox OmniboxConfig `mapstructure:"omnibox" yaml:"omnibox" toml:"omnibox"` | 25 | Omnibox OmniboxConfig `mapstructure:"omnibox" yaml:"omnibox" toml:"omnibox"` | ||
| 26 | + | // Media controls video playback and hardware acceleration | |||
| 27 | + | Media MediaConfig `mapstructure:"media" yaml:"media" toml:"media"` | |||
| 26 | } | 28 | } | ||
| 27 | 29 | ||||
| 28 | // RenderingMode selects GPU vs CPU rendering. | 30 | // RenderingMode selects GPU vs CPU rendering. | ||
| @@ -34,9 +36,32 @@ const ( | |||||
| 34 | RenderingModeCPU RenderingMode = "cpu" | 36 | RenderingModeCPU RenderingMode = "cpu" | ||
| 35 | ) | 37 | ) | ||
| 36 | 38 | ||||
| 39 | + | // HardwareDecodingMode controls video hardware acceleration. | |||
| 40 | + | type HardwareDecodingMode string | |||
| 41 | + | ||||
| 42 | + | const ( | |||
| 43 | + | // HardwareDecodingAuto lets GStreamer choose (hw preferred, sw fallback) | |||
| 44 | + | HardwareDecodingAuto HardwareDecodingMode = "auto" | |||
| 45 | + | // HardwareDecodingForce requires hardware decoding (fails if unavailable) | |||
| 46 | + | HardwareDecodingForce HardwareDecodingMode = "force" | |||
| 47 | + | // HardwareDecodingDisable uses software decoding only | |||
| 48 | + | HardwareDecodingDisable HardwareDecodingMode = "disable" | |||
| 49 | + | ) | |||
| 50 | + | ||||
| 37 | // ThemeDefault is the default theme setting (follows system). | 51 | // ThemeDefault is the default theme setting (follows system). | ||
| 38 | const ThemeDefault = "default" | 52 | const ThemeDefault = "default" | ||
| 39 | 53 | ||||
| 54 | + | // MediaConfig holds video playback and hardware acceleration preferences. | |||
| 55 | + | type MediaConfig struct { | |||
| 56 | + | // HardwareDecodingMode controls hardware vs software video decoding | |||
| 57 | + | // Values: "auto" (default), "force", "disable" | |||
| 58 | + | HardwareDecodingMode HardwareDecodingMode `mapstructure:"hardware_decoding" yaml:"hardware_decoding" toml:"hardware_decoding"` | |||
| 59 | + | // PreferAV1 prioritizes AV1 codec (most efficient) when available | |||
| 60 | + | PreferAV1 bool `mapstructure:"prefer_av1" yaml:"prefer_av1" toml:"prefer_av1"` | |||
| 61 | + | // ShowDiagnosticsOnStartup shows media capability warnings at startup | |||
| 62 | + | ShowDiagnosticsOnStartup bool `mapstructure:"show_diagnostics" yaml:"show_diagnostics" toml:"show_diagnostics"` | |||
| 63 | + | } | |||
| 64 | + | ||||
| 40 | // DatabaseConfig holds database-related configuration. | 65 | // DatabaseConfig holds database-related configuration. | ||
| 41 | type DatabaseConfig struct { | 66 | type DatabaseConfig struct { | ||
| 42 | Path string `mapstructure:"path" yaml:"path" toml:"path"` | 67 | Path string `mapstructure:"path" yaml:"path" toml:"path"` | ||