Skip to content

feat: add fallback icon and image on RSS feeds #483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,8 @@ An array of RSS/atom feeds. The title can optionally be changed.
| limit | integer | no | | |
| item-link-prefix | string | no | | |
| headers | key (string) & value (string) | no | | |
| fallback-icon | string | no | | URL to an icon to use if the feed doesn't provide one |
| fallback-image | string | no | | URL to an image to use if the feed doesn't provide one |

###### `limit`
The maximum number of articles to show from that specific feed. Useful if you have a feed which posts a lot of articles frequently and you want to prevent it from excessively pushing down articles from other feeds.
Expand All @@ -610,6 +612,43 @@ Optionally specify the headers that will be sent with the request. Example:
User-Agent: Custom User Agent
```

###### `fallback-icon`
If the feed doesn't provide an image, this will be used instead.

```yaml
- type: rss
feeds:
- url: https://domain.com/rss
fallback-icon: https://..../image.png
```

You can also directly use [Simple Icons](https://simpleicons.org/) via a `si:` prefix or [Dashboard Icons](https://github.com/walkxcode/dashboard-icons) via a `di:` prefix:

```yaml
- type: rss
feeds:
- url: https://domain.com/rss
fallback-icon: si:github
```

> [!WARNING]
>
> The `fallback-icon` property cannot be defined if `fallback-image` is also defined.

###### `fallback-image`
If the feed doesn't provide an image, this will be used instead. Example:

```yaml
- type: rss
feeds:
- url: https://domain.com/rss
fallback-icon: https://..../image.png
```

> [!WARNING]
>
> The `fallback-icon` property cannot be defined if `fallback-image` is also defined.

### Videos
Display a list of the latest videos from specific YouTube channels.

Expand Down
5 changes: 5 additions & 0 deletions internal/glance/static/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,11 @@ details[open] .summary::after {
height: 8.7rem;
}

.fallback-icon-thumbnail {
margin: auto;
height: 100%;
}

.twitch-category-thumbnail {
width: 5rem;
aspect-ratio: 3 / 4;
Expand Down
8 changes: 7 additions & 1 deletion internal/glance/templates/rss-detailed-list.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
{{ range .Items }}
<li class="flex gap-15 items-start row-reverse-on-mobile thumbnail-parent">
<div class="thumbnail-container rss-detailed-thumbnail">
{{ if ne "" .ImageURL }}
{{ if and (eq "" .ImageURL) (ne "" .FallbackIconURL) }}
<div class="scale-half hide-on-mobile">
<img class="fallback-icon-thumbnail" loading="lazy" src="{{ .FallbackIconURL }}" alt="">
</div>
{{ else if and (eq "" .ImageURL) (ne "" .FallbackImageURL) }}
<img class="thumbnail" loading="lazy" src="{{ .FallbackImageURL }}" alt="">
{{ else if and (ne "" .ImageURL) (eq "" .FallbackImageURL) }}
<img class="thumbnail" loading="lazy" src="{{ .ImageURL }}" alt="">
{{ else }}
<svg class="scale-half hide-on-mobile" stroke="var(--color-text-subdue)" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5">
Expand Down
8 changes: 7 additions & 1 deletion internal/glance/templates/rss-horizontal-cards-2.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
<div class="cards-horizontal carousel-items-container"{{ if ne 0.0 .CardHeight }} style="--rss-card-height: {{ .CardHeight }}rem;"{{ end }}>
{{ range .Items }}
<div class="card rss-card-2 widget-content-frame thumbnail-parent">
{{ if ne "" .ImageURL }}
{{ if and (eq "" .ImageURL) (ne "" .FallbackIconURL) }}
<div class="rss-card-2-image scale-half hide-on-mobile">
<img class="fallback-icon-thumbnail" loading="lazy" src="{{ .FallbackIconURL }}" alt="">
</div>
{{ else if and (eq "" .ImageURL) (ne "" .FallbackImageURL) }}
<img class="rss-card-2-image thumbnail" loading="lazy" src="{{ .FallbackImageURL }}" alt="">
{{ else if and (ne "" .ImageURL) (eq "" .FallbackImageURL) }}
<img class="rss-card-2-image thumbnail" loading="lazy" src="{{ .ImageURL }}" alt="">
{{ else }}
<svg class="rss-card-2-image" style="transform: scale(0.35) translateY(-25%)" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="var(--color-text-subdue)">
Expand Down
8 changes: 7 additions & 1 deletion internal/glance/templates/rss-horizontal-cards.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
<div class="cards-horizontal carousel-items-container"{{ if ne 0.0 .ThumbnailHeight }} style="--rss-thumbnail-height: {{ .ThumbnailHeight }}rem;"{{ end }}>
{{ range .Items }}
<div class="card widget-content-frame thumbnail-parent">
{{ if ne "" .ImageURL }}
{{ if and (eq "" .ImageURL) (ne "" .FallbackIconURL) }}
<div class="rss-card-image scale-half hide-on-mobile">
<img class="fallback-icon-thumbnail" loading="lazy" src="{{ .FallbackIconURL }}" alt="">
</div>
{{ else if and (eq "" .ImageURL) (ne "" .FallbackImageURL) }}
<img class="rss-card-image thumbnail" loading="lazy" src="{{ .FallbackImageURL }}" alt="">
{{ else if and (ne "" .ImageURL) (eq "" .FallbackImageURL) }}
<img class="rss-card-image thumbnail" loading="lazy" src="{{ .ImageURL }}" alt="">
{{ else }}
<svg class="rss-card-image" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="var(--color-text-subdue)">
Expand Down
28 changes: 20 additions & 8 deletions internal/glance/widget-rss.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ func (widget *rssWidget) initialize() error {

if widget.Style == "detailed-list" {
for i := range widget.FeedRequests {
if widget.FeedRequests[i].FallbackImage != "" && widget.FeedRequests[i].FallbackIcon != "" {
return fmt.Errorf("RSS feed %s in widget %s has both fallback image and icon set", widget.FeedRequests[i].Title, widget.Title)
}

widget.FeedRequests[i].IsDetailed = true
}
}
Expand Down Expand Up @@ -104,14 +108,16 @@ func (widget *rssWidget) Render() template.HTML {
}

type rssFeedItem struct {
ChannelName string
ChannelURL string
Title string
Link string
ImageURL string
Categories []string
Description string
PublishedAt time.Time
ChannelName string
ChannelURL string
Title string
Link string
ImageURL string
FallbackIconURL string
FallbackImageURL string
Categories []string
Description string
PublishedAt time.Time
}

// doesn't cover all cases but works the vast majority of the time
Expand Down Expand Up @@ -146,6 +152,8 @@ func shortenFeedDescriptionLen(description string, maxLen int) string {
type rssFeedRequest struct {
URL string `yaml:"url"`
Title string `yaml:"title"`
FallbackImage string `yaml:"fallback-image"`
FallbackIcon string `yaml:"fallback-icon"`
HideCategories bool `yaml:"hide-categories"`
HideDescription bool `yaml:"hide-description"`
Limit int `yaml:"limit"`
Expand Down Expand Up @@ -278,6 +286,10 @@ func fetchItemsFromRSSFeedTask(request rssFeedRequest) ([]rssFeedItem, error) {
} else {
rssItem.ImageURL = feed.Image.URL
}
} else if request.FallbackIcon != "" {
rssItem.FallbackIconURL = newCustomIconField(request.FallbackIcon).URL
} else if request.FallbackImage != "" {
rssItem.FallbackImageURL = request.FallbackImage
}

if item.PublishedParsed != nil {
Expand Down