aboutsummaryrefslogtreecommitdiffhomepage
path: root/backend/feed
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-01 10:05:13 +0900
committernsfisis <nsfisis@gmail.com>2026-02-01 10:05:13 +0900
commit1d78371e13c19488d472257ab614e0be17bfa85e (patch)
tree6c14cf068faac9a9a411d1cf6c436ae23ba235c2 /backend/feed
parent65d6ebca318fecb48b32c0ecdba3ae01304b55de (diff)
downloadfeedaka-1d78371e13c19488d472257ab614e0be17bfa85e.tar.gz
feedaka-1d78371e13c19488d472257ab614e0be17bfa85e.tar.zst
feedaka-1d78371e13c19488d472257ab614e0be17bfa85e.zip
refactor: extract feed fetch and sync logic into shared feed package
Consolidate duplicated feed fetching and article syncing code from AddFeed resolver and fetchOneFeed into reusable feed.Fetch and feed.Sync functions. This unifies behavior (10s timeout, article updates) across both call sites. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'backend/feed')
-rw-r--r--backend/feed/feed.go75
1 files changed, 75 insertions, 0 deletions
diff --git a/backend/feed/feed.go b/backend/feed/feed.go
new file mode 100644
index 0000000..4349d1e
--- /dev/null
+++ b/backend/feed/feed.go
@@ -0,0 +1,75 @@
+package feed
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/mmcdole/gofeed"
+
+ "undef.ninja/x/feedaka/db"
+)
+
+func Fetch(ctx context.Context, url string) (*gofeed.Feed, error) {
+ fp := gofeed.NewParser()
+ ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
+ defer cancel()
+ feed, err := fp.ParseURLWithContext(url, ctx)
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch %s: %w", url, err)
+ }
+ return feed, nil
+}
+
+func Sync(ctx context.Context, queries *db.Queries, feedID int64, f *gofeed.Feed) error {
+ err := queries.UpdateFeedMetadata(ctx, db.UpdateFeedMetadataParams{
+ Title: f.Title,
+ FetchedAt: time.Now().UTC().Format(time.RFC3339),
+ ID: feedID,
+ })
+ if err != nil {
+ return err
+ }
+
+ guids, err := queries.GetArticleGUIDsByFeed(ctx, feedID)
+ if err != nil {
+ return err
+ }
+ existingFeedGUIDs := make(map[string]bool, len(guids))
+ for _, guid := range guids {
+ existingFeedGUIDs[guid] = true
+ }
+
+ for _, item := range f.Items {
+ if existingFeedGUIDs[item.GUID] {
+ err := queries.UpdateArticle(ctx, db.UpdateArticleParams{
+ Title: item.Title,
+ Url: item.Link,
+ FeedID: feedID,
+ Guid: item.GUID,
+ })
+ if err != nil {
+ return err
+ }
+ } else {
+ exists, err := queries.CheckArticleExistsByGUID(ctx, item.GUID)
+ if err != nil {
+ return err
+ }
+ if exists == 1 {
+ continue
+ }
+ _, err = queries.CreateArticle(ctx, db.CreateArticleParams{
+ FeedID: feedID,
+ Guid: item.GUID,
+ Title: item.Title,
+ Url: item.Link,
+ IsRead: 0,
+ })
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}