1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-07-02 16:38:37 +00:00

feat: populate feed description automatically

This commit is contained in:
Frédéric Guillot 2025-05-24 21:10:13 -07:00
parent 5920e02562
commit 8142268799
9 changed files with 83 additions and 11 deletions

View file

@ -39,6 +39,10 @@ type Atom10Feed struct {
// atom:feed elements MUST contain exactly one atom:title element. // atom:feed elements MUST contain exactly one atom:title element.
Title Atom10Text `xml:"http://www.w3.org/2005/Atom title"` Title Atom10Text `xml:"http://www.w3.org/2005/Atom title"`
// The "atom:subtitle" element is a Text construct that
// contains a human-readable description or subtitle for the feed.
Subtitle Atom10Text `xml:"http://www.w3.org/2005/Atom subtitle"`
// The "atom:author" element is a Person construct that indicates the // The "atom:author" element is a Person construct that indicates the
// author of the entry or feed. // author of the entry or feed.
// //

View file

@ -55,6 +55,9 @@ func (a *Atom10Adapter) BuildFeed(baseURL string) *model.Feed {
feed.Title = feed.SiteURL feed.Title = feed.SiteURL
} }
// Populate the feed description.
feed.Description = a.atomFeed.Subtitle.Body()
// Populate the feed icon. // Populate the feed icon.
if a.atomFeed.Icon != "" { if a.atomFeed.Icon != "" {
if absoluteIconURL, err := urllib.AbsoluteURL(feed.SiteURL, a.atomFeed.Icon); err == nil { if absoluteIconURL, err := urllib.AbsoluteURL(feed.SiteURL, a.atomFeed.Icon); err == nil {

View file

@ -82,6 +82,29 @@ func TestParseAtomSample(t *testing.T) {
} }
} }
func TestParseFeedWithSubtitle(t *testing.T) {
data := `<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Example Feed</title>
<subtitle>This is a subtitle</subtitle>
<link href="http://example.org/"/>
<updated>2003-12-13T18:30:02Z</updated>
<author>
<name>John Doe</name>
</author>
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
</feed>`
feed, err := Parse("http://example.org/feed.xml", bytes.NewReader([]byte(data)), "10")
if err != nil {
t.Fatal(err)
}
if feed.Description != "This is a subtitle" {
t.Errorf("Incorrect description, got: %s", feed.Description)
}
}
func TestParseFeedWithoutTitle(t *testing.T) { func TestParseFeedWithoutTitle(t *testing.T) {
data := `<?xml version="1.0" encoding="utf-8"?> data := `<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"> <feed xmlns="http://www.w3.org/2005/Atom">

View file

@ -29,6 +29,7 @@ func (j *JSONAdapter) BuildFeed(baseURL string) *model.Feed {
Title: strings.TrimSpace(j.jsonFeed.Title), Title: strings.TrimSpace(j.jsonFeed.Title),
FeedURL: strings.TrimSpace(j.jsonFeed.FeedURL), FeedURL: strings.TrimSpace(j.jsonFeed.FeedURL),
SiteURL: strings.TrimSpace(j.jsonFeed.HomePageURL), SiteURL: strings.TrimSpace(j.jsonFeed.HomePageURL),
Description: strings.TrimSpace(j.jsonFeed.Description),
} }
if feed.FeedURL == "" { if feed.FeedURL == "" {

View file

@ -41,6 +41,10 @@ func TestParseJsonFeedVersion1(t *testing.T) {
t.Errorf("Incorrect title, got: %s", feed.Title) t.Errorf("Incorrect title, got: %s", feed.Title)
} }
if feed.Description != "" {
t.Errorf("Incorrect description, got: %s", feed.Description)
}
if feed.FeedURL != "https://example.org/feed.json" { if feed.FeedURL != "https://example.org/feed.json" {
t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL) t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
} }
@ -90,6 +94,26 @@ func TestParseJsonFeedVersion1(t *testing.T) {
} }
} }
func TestParseFeedWithDescription(t *testing.T) {
data := `{
"version": "https://jsonfeed.org/version/1",
"title": "My Example Feed",
"description": "This is a sample feed description.",
"home_page_url": "https://example.org/",
"feed_url": "https://example.org/feed.json",
"items": []
}`
feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
if feed.Description != "This is a sample feed description." {
t.Errorf("Incorrect description, got: %s", feed.Description)
}
}
func TestParsePodcast(t *testing.T) { func TestParsePodcast(t *testing.T) {
data := `{ data := `{
"version": "https://jsonfeed.org/version/1", "version": "https://jsonfeed.org/version/1",

View file

@ -29,6 +29,7 @@ func (r *RDFAdapter) BuildFeed(baseURL string) *model.Feed {
Title: stripTags(r.rdf.Channel.Title), Title: stripTags(r.rdf.Channel.Title),
FeedURL: strings.TrimSpace(baseURL), FeedURL: strings.TrimSpace(baseURL),
SiteURL: strings.TrimSpace(r.rdf.Channel.Link), SiteURL: strings.TrimSpace(r.rdf.Channel.Link),
Description: strings.TrimSpace(r.rdf.Channel.Description),
} }
if feed.Title == "" { if feed.Title == "" {

View file

@ -23,8 +23,7 @@ func TestParseRDFSample(t *testing.T) {
<title>XML.com</title> <title>XML.com</title>
<link>http://xml.com/pub</link> <link>http://xml.com/pub</link>
<description> <description>
XML.com features a rich mix of information and services XML.com features a rich mix of information and services for the XML community.
for the XML community.
</description> </description>
<image rdf:resource="http://xml.com/universal/images/xml_tiny.gif" /> <image rdf:resource="http://xml.com/universal/images/xml_tiny.gif" />
@ -84,6 +83,10 @@ func TestParseRDFSample(t *testing.T) {
t.Errorf("Incorrect title, got: %s", feed.Title) t.Errorf("Incorrect title, got: %s", feed.Title)
} }
if feed.Description != "XML.com features a rich mix of information and services for the XML community." {
t.Errorf("Incorrect description, got: %s", feed.Description)
}
if feed.FeedURL != "http://xml.com/pub/rdf.xml" { if feed.FeedURL != "http://xml.com/pub/rdf.xml" {
t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL) t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
} }

View file

@ -31,6 +31,7 @@ func (r *RSSAdapter) BuildFeed(baseURL string) *model.Feed {
Title: html.UnescapeString(strings.TrimSpace(r.rss.Channel.Title)), Title: html.UnescapeString(strings.TrimSpace(r.rss.Channel.Title)),
FeedURL: strings.TrimSpace(baseURL), FeedURL: strings.TrimSpace(baseURL),
SiteURL: strings.TrimSpace(r.rss.Channel.Link), SiteURL: strings.TrimSpace(r.rss.Channel.Link),
Description: strings.TrimSpace(r.rss.Channel.Description),
} }
// Ensure the Site URL is absolute. // Ensure the Site URL is absolute.

View file

@ -67,6 +67,10 @@ func TestParseRss2Sample(t *testing.T) {
t.Errorf("Incorrect title, got: %s", feed.Title) t.Errorf("Incorrect title, got: %s", feed.Title)
} }
if feed.Description != "Liftoff to Space Exploration." {
t.Errorf("Incorrect description, got: %s", feed.Description)
}
if feed.FeedURL != "http://liftoff.msfc.nasa.gov/rss.xml" { if feed.FeedURL != "http://liftoff.msfc.nasa.gov/rss.xml" {
t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL) t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
} }
@ -237,6 +241,14 @@ func TestParseEntryWithoutTitleAndDescription(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if feed.Description != "" {
t.Errorf("Expected empty feed description, got: %s", feed.Description)
}
if len(feed.Entries) != 1 {
t.Errorf("Expected 1 entry, got: %d", len(feed.Entries))
}
if feed.Entries[0].Title != "https://example.org/item" { if feed.Entries[0].Title != "https://example.org/item" {
t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title) t.Errorf("Incorrect entry title, got: %s", feed.Entries[0].Title)
} }