feat(config): add color palettes and update default search shortcuts
- Add ColorPalette struct with semantic color tokens (background, surface, text, muted, accent, border) - Add light and dark palette configurations to AppearanceConfig - Refactor search shortcuts to use GetDefaultSearchShortcuts() function - Update default shortcuts: add ddg, go, mdn, npm, remove/reorder others - Update Chrome user agent to version 141.0.0.0 - Set viper defaults for new palette configurations
- commit
- 135779d50057193fc4b08aab140790b8b209d2ed
- author
- bamen · · 2025-10-06 17:02 UTC
- committer
- bamen · · 2025-10-06 16:13 UTC
- parent
- a36e3e7
- signature
- unsigned
2 files · +59 -42
M internal/config/config.go +17 -1
| @@ -118,7 +118,20 @@ type AppearanceConfig struct { | |||
| 118 | 118 | SerifFont string `mapstructure:"serif_font" yaml:"serif_font"` | |
| 119 | 119 | MonospaceFont string `mapstructure:"monospace_font" yaml:"monospace_font"` | |
| 120 | 120 | // Default font size in CSS pixels (approx). | |
| 121 | - | DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"` | |
| 121 | + | DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"` | |
| 122 | + | LightPalette ColorPalette `mapstructure:"light_palette" yaml:"light_palette"` | |
| 123 | + | DarkPalette ColorPalette `mapstructure:"dark_palette" yaml:"dark_palette"` | |
| 124 | + | } | |
| 125 | + | ||
| 126 | + | // ColorPalette contains semantic color tokens for light/dark themes. | |
| 127 | + | type ColorPalette struct { | |
| 128 | + | Background string `mapstructure:"background" yaml:"background" json:"background"` | |
| 129 | + | Surface string `mapstructure:"surface" yaml:"surface" json:"surface"` | |
| 130 | + | SurfaceVariant string `mapstructure:"surface_variant" yaml:"surface_variant" json:"surface_variant"` | |
| 131 | + | Text string `mapstructure:"text" yaml:"text" json:"text"` | |
| 132 | + | Muted string `mapstructure:"muted" yaml:"muted" json:"muted"` | |
| 133 | + | Accent string `mapstructure:"accent" yaml:"accent" json:"accent"` | |
| 134 | + | Border string `mapstructure:"border" yaml:"border" json:"border"` | |
| 122 | 135 | } | |
| 123 | 136 | ||
| 124 | 137 | // VideoAccelerationConfig holds video hardware acceleration preferences. | |
| @@ -665,6 +678,8 @@ func (m *Manager) setDefaults() { | |||
| 665 | 678 | m.viper.SetDefault("appearance.serif_font", defaults.Appearance.SerifFont) | |
| 666 | 679 | m.viper.SetDefault("appearance.monospace_font", defaults.Appearance.MonospaceFont) | |
| 667 | 680 | m.viper.SetDefault("appearance.default_font_size", defaults.Appearance.DefaultFontSize) | |
| 681 | + | m.viper.SetDefault("appearance.light_palette", defaults.Appearance.LightPalette) | |
| 682 | + | m.viper.SetDefault("appearance.dark_palette", defaults.Appearance.DarkPalette) | |
| 668 | 683 | ||
| 669 | 684 | // Video acceleration defaults | |
| 670 | 685 | m.viper.SetDefault("video_acceleration.enable_vaapi", defaults.VideoAcceleration.EnableVAAPI) | |
| @@ -768,6 +783,7 @@ func (m *Manager) createDefaultConfig() error { | |||
| 768 | 783 | defaultConfig := DefaultConfig() | |
| 769 | 784 | ||
| 770 | 785 | // Marshal to JSON with proper indentation | |
| 786 | + | // Note: Go 1.20+ automatically sorts map keys in JSON output | |
| 771 | 787 | configData, err := json.MarshalIndent(defaultConfig, "", " ") | |
| 772 | 788 | if err != nil { | |
| 773 | 789 | return fmt.Errorf("failed to marshal default config: %w", err) | |
| @@ -118,7 +118,20 @@ type AppearanceConfig struct { | |||||
| 118 | SerifFont string `mapstructure:"serif_font" yaml:"serif_font"` | 118 | SerifFont string `mapstructure:"serif_font" yaml:"serif_font"` | ||
| 119 | MonospaceFont string `mapstructure:"monospace_font" yaml:"monospace_font"` | 119 | MonospaceFont string `mapstructure:"monospace_font" yaml:"monospace_font"` | ||
| 120 | // Default font size in CSS pixels (approx). | 120 | // Default font size in CSS pixels (approx). | ||
| 121 | - | DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"` | 121 | + | DefaultFontSize int `mapstructure:"default_font_size" yaml:"default_font_size"` |
| 122 | + | LightPalette ColorPalette `mapstructure:"light_palette" yaml:"light_palette"` | |||
| 123 | + | DarkPalette ColorPalette `mapstructure:"dark_palette" yaml:"dark_palette"` | |||
| 124 | + | } | |||
| 125 | + | ||||
| 126 | + | // ColorPalette contains semantic color tokens for light/dark themes. | |||
| 127 | + | type ColorPalette struct { | |||
| 128 | + | Background string `mapstructure:"background" yaml:"background" json:"background"` | |||
| 129 | + | Surface string `mapstructure:"surface" yaml:"surface" json:"surface"` | |||
| 130 | + | SurfaceVariant string `mapstructure:"surface_variant" yaml:"surface_variant" json:"surface_variant"` | |||
| 131 | + | Text string `mapstructure:"text" yaml:"text" json:"text"` | |||
| 132 | + | Muted string `mapstructure:"muted" yaml:"muted" json:"muted"` | |||
| 133 | + | Accent string `mapstructure:"accent" yaml:"accent" json:"accent"` | |||
| 134 | + | Border string `mapstructure:"border" yaml:"border" json:"border"` | |||
| 122 | } | 135 | } | ||
| 123 | 136 | ||||
| 124 | // VideoAccelerationConfig holds video hardware acceleration preferences. | 137 | // VideoAccelerationConfig holds video hardware acceleration preferences. | ||
| @@ -665,6 +678,8 @@ func (m *Manager) setDefaults() { | |||||
| 665 | m.viper.SetDefault("appearance.serif_font", defaults.Appearance.SerifFont) | 678 | m.viper.SetDefault("appearance.serif_font", defaults.Appearance.SerifFont) | ||
| 666 | m.viper.SetDefault("appearance.monospace_font", defaults.Appearance.MonospaceFont) | 679 | m.viper.SetDefault("appearance.monospace_font", defaults.Appearance.MonospaceFont) | ||
| 667 | m.viper.SetDefault("appearance.default_font_size", defaults.Appearance.DefaultFontSize) | 680 | m.viper.SetDefault("appearance.default_font_size", defaults.Appearance.DefaultFontSize) | ||
| 681 | + | m.viper.SetDefault("appearance.light_palette", defaults.Appearance.LightPalette) | |||
| 682 | + | m.viper.SetDefault("appearance.dark_palette", defaults.Appearance.DarkPalette) | |||
| 668 | 683 | ||||
| 669 | // Video acceleration defaults | 684 | // Video acceleration defaults | ||
| 670 | m.viper.SetDefault("video_acceleration.enable_vaapi", defaults.VideoAcceleration.EnableVAAPI) | 685 | m.viper.SetDefault("video_acceleration.enable_vaapi", defaults.VideoAcceleration.EnableVAAPI) | ||
| @@ -768,6 +783,7 @@ func (m *Manager) createDefaultConfig() error { | |||||
| 768 | defaultConfig := DefaultConfig() | 783 | defaultConfig := DefaultConfig() | ||
| 769 | 784 | ||||
| 770 | // Marshal to JSON with proper indentation | 785 | // Marshal to JSON with proper indentation | ||
| 786 | + | // Note: Go 1.20+ automatically sorts map keys in JSON output | |||
| 771 | configData, err := json.MarshalIndent(defaultConfig, "", " ") | 787 | configData, err := json.MarshalIndent(defaultConfig, "", " ") | ||
| 772 | if err != nil { | 788 | if err != nil { | ||
| 773 | return fmt.Errorf("failed to marshal default config: %w", err) | 789 | return fmt.Errorf("failed to marshal default config: %w", err) | ||
M internal/config/defaults.go +42 -41
| @@ -60,24 +60,7 @@ func DefaultConfig() *Config { | |||
| 60 | 60 | RetentionPeriodDays: defaultRetentionDays, // 1 year | |
| 61 | 61 | CleanupIntervalDays: 1, // daily cleanup | |
| 62 | 62 | }, | |
| 63 | - | SearchShortcuts: map[string]SearchShortcut{ | |
| 64 | - | "g": { | |
| 65 | - | URL: "https://www.google.com/search?q=%s", | |
| 66 | - | Description: "Google search", | |
| 67 | - | }, | |
| 68 | - | "gh": { | |
| 69 | - | URL: "https://github.com/search?q=%s", | |
| 70 | - | Description: "GitHub search", | |
| 71 | - | }, | |
| 72 | - | "yt": { | |
| 73 | - | URL: "https://www.youtube.com/results?search_query=%s", | |
| 74 | - | Description: "YouTube search", | |
| 75 | - | }, | |
| 76 | - | "w": { | |
| 77 | - | URL: "https://en.wikipedia.org/wiki/%s", | |
| 78 | - | Description: "Wikipedia search", | |
| 79 | - | }, | |
| 80 | - | }, | |
| 63 | + | SearchShortcuts: GetDefaultSearchShortcuts(), | |
| 81 | 64 | Dmenu: DmenuConfig{ | |
| 82 | 65 | MaxHistoryItems: defaultMaxHistoryItems, | |
| 83 | 66 | ShowVisitCount: true, | |
| @@ -110,6 +93,24 @@ func DefaultConfig() *Config { | |||
| 110 | 93 | SerifFont: "Fira Sans", | |
| 111 | 94 | MonospaceFont: "Fira Code", | |
| 112 | 95 | DefaultFontSize: defaultFontSize, | |
| 96 | + | LightPalette: ColorPalette{ | |
| 97 | + | Background: "#f8f8f8", | |
| 98 | + | Surface: "#f2f2f2", | |
| 99 | + | SurfaceVariant: "#ececec", | |
| 100 | + | Text: "#1a1a1a", | |
| 101 | + | Muted: "#6e6e6e", | |
| 102 | + | Accent: "#404040", | |
| 103 | + | Border: "#d2d2d2", | |
| 104 | + | }, | |
| 105 | + | DarkPalette: ColorPalette{ | |
| 106 | + | Background: "#0e0e0e", | |
| 107 | + | Surface: "#1a1a1a", | |
| 108 | + | SurfaceVariant: "#141414", | |
| 109 | + | Text: "#e4e4e4", | |
| 110 | + | Muted: "#848484", | |
| 111 | + | Accent: "#a8a8a8", | |
| 112 | + | Border: "#363636", | |
| 113 | + | }, | |
| 113 | 114 | }, | |
| 114 | 115 | VideoAcceleration: VideoAccelerationConfig{ | |
| 115 | 116 | EnableVAAPI: true, | |
| @@ -127,7 +128,7 @@ func DefaultConfig() *Config { | |||
| 127 | 128 | DisableVP9Hardware: false, // Allow VP9 hardware for high res content | |
| 128 | 129 | VideoBufferSizeMB: 16, // Larger buffer for AV1 streams | |
| 129 | 130 | QueueBufferTimeSec: 10, // More buffering time for smooth playback | |
| 130 | - | CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", // Chrome UA with AV1 support | |
| 131 | + | CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", // Chrome UA with AV1 support | |
| 131 | 132 | AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res | |
| 132 | 133 | DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing) | |
| 133 | 134 | }, | |
| @@ -209,6 +210,10 @@ func DefaultConfig() *Config { | |||
| 209 | 210 | // GetDefaultSearchShortcuts returns the default search shortcuts. | |
| 210 | 211 | func GetDefaultSearchShortcuts() map[string]SearchShortcut { | |
| 211 | 212 | return map[string]SearchShortcut{ | |
| 213 | + | "ddg": { | |
| 214 | + | URL: "https://duckduckgo.com/?q=%s", | |
| 215 | + | Description: "DuckDuckGo search", | |
| 216 | + | }, | |
| 212 | 217 | "g": { | |
| 213 | 218 | URL: "https://www.google.com/search?q=%s", | |
| 214 | 219 | Description: "Google search", | |
| @@ -217,37 +222,33 @@ func GetDefaultSearchShortcuts() map[string]SearchShortcut { | |||
| 217 | 222 | URL: "https://github.com/search?q=%s", | |
| 218 | 223 | Description: "GitHub search", | |
| 219 | 224 | }, | |
| 220 | - | "yt": { | |
| 221 | - | URL: "https://www.youtube.com/results?search_query=%s", | |
| 222 | - | Description: "YouTube search", | |
| 223 | - | }, | |
| 224 | - | "w": { | |
| 225 | - | URL: "https://en.wikipedia.org/wiki/%s", | |
| 226 | - | Description: "Wikipedia search", | |
| 225 | + | "go": { | |
| 226 | + | URL: "https://pkg.go.dev/search?q=%s", | |
| 227 | + | Description: "Go package search", | |
| 227 | 228 | }, | |
| 228 | - | "ddg": { | |
| 229 | - | URL: "https://duckduckgo.com/?q=%s", | |
| 230 | - | Description: "DuckDuckGo search", | |
| 229 | + | "mdn": { | |
| 230 | + | URL: "https://developer.mozilla.org/en-US/search?q=%s", | |
| 231 | + | Description: "MDN Web Docs search", | |
| 231 | 232 | }, | |
| 232 | - | "so": { | |
| 233 | - | URL: "https://stackoverflow.com/search?q=%s", | |
| 234 | - | Description: "Stack Overflow search", | |
| 233 | + | "npm": { | |
| 234 | + | URL: "https://www.npmjs.com/search?q=%s", | |
| 235 | + | Description: "npm package search", | |
| 235 | 236 | }, | |
| 236 | 237 | "r": { | |
| 237 | 238 | URL: "https://www.reddit.com/search?q=%s", | |
| 238 | 239 | Description: "Reddit search", | |
| 239 | 240 | }, | |
| 240 | - | "npm": { | |
| 241 | - | URL: "https://www.npmjs.com/search?q=%s", | |
| 242 | - | Description: "npm package search", | |
| 241 | + | "so": { | |
| 242 | + | URL: "https://stackoverflow.com/search?q=%s", | |
| 243 | + | Description: "Stack Overflow search", | |
| 243 | 244 | }, | |
| 244 | - | "go": { | |
| 245 | - | URL: "https://pkg.go.dev/search?q=%s", | |
| 246 | - | Description: "Go package search", | |
| 245 | + | "w": { | |
| 246 | + | URL: "https://en.wikipedia.org/wiki/%s", | |
| 247 | + | Description: "Wikipedia search", | |
| 247 | 248 | }, | |
| 248 | - | "mdn": { | |
| 249 | - | URL: "https://developer.mozilla.org/en-US/search?q=%s", | |
| 250 | - | Description: "MDN Web Docs search", | |
| 249 | + | "yt": { | |
| 250 | + | URL: "https://www.youtube.com/results?search_query=%s", | |
| 251 | + | Description: "YouTube search", | |
| 251 | 252 | }, | |
| 252 | 253 | } | |
| 253 | 254 | } | |
| @@ -60,24 +60,7 @@ func DefaultConfig() *Config { | |||||
| 60 | RetentionPeriodDays: defaultRetentionDays, // 1 year | 60 | RetentionPeriodDays: defaultRetentionDays, // 1 year | ||
| 61 | CleanupIntervalDays: 1, // daily cleanup | 61 | CleanupIntervalDays: 1, // daily cleanup | ||
| 62 | }, | 62 | }, | ||
| 63 | - | SearchShortcuts: map[string]SearchShortcut{ | 63 | + | SearchShortcuts: GetDefaultSearchShortcuts(), |
| 64 | - | "g": { | |||
| 65 | - | URL: "https://www.google.com/search?q=%s", | |||
| 66 | - | Description: "Google search", | |||
| 67 | - | }, | |||
| 68 | - | "gh": { | |||
| 69 | - | URL: "https://github.com/search?q=%s", | |||
| 70 | - | Description: "GitHub search", | |||
| 71 | - | }, | |||
| 72 | - | "yt": { | |||
| 73 | - | URL: "https://www.youtube.com/results?search_query=%s", | |||
| 74 | - | Description: "YouTube search", | |||
| 75 | - | }, | |||
| 76 | - | "w": { | |||
| 77 | - | URL: "https://en.wikipedia.org/wiki/%s", | |||
| 78 | - | Description: "Wikipedia search", | |||
| 79 | - | }, | |||
| 80 | - | }, | |||
| 81 | Dmenu: DmenuConfig{ | 64 | Dmenu: DmenuConfig{ | ||
| 82 | MaxHistoryItems: defaultMaxHistoryItems, | 65 | MaxHistoryItems: defaultMaxHistoryItems, | ||
| 83 | ShowVisitCount: true, | 66 | ShowVisitCount: true, | ||
| @@ -110,6 +93,24 @@ func DefaultConfig() *Config { | |||||
| 110 | SerifFont: "Fira Sans", | 93 | SerifFont: "Fira Sans", | ||
| 111 | MonospaceFont: "Fira Code", | 94 | MonospaceFont: "Fira Code", | ||
| 112 | DefaultFontSize: defaultFontSize, | 95 | DefaultFontSize: defaultFontSize, | ||
| 96 | + | LightPalette: ColorPalette{ | |||
| 97 | + | Background: "#f8f8f8", | |||
| 98 | + | Surface: "#f2f2f2", | |||
| 99 | + | SurfaceVariant: "#ececec", | |||
| 100 | + | Text: "#1a1a1a", | |||
| 101 | + | Muted: "#6e6e6e", | |||
| 102 | + | Accent: "#404040", | |||
| 103 | + | Border: "#d2d2d2", | |||
| 104 | + | }, | |||
| 105 | + | DarkPalette: ColorPalette{ | |||
| 106 | + | Background: "#0e0e0e", | |||
| 107 | + | Surface: "#1a1a1a", | |||
| 108 | + | SurfaceVariant: "#141414", | |||
| 109 | + | Text: "#e4e4e4", | |||
| 110 | + | Muted: "#848484", | |||
| 111 | + | Accent: "#a8a8a8", | |||
| 112 | + | Border: "#363636", | |||
| 113 | + | }, | |||
| 113 | }, | 114 | }, | ||
| 114 | VideoAcceleration: VideoAccelerationConfig{ | 115 | VideoAcceleration: VideoAccelerationConfig{ | ||
| 115 | EnableVAAPI: true, | 116 | EnableVAAPI: true, | ||
| @@ -127,7 +128,7 @@ func DefaultConfig() *Config { | |||||
| 127 | DisableVP9Hardware: false, // Allow VP9 hardware for high res content | 128 | DisableVP9Hardware: false, // Allow VP9 hardware for high res content | ||
| 128 | VideoBufferSizeMB: 16, // Larger buffer for AV1 streams | 129 | VideoBufferSizeMB: 16, // Larger buffer for AV1 streams | ||
| 129 | QueueBufferTimeSec: 10, // More buffering time for smooth playback | 130 | QueueBufferTimeSec: 10, // More buffering time for smooth playback | ||
| 130 | - | CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", // Chrome UA with AV1 support | 131 | + | CustomUserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", // Chrome UA with AV1 support |
| 131 | AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res | 132 | AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res | ||
| 132 | DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing) | 133 | DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing) | ||
| 133 | }, | 134 | }, | ||
| @@ -209,6 +210,10 @@ func DefaultConfig() *Config { | |||||
| 209 | // GetDefaultSearchShortcuts returns the default search shortcuts. | 210 | // GetDefaultSearchShortcuts returns the default search shortcuts. | ||
| 210 | func GetDefaultSearchShortcuts() map[string]SearchShortcut { | 211 | func GetDefaultSearchShortcuts() map[string]SearchShortcut { | ||
| 211 | return map[string]SearchShortcut{ | 212 | return map[string]SearchShortcut{ | ||
| 213 | + | "ddg": { | |||
| 214 | + | URL: "https://duckduckgo.com/?q=%s", | |||
| 215 | + | Description: "DuckDuckGo search", | |||
| 216 | + | }, | |||
| 212 | "g": { | 217 | "g": { | ||
| 213 | URL: "https://www.google.com/search?q=%s", | 218 | URL: "https://www.google.com/search?q=%s", | ||
| 214 | Description: "Google search", | 219 | Description: "Google search", | ||
| @@ -217,37 +222,33 @@ func GetDefaultSearchShortcuts() map[string]SearchShortcut { | |||||
| 217 | URL: "https://github.com/search?q=%s", | 222 | URL: "https://github.com/search?q=%s", | ||
| 218 | Description: "GitHub search", | 223 | Description: "GitHub search", | ||
| 219 | }, | 224 | }, | ||
| 220 | - | "yt": { | 225 | + | "go": { |
| 221 | - | URL: "https://www.youtube.com/results?search_query=%s", | 226 | + | URL: "https://pkg.go.dev/search?q=%s", |
| 222 | - | Description: "YouTube search", | 227 | + | Description: "Go package search", |
| 223 | - | }, | |||
| 224 | - | "w": { | |||
| 225 | - | URL: "https://en.wikipedia.org/wiki/%s", | |||
| 226 | - | Description: "Wikipedia search", | |||
| 227 | }, | 228 | }, | ||
| 228 | - | "ddg": { | 229 | + | "mdn": { |
| 229 | - | URL: "https://duckduckgo.com/?q=%s", | 230 | + | URL: "https://developer.mozilla.org/en-US/search?q=%s", |
| 230 | - | Description: "DuckDuckGo search", | 231 | + | Description: "MDN Web Docs search", |
| 231 | }, | 232 | }, | ||
| 232 | - | "so": { | 233 | + | "npm": { |
| 233 | - | URL: "https://stackoverflow.com/search?q=%s", | 234 | + | URL: "https://www.npmjs.com/search?q=%s", |
| 234 | - | Description: "Stack Overflow search", | 235 | + | Description: "npm package search", |
| 235 | }, | 236 | }, | ||
| 236 | "r": { | 237 | "r": { | ||
| 237 | URL: "https://www.reddit.com/search?q=%s", | 238 | URL: "https://www.reddit.com/search?q=%s", | ||
| 238 | Description: "Reddit search", | 239 | Description: "Reddit search", | ||
| 239 | }, | 240 | }, | ||
| 240 | - | "npm": { | 241 | + | "so": { |
| 241 | - | URL: "https://www.npmjs.com/search?q=%s", | 242 | + | URL: "https://stackoverflow.com/search?q=%s", |
| 242 | - | Description: "npm package search", | 243 | + | Description: "Stack Overflow search", |
| 243 | }, | 244 | }, | ||
| 244 | - | "go": { | 245 | + | "w": { |
| 245 | - | URL: "https://pkg.go.dev/search?q=%s", | 246 | + | URL: "https://en.wikipedia.org/wiki/%s", |
| 246 | - | Description: "Go package search", | 247 | + | Description: "Wikipedia search", |
| 247 | }, | 248 | }, | ||
| 248 | - | "mdn": { | 249 | + | "yt": { |
| 249 | - | URL: "https://developer.mozilla.org/en-US/search?q=%s", | 250 | + | URL: "https://www.youtube.com/results?search_query=%s", |
| 250 | - | Description: "MDN Web Docs search", | 251 | + | Description: "YouTube search", |
| 251 | }, | 252 | }, | ||
| 252 | } | 253 | } | ||
| 253 | } | 254 | } | ||