use freshrss api to load rss feeds

This commit is contained in:
trinidz 2024-06-04 10:00:51 +00:00
parent b83bf9bc09
commit 97fb1e5afb
3 changed files with 156 additions and 0 deletions

View File

@ -1,10 +1,15 @@
package feed
import (
"bytes"
"context"
"crypto/md5"
"encoding/json"
"fmt"
"html"
"io"
"log/slog"
"net/http"
"net/url"
"regexp"
"sort"
@ -25,6 +30,29 @@ type RSSFeedItem struct {
PublishedAt time.Time
}
type FreshRssFeedsGroups struct {
Group_id int
Feed_ids string
}
type FreshRssFeed struct {
Id int
Favicon_id int
Title string
Url string
Site_url string
Is_spark int
Last_updated_on_time int
}
type FreshRSSFeedsAPI struct {
Api_version uint
Auth uint
Last_refreshed_on_time int
Feeds []FreshRssFeed
Feeds_groups []FreshRssFeedsGroups
}
// doesn't cover all cases but works the vast majority of the time
var htmlTagsWithAttributesPattern = regexp.MustCompile(`<\/?[a-zA-Z0-9-]+ *(?:[a-zA-Z-]+=(?:"|').*?(?:"|') ?)* *\/?>`)
var sequentialWhitespacePattern = regexp.MustCompile(`\s+`)
@ -195,3 +223,53 @@ func GetItemsFromRSSFeeds(requests []RSSFeedRequest) (RSSFeedItems, error) {
return entries, nil
}
func GetItemsFromFreshRssFeeds(freshrssUrl string, freshrssUser string, freshrsspass string) (RSSFeedItems, error) {
var p FreshRSSFeedsAPI
var feedReqs []RSSFeedRequest
var param = url.Values{}
user_credentials := []byte(fmt.Sprintf("%v:%v", freshrssUser, freshrsspass))
api_key := fmt.Sprintf("%x", md5.Sum(user_credentials))
param.Set("api_key", api_key)
param.Set("feeds", "")
var payload = bytes.NewBufferString(param.Encode())
requestURL := fmt.Sprintf("%v/api/fever.php?api", freshrssUrl)
req, err := http.NewRequest(http.MethodPost, requestURL, payload)
if err != nil {
return nil, fmt.Errorf("could not create freshRss request: %v ", err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := http.Client{
Timeout: 10 * time.Second,
}
res, err := client.Do(req)
if err != nil || res.StatusCode != 200 {
return nil, fmt.Errorf("could not connect to freshRss instance: %v", err)
}
resBody, err := io.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("could not read freshRss response body: %v", err)
}
errr := json.Unmarshal(resBody, &p)
if errr != nil {
return nil, fmt.Errorf("could not unmarshal freshrss response body: %v", errr)
}
for i := range p.Feeds {
var feedReq RSSFeedRequest
feedReq.Url = p.Feeds[i].Url
feedReq.Title = p.Feeds[i].Title
feedReqs = append(feedReqs, feedReq)
}
return GetItemsFromRSSFeeds(feedReqs)
}

View File

@ -0,0 +1,76 @@
package widget
import (
"context"
"html/template"
"time"
"github.com/glanceapp/glance/internal/assets"
"github.com/glanceapp/glance/internal/feed"
)
type FreshRSS struct {
widgetBase `yaml:",inline"`
FeedRequests []feed.RSSFeedRequest `yaml:"feeds"`
Style string `yaml:"style"`
ThumbnailHeight float64 `yaml:"thumbnail-height"`
CardHeight float64 `yaml:"card-height"`
Items feed.RSSFeedItems `yaml:"-"`
Limit int `yaml:"limit"`
CollapseAfter int `yaml:"collapse-after"`
FreshRSSUrl string `yaml:"freshrss-url"`
FreshRSSUser string `yaml:"freshrss-user"`
FreshRSSApiPass string `yaml:"freshrss-api-pass"`
}
func (widget *FreshRSS) Initialize() error {
widget.withTitle("FreshRSS Feed").withCacheDuration(1 * time.Hour)
if widget.Limit <= 0 {
widget.Limit = 25
}
if widget.CollapseAfter == 0 || widget.CollapseAfter < -1 {
widget.CollapseAfter = 5
}
if widget.ThumbnailHeight < 0 {
widget.ThumbnailHeight = 0
}
if widget.CardHeight < 0 {
widget.CardHeight = 0
}
return nil
}
func (widget *FreshRSS) Update(ctx context.Context) {
var items feed.RSSFeedItems
var err error
items, err = feed.GetItemsFromFreshRssFeeds(widget.FreshRSSUrl, widget.FreshRSSUser, widget.FreshRSSApiPass)
if !widget.canContinueUpdateAfterHandlingErr(err) {
return
}
if len(items) > widget.Limit {
items = items[:widget.Limit]
}
widget.Items = items
}
func (widget *FreshRSS) Render() template.HTML {
if widget.Style == "horizontal-cards" {
return widget.render(widget, assets.RSSHorizontalCardsTemplate)
}
if widget.Style == "horizontal-cards-2" {
return widget.render(widget, assets.RSSHorizontalCards2Template)
}
return widget.render(widget, assets.RSSListTemplate)
}

View File

@ -41,6 +41,8 @@ func New(widgetType string) (Widget, error) {
return &Reddit{}, nil
case "rss":
return &RSS{}, nil
case "freshrss":
return &FreshRSS{}, nil
case "monitor":
return &Monitor{}, nil
case "twitch-top-games":