From 10bc71779486a75c70a90278c91e4790e29b1ba6 Mon Sep 17 00:00:00 2001 From: anzzyspeaksgit Date: Tue, 24 Mar 2026 10:09:27 +0000 Subject: [PATCH] feat: Add channel allowlist to skip sponsor processing for specified channels Closes #177 --- internal/config/config.go | 3 +++ internal/config/load.go | 6 +++++- internal/config/names/names.go | 1 + internal/device/watch.go | 18 +++++++++++++++--- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index b04e87e..3d99e7c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -29,6 +29,7 @@ type Config struct { SkipSponsors bool `yaml:"skip-sponsors"` Categories []string `yaml:"categories"` ActionTypes []string `yaml:"action-types"` + AllowChannels []string `yaml:"allow-channels"` YouTubeAPIKey string `yaml:"youtube-api-key"` MuteAds bool `yaml:"mute-ads"` @@ -47,6 +48,7 @@ func New() *Config { SkipSponsors: true, Categories: []string{"sponsor"}, ActionTypes: []string{"skip", "mute"}, + AllowChannels: []string{}, MuteAds: true, } @@ -72,6 +74,7 @@ func RegisterFlags(cmd *cobra.Command) { fs.Bool(names.FlagSkipSponsors, c.SkipSponsors, "Skip sponsored segments with SponsorBlock") fs.StringSliceP(names.FlagCategories, "c", c.Categories, "Comma-separated list of SponsorBlock categories to skip") fs.StringSlice(names.FlagActionTypes, c.ActionTypes, "SponsorBlock action types to handle. Shorter segments that overlap with content can be muted instead of skipped.") + fs.StringSliceP(names.FlagAllowChannels, "a", c.AllowChannels, "Comma-separated list of channel names or IDs to allowlist (will not skip sponsors)") fs.String(names.FlagYouTubeAPIKey, c.YouTubeAPIKey, "YouTube API key for fallback video identification (required on some Chromecast devices).") fs.Bool(names.FlagMuteAds, c.MuteAds, "Mutes the device while an ad is playing") diff --git a/internal/config/load.go b/internal/config/load.go index 0a5b7c7..97b37f2 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -85,7 +85,7 @@ func Load(cmd *cobra.Command) (*Config, error) { k = strings.ReplaceAll(strings.ToLower(strings.TrimPrefix(k, EnvPrefix)), "_", "-") switch k { - case names.FlagDevices, names.FlagCategories, names.FlagActionTypes: + case names.FlagDevices, names.FlagCategories, names.FlagActionTypes, names.FlagAllowChannels: return k, strings.Split(v, ",") default: return k, v @@ -120,6 +120,10 @@ func Load(cmd *cobra.Command) (*Config, error) { c.ActionTypes[i] = strings.TrimSpace(actionType) } + for i, allowChannel := range c.AllowChannels { + c.AllowChannels[i] = strings.TrimSpace(allowChannel) + } + if len(c.DeviceAddrStrs) != 0 { c.DeviceAddrs = make([]castdns.CastEntry, 0, len(c.DeviceAddrStrs)) for _, device := range c.DeviceAddrStrs { diff --git a/internal/config/names/names.go b/internal/config/names/names.go index 89b8a76..51dafca 100644 --- a/internal/config/names/names.go +++ b/internal/config/names/names.go @@ -17,6 +17,7 @@ const ( FlagSkipSponsors = "skip-sponsors" FlagCategories = "categories" FlagActionTypes = "action-types" + FlagAllowChannels = "allow-channels" FlagYouTubeAPIKey = "youtube-api-key" FlagMuteAds = "mute-ads" diff --git a/internal/device/watch.go b/internal/device/watch.go index 25b1f81..6b82181 100644 --- a/internal/device/watch.go +++ b/internal/device/watch.go @@ -6,6 +6,7 @@ import ( "log/slog" "os" "runtime/debug" + "strings" "sync" "time" @@ -218,9 +219,20 @@ func (d *Device) tick() error { break } - for i, segment := range d.segments { - if (segment.Segment[0]+float32(d.config.SkipDelay.Seconds())) <= castMedia.CurrentTime && castMedia.CurrentTime < segment.Segment[1]-1 { - d.handleSegment(castMedia, castVol, segment, i) + // Skip processing if the channel is in the allowlist + allowed := false + for _, allowChannel := range d.config.AllowChannels { + if strings.EqualFold(d.meta.CurrArtist, allowChannel) { + allowed = true + break + } + } + + if !allowed { + for i, segment := range d.segments { + if (segment.Segment[0]+float32(d.config.SkipDelay.Seconds())) <= castMedia.CurrentTime && castMedia.CurrentTime < segment.Segment[1]-1 { + d.handleSegment(castMedia, castVol, segment, i) + } } }