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) + } } }