From d9de9d185272d50f9c5b31a3db3edfb4f0fcedf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Guillot?= Date: Sat, 19 Jul 2025 10:38:19 -0700 Subject: [PATCH] feat(rss): fallback to enclosure URL when entry URL is missing --- internal/reader/rss/adapter.go | 8 +++++++- internal/reader/rss/parser_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/internal/reader/rss/adapter.go b/internal/reader/rss/adapter.go index b26636f6..8c0e3c4d 100644 --- a/internal/reader/rss/adapter.go +++ b/internal/reader/rss/adapter.go @@ -79,7 +79,13 @@ func (r *RSSAdapter) BuildFeed(baseURL string) *model.Feed { // Populate the entry URL. entryURL := findEntryURL(&item) if entryURL == "" { - entry.URL = feed.SiteURL + // Fallback to the first enclosure URL if it exists. + if len(entry.Enclosures) > 0 && entry.Enclosures[0].URL != "" { + entry.URL = entry.Enclosures[0].URL + } else { + // Fallback to the feed URL if no entry URL is found. + entry.URL = feed.SiteURL + } } else { if absoluteEntryURL, err := urllib.AbsoluteURL(feed.SiteURL, entryURL); err == nil { entry.URL = absoluteEntryURL diff --git a/internal/reader/rss/parser_test.go b/internal/reader/rss/parser_test.go index 791eeab5..422073fe 100644 --- a/internal/reader/rss/parser_test.go +++ b/internal/reader/rss/parser_test.go @@ -632,6 +632,34 @@ func TestParseEntryWithMultipleAtomLinks(t *testing.T) { } } +func TestParseEntryWithoutLinkAndWithEnclosureURLs(t *testing.T) { + data := ` + + + https://example.org/feed + + guid + + + + + + ` + + feed, err := Parse("https://example.org/", bytes.NewReader([]byte(data))) + if err != nil { + t.Fatal(err) + } + + if len(feed.Entries) != 1 { + t.Fatalf("Expected 1 entry, got: %d", len(feed.Entries)) + } + + if feed.Entries[0].URL != "https://audio-file" { + t.Errorf("Incorrect entry link, got: %q", feed.Entries[0].URL) + } +} + func TestParseFeedURLWithAtomLink(t *testing.T) { data := `