feat(config): add content filtering whitelist
Adds content_filtering_whitelist config to selectively disable ad blocking on specific domains. Default includes Twitch (twitch.tv, passport.twitch.tv, gql.twitch.tv) to allow Arkose Labs bot detection to function correctly. Whitelist checking happens during navigation before cosmetic filters are applied.
- commit
- e380785190cedda3da024d126d61d2a3bcc1b5e7
- author
- bamen · · 2025-10-08 06:45 UTC
- parent
- 90f2a23
- signature
- unsigned
5 files · +18 -3
M internal/app/browser/webview.go +1 -1
| @@ -371,7 +371,7 @@ func (app *BrowserApp) setupContentBlocking() error { | |||
| 371 | 371 | ||
| 372 | 372 | // Apply content filtering if available | |
| 373 | 373 | if app.filterManager != nil { | |
| 374 | - | app.webView.OnNavigate(uri, app.filterManager) | |
| 374 | + | app.webView.OnNavigate(uri, app.filterManager, app.config.ContentFilteringWhitelist) | |
| 375 | 375 | } | |
| 376 | 376 | ||
| 377 | 377 | // Note: GUI bundle (controls and toast) is now injected as User Script | |
| @@ -371,7 +371,7 @@ func (app *BrowserApp) setupContentBlocking() error { | |||||
| 371 | 371 | ||||
| 372 | // Apply content filtering if available | 372 | // Apply content filtering if available | ||
| 373 | if app.filterManager != nil { | 373 | if app.filterManager != nil { | ||
| 374 | - | app.webView.OnNavigate(uri, app.filterManager) | 374 | + | app.webView.OnNavigate(uri, app.filterManager, app.config.ContentFilteringWhitelist) |
| 375 | } | 375 | } | ||
| 376 | 376 | ||||
| 377 | // Note: GUI bundle (controls and toast) is now injected as User Script | 377 | // Note: GUI bundle (controls and toast) is now injected as User Script | ||
M internal/config/config.go +2 -0
| @@ -44,6 +44,8 @@ type Config struct { | |||
| 44 | 44 | DefaultZoom float64 `mapstructure:"default_zoom" yaml:"default_zoom"` | |
| 45 | 45 | // Workspace defines workspace, pane, and tab handling behaviour. | |
| 46 | 46 | Workspace WorkspaceConfig `mapstructure:"workspace" yaml:"workspace"` | |
| 47 | + | // ContentFilteringWhitelist domains skip ad blocking (e.g. Twitch breaks with bot detection) | |
| 48 | + | ContentFilteringWhitelist []string `mapstructure:"content_filtering_whitelist" yaml:"content_filtering_whitelist"` | |
| 47 | 49 | } | |
| 48 | 50 | ||
| 49 | 51 | // RenderingMode selects GPU vs CPU rendering. | |
| @@ -44,6 +44,8 @@ type Config struct { | |||||
| 44 | DefaultZoom float64 `mapstructure:"default_zoom" yaml:"default_zoom"` | 44 | DefaultZoom float64 `mapstructure:"default_zoom" yaml:"default_zoom"` | ||
| 45 | // Workspace defines workspace, pane, and tab handling behaviour. | 45 | // Workspace defines workspace, pane, and tab handling behaviour. | ||
| 46 | Workspace WorkspaceConfig `mapstructure:"workspace" yaml:"workspace"` | 46 | Workspace WorkspaceConfig `mapstructure:"workspace" yaml:"workspace"` | ||
| 47 | + | // ContentFilteringWhitelist domains skip ad blocking (e.g. Twitch breaks with bot detection) | |||
| 48 | + | ContentFilteringWhitelist []string `mapstructure:"content_filtering_whitelist" yaml:"content_filtering_whitelist"` | |||
| 47 | } | 49 | } | ||
| 48 | 50 | ||||
| 49 | // RenderingMode selects GPU vs CPU rendering. | 51 | // RenderingMode selects GPU vs CPU rendering. | ||
M internal/config/defaults.go +5 -0
| @@ -205,6 +205,11 @@ func DefaultConfig() *Config { | |||
| 205 | 205 | BorderRadius: defaultBorderRadius, | |
| 206 | 206 | }, | |
| 207 | 207 | }, | |
| 208 | + | ContentFilteringWhitelist: []string{ | |
| 209 | + | "twitch.tv", // Arkose Labs bot detection breaks with filtering | |
| 210 | + | "passport.twitch.tv", // Auth subdomain | |
| 211 | + | "gql.twitch.tv", // GraphQL API | |
| 212 | + | }, | |
| 208 | 213 | } | |
| 209 | 214 | } | |
| 210 | 215 | ||
| @@ -205,6 +205,11 @@ func DefaultConfig() *Config { | |||||
| 205 | BorderRadius: defaultBorderRadius, | 205 | BorderRadius: defaultBorderRadius, | ||
| 206 | }, | 206 | }, | ||
| 207 | }, | 207 | }, | ||
| 208 | + | ContentFilteringWhitelist: []string{ | |||
| 209 | + | "twitch.tv", // Arkose Labs bot detection breaks with filtering | |||
| 210 | + | "passport.twitch.tv", // Auth subdomain | |||
| 211 | + | "gql.twitch.tv", // GraphQL API | |||
| 212 | + | }, | |||
| 208 | } | 213 | } | ||
| 209 | } | 214 | } | ||
| 210 | 215 | ||||
M pkg/webkit/webview.go +1 -1
| @@ -279,7 +279,7 @@ func (w *WebView) InitializeContentBlocking(filterManager interface{}) error { | |||
| 279 | 279 | } | |
| 280 | 280 | ||
| 281 | 281 | // OnNavigate sets up domain-specific cosmetic filtering on navigation (stub) | |
| 282 | - | func (w *WebView) OnNavigate(url string, filterManager interface{}) { | |
| 282 | + | func (w *WebView) OnNavigate(url string, filterManager interface{}, whitelist []string) { | |
| 283 | 283 | // No-op in stub | |
| 284 | 284 | } | |
| 285 | 285 | ||
| @@ -279,7 +279,7 @@ func (w *WebView) InitializeContentBlocking(filterManager interface{}) error { | |||||
| 279 | } | 279 | } | ||
| 280 | 280 | ||||
| 281 | // OnNavigate sets up domain-specific cosmetic filtering on navigation (stub) | 281 | // OnNavigate sets up domain-specific cosmetic filtering on navigation (stub) | ||
| 282 | - | func (w *WebView) OnNavigate(url string, filterManager interface{}) { | 282 | + | func (w *WebView) OnNavigate(url string, filterManager interface{}, whitelist []string) { |
| 283 | // No-op in stub | 283 | // No-op in stub | ||
| 284 | } | 284 | } | ||
| 285 | 285 | ||||
M pkg/webkit/webview_cgo.go +9 -1
| @@ -2654,7 +2654,7 @@ func (w *WebView) InitializeContentBlocking(filterManager FilterManager) error { | |||
| 2654 | 2654 | } | |
| 2655 | 2655 | ||
| 2656 | 2656 | // OnNavigate sets up domain-specific cosmetic filtering on navigation | |
| 2657 | - | func (w *WebView) OnNavigate(url string, filterManager FilterManager) { | |
| 2657 | + | func (w *WebView) OnNavigate(url string, filterManager FilterManager, whitelist []string) { | |
| 2658 | 2658 | if w == nil || w.destroyed { | |
| 2659 | 2659 | return | |
| 2660 | 2660 | } | |
| @@ -2664,6 +2664,14 @@ func (w *WebView) OnNavigate(url string, filterManager FilterManager) { | |||
| 2664 | 2664 | return | |
| 2665 | 2665 | } | |
| 2666 | 2666 | ||
| 2667 | + | // Skip cosmetic filtering for whitelisted domains (e.g., Twitch with Arkose Labs bot detection) | |
| 2668 | + | for _, whitelistedDomain := range whitelist { | |
| 2669 | + | if strings.Contains(domain, whitelistedDomain) { | |
| 2670 | + | logging.Info("[webkit] Skipping cosmetic filtering for whitelisted domain: " + domain) | |
| 2671 | + | return | |
| 2672 | + | } | |
| 2673 | + | } | |
| 2674 | + | ||
| 2667 | 2675 | // Get domain-specific cosmetic rules | |
| 2668 | 2676 | script := filterManager.GetCosmeticScriptForDomain(domain) | |
| 2669 | 2677 | if script != "" { | |
| @@ -2654,7 +2654,7 @@ func (w *WebView) InitializeContentBlocking(filterManager FilterManager) error { | |||||
| 2654 | } | 2654 | } | ||
| 2655 | 2655 | ||||
| 2656 | // OnNavigate sets up domain-specific cosmetic filtering on navigation | 2656 | // OnNavigate sets up domain-specific cosmetic filtering on navigation | ||
| 2657 | - | func (w *WebView) OnNavigate(url string, filterManager FilterManager) { | 2657 | + | func (w *WebView) OnNavigate(url string, filterManager FilterManager, whitelist []string) { |
| 2658 | if w == nil || w.destroyed { | 2658 | if w == nil || w.destroyed { | ||
| 2659 | return | 2659 | return | ||
| 2660 | } | 2660 | } | ||
| @@ -2664,6 +2664,14 @@ func (w *WebView) OnNavigate(url string, filterManager FilterManager) { | |||||
| 2664 | return | 2664 | return | ||
| 2665 | } | 2665 | } | ||
| 2666 | 2666 | ||||
| 2667 | + | // Skip cosmetic filtering for whitelisted domains (e.g., Twitch with Arkose Labs bot detection) | |||
| 2668 | + | for _, whitelistedDomain := range whitelist { | |||
| 2669 | + | if strings.Contains(domain, whitelistedDomain) { | |||
| 2670 | + | logging.Info("[webkit] Skipping cosmetic filtering for whitelisted domain: " + domain) | |||
| 2671 | + | return | |||
| 2672 | + | } | |||
| 2673 | + | } | |||
| 2674 | + | ||||
| 2667 | // Get domain-specific cosmetic rules | 2675 | // Get domain-specific cosmetic rules | ||
| 2668 | script := filterManager.GetCosmeticScriptForDomain(domain) | 2676 | script := filterManager.GetCosmeticScriptForDomain(domain) | ||
| 2669 | if script != "" { | 2677 | if script != "" { | ||