diff --git a/internal/glance/templates/videos-grid.html b/internal/glance/templates/videos-grid.html index 2819fe8..4c87384 100644 --- a/internal/glance/templates/videos-grid.html +++ b/internal/glance/templates/videos-grid.html @@ -1,8 +1,11 @@ {{ template "widget-base.html" . }} -{{ define "widget-content-classes" }}widget-content-frameless{{ end }} +{{ define "widget-content-classes" }}{{ if not .Filters.AllFiltered }}widget-content-frameless{{ end }}{{ end }} {{ define "widget-content" }} +{{ if .Filters.AllFiltered }} +

No videos match the specified filters ({{ .Filters.FilteredCount }} filtered)

+{{ else }}
{{ range .Videos }}
@@ -11,3 +14,4 @@ {{ end }}
{{ end }} +{{ end }} diff --git a/internal/glance/templates/videos-vertical-list.html b/internal/glance/templates/videos-vertical-list.html index cd760a4..a6639f2 100644 --- a/internal/glance/templates/videos-vertical-list.html +++ b/internal/glance/templates/videos-vertical-list.html @@ -1,6 +1,9 @@ {{ template "widget-base.html" . }} {{- define "widget-content" }} +{{ if .Filters.AllFiltered }} +

No videos match the specified filters ({{ .Filters.FilteredCount }} filtered)

+{{ else }} +{{ end }} {{- end }} diff --git a/internal/glance/templates/videos.html b/internal/glance/templates/videos.html index 16e7261..8a09b18 100644 --- a/internal/glance/templates/videos.html +++ b/internal/glance/templates/videos.html @@ -1,8 +1,11 @@ {{ template "widget-base.html" . }} -{{ define "widget-content-classes" }}widget-content-frameless{{ end }} +{{ define "widget-content-classes" }}{{ if not .Filters.AllFiltered }}widget-content-frameless{{ end }}{{ end }} {{ define "widget-content" }} +{{ if .Filters.AllFiltered }} +

No videos match the specified filters ({{ .Filters.FilteredCount }} filtered)

+{{ else }} {{ end }} +{{ end }} diff --git a/internal/glance/widget-rss.go b/internal/glance/widget-rss.go index fe17b2f..cf036bd 100644 --- a/internal/glance/widget-rss.go +++ b/internal/glance/widget-rss.go @@ -44,6 +44,8 @@ type rssWidget struct { cachedFeedsMutex sync.Mutex cachedFeeds map[string]*cachedRSSFeed `yaml:"-"` + + Filters filterableFields[rssFeedItem] `yaml:"filters"` } func (widget *rssWidget) initialize() error { @@ -71,13 +73,14 @@ func (widget *rssWidget) initialize() error { } } - widget.NoItemsMessage = "No items were returned from the feeds." widget.cachedFeeds = make(map[string]*cachedRSSFeed) return nil } func (widget *rssWidget) update(ctx context.Context) { + widget.NoItemsMessage = "No items were returned from the feeds." + items, err := widget.fetchItemsFromFeeds() if !widget.canContinueUpdateAfterHandlingErr(err) { @@ -88,6 +91,15 @@ func (widget *rssWidget) update(ctx context.Context) { items.sortByNewest() } + items = widget.Filters.Apply(items) + + if widget.Filters.AllFiltered { + widget.NoItemsMessage = fmt.Sprintf( + "No items match the specified filters (%d filtered)", + widget.Filters.FilteredCount, + ) + } + if len(items) > widget.Limit { items = items[:widget.Limit] } @@ -128,6 +140,19 @@ type rssFeedItem struct { PublishedAt time.Time } +func (i rssFeedItem) filterableField(field string) any { + switch field { + case "title": + return i.Title + case "description": + return i.Description + case "posted": + return i.PublishedAt + default: + return nil + } +} + type rssFeedRequest struct { URL string `yaml:"url"` Title string `yaml:"title"` diff --git a/internal/glance/widget-videos.go b/internal/glance/widget-videos.go index ecf77fa..569f1da 100644 --- a/internal/glance/widget-videos.go +++ b/internal/glance/widget-videos.go @@ -32,6 +32,8 @@ type videosWidget struct { Limit int `yaml:"limit"` IncludeShorts bool `yaml:"include-shorts"` SortBy string `yaml:"sort-by"` + + Filters filterableFields[video] `yaml:"filters"` } func (widget *videosWidget) initialize() error { @@ -71,6 +73,8 @@ func (widget *videosWidget) update(ctx context.Context) { return } + videos = widget.Filters.Apply(videos) + if len(videos) > widget.Limit { videos = videos[:widget.Limit] } @@ -131,6 +135,19 @@ type video struct { TimeUpdated time.Time } +func (v video) filterableField(field string) any { + switch field { + case "title": + return v.Title + case "posted": + return v.TimePosted + case "updated": + return v.TimeUpdated + default: + return nil + } +} + type videoList []video func (v videoList) sortByPosted() videoList { @@ -154,9 +171,8 @@ func fetchYoutubeChannelUploads(channelOrPlaylistIDs []string, videoUrlTemplate for i := range channelOrPlaylistIDs { var feedUrl string - if strings.HasPrefix(channelOrPlaylistIDs[i], videosWidgetPlaylistPrefix) { - feedUrl = "https://www.youtube.com/feeds/videos.xml?playlist_id=" + - strings.TrimPrefix(channelOrPlaylistIDs[i], videosWidgetPlaylistPrefix) + if after, ok := strings.CutPrefix(channelOrPlaylistIDs[i], videosWidgetPlaylistPrefix); ok { + feedUrl = "https://www.youtube.com/feeds/videos.xml?playlist_id=" + after } else if !includeShorts && strings.HasPrefix(channelOrPlaylistIDs[i], "UC") { playlistId := strings.Replace(channelOrPlaylistIDs[i], "UC", "UULF", 1) feedUrl = "https://www.youtube.com/feeds/videos.xml?playlist_id=" + playlistId