2026-08-05 12:06:46 +05:00
|
|
|
package rss
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"log/slog"
|
|
|
|
|
"net/url"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/mmcdole/gofeed"
|
|
|
|
|
"go.dev.pztrn.name/rsser/fixers"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Parse parses RSS feeds and produce output in outputs.
|
|
|
|
|
func (r *RSS) Parse() {
|
|
|
|
|
for _, feed := range r.cfg.RSS.Feeds {
|
|
|
|
|
ctx, cancelFunc := context.WithTimeout(
|
|
|
|
|
context.Background(),
|
|
|
|
|
time.Second*time.Duration(r.cfg.RSS.HTTPClient.RequestTimeoutSeconds),
|
|
|
|
|
)
|
|
|
|
|
//revive:disable:defer
|
|
|
|
|
defer cancelFunc()
|
|
|
|
|
|
|
|
|
|
parser := gofeed.NewParser()
|
|
|
|
|
|
|
|
|
|
parsedFeedData, err := parser.ParseURLWithContext(feed.URL, ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("Failed to parse feed!", "name", feed.Name, "error", err.Error())
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
feedURL, _ := url.Parse(feed.URL)
|
|
|
|
|
|
|
|
|
|
for _, item := range parsedFeedData.Items {
|
|
|
|
|
slog.Info(
|
|
|
|
|
"Processing feed item...",
|
|
|
|
|
"domain", feedURL.Host,
|
|
|
|
|
"guid", item.GUID,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
itemWasProcessed, err := r.checkItemWasProcessed(feedURL.Host, item.GUID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error(
|
|
|
|
|
"Failed to check item processing status!",
|
|
|
|
|
"domain", feedURL.Host,
|
|
|
|
|
"guid", item.GUID,
|
|
|
|
|
"error", err.Error(),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if itemWasProcessed {
|
|
|
|
|
slog.Info(
|
|
|
|
|
"Feed item already processed, skipping.",
|
|
|
|
|
"domain", feedURL.Host,
|
|
|
|
|
"guid", item.GUID,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-09 07:27:19 +05:00
|
|
|
title, fixedDescription := fixers.Fix(feedURL.Host, item)
|
2026-08-05 12:06:46 +05:00
|
|
|
|
|
|
|
|
for _, output := range r.outputs {
|
|
|
|
|
if feed.Output == output.Name() {
|
|
|
|
|
if err := output.Do(feed.Destination, feed.Name, item.Link, title, fixedDescription); err != nil {
|
|
|
|
|
slog.Error(
|
|
|
|
|
"Failed to process feed item with outputter!",
|
|
|
|
|
"feed", feed.Name,
|
|
|
|
|
"guid", item.GUID,
|
|
|
|
|
"error", err.Error(),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := r.addProcessedItem(feedURL.Host, item.GUID); err != nil {
|
|
|
|
|
slog.Error(
|
|
|
|
|
"Failed to save item processing status!",
|
|
|
|
|
"domain", feedURL.Host,
|
|
|
|
|
"guid", item.GUID,
|
|
|
|
|
"error", err.Error(),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|