diff options
author | Frédéric Guillot <fred@miniflux.net> | 2019-11-28 23:47:53 -0800 |
---|---|---|
committer | Frédéric Guillot <fred@miniflux.net> | 2019-11-28 23:55:40 -0800 |
commit | 912a98788e66b836125fe8ef37672a4de20c169c (patch) | |
tree | 857e4c57695139ee07193223beae7d04775e3347 /reader/atom | |
parent | f90e9dfab015a2ebdbbe66334a29477152a948f5 (diff) |
Add support of media elements for Atom feeds
Diffstat (limited to 'reader/atom')
-rw-r--r-- | reader/atom/atom.go | 69 | ||||
-rw-r--r-- | reader/atom/parser_test.go | 171 |
2 files changed, 204 insertions, 36 deletions
diff --git a/reader/atom/atom.go b/reader/atom/atom.go index 30297e5..517b43d 100644 --- a/reader/atom/atom.go +++ b/reader/atom/atom.go @@ -15,6 +15,7 @@ import ( "miniflux.app/logger" "miniflux.app/model" "miniflux.app/reader/date" + "miniflux.app/reader/media" "miniflux.app/reader/sanitizer" "miniflux.app/url" ) @@ -29,15 +30,15 @@ type atomFeed struct { } type atomEntry struct { - ID string `xml:"id"` - Title atomContent `xml:"title"` - Published string `xml:"published"` - Updated string `xml:"updated"` - Links []atomLink `xml:"link"` - Summary atomContent `xml:"summary"` - Content atomContent `xml:"content"` - MediaGroup atomMediaGroup `xml:"http://search.yahoo.com/mrss/ group"` - Author atomAuthor `xml:"author"` + ID string `xml:"id"` + Title atomContent `xml:"title"` + Published string `xml:"published"` + Updated string `xml:"updated"` + Links []atomLink `xml:"link"` + Summary atomContent `xml:"summary"` + Content atomContent `xml:"http://www.w3.org/2005/Atom content"` + Author atomAuthor `xml:"author"` + media.Element } type atomAuthor struct { @@ -58,10 +59,6 @@ type atomContent struct { XML string `xml:",innerxml"` } -type atomMediaGroup struct { - Description string `xml:"http://search.yahoo.com/mrss/ description"` -} - func (a *atomFeed) Transform() *model.Feed { feed := new(model.Feed) feed.FeedURL = getRelationURL(a.Links, "self") @@ -179,8 +176,9 @@ func getContent(a *atomEntry) string { return r } - if a.MediaGroup.Description != "" { - return a.MediaGroup.Description + mediaDescription := a.FirstMediaDescription() + if mediaDescription != "" { + return mediaDescription } return "" @@ -203,11 +201,48 @@ func getHash(a *atomEntry) string { func getEnclosures(a *atomEntry) model.EnclosureList { enclosures := make(model.EnclosureList, 0) + duplicates := make(map[string]bool, 0) + + for _, mediaThumbnail := range a.AllMediaThumbnails() { + if _, found := duplicates[mediaThumbnail.URL]; !found { + duplicates[mediaThumbnail.URL] = true + enclosures = append(enclosures, &model.Enclosure{ + URL: mediaThumbnail.URL, + MimeType: mediaThumbnail.MimeType(), + Size: mediaThumbnail.Size(), + }) + } + } for _, link := range a.Links { if strings.ToLower(link.Rel) == "enclosure" { - length, _ := strconv.ParseInt(link.Length, 10, 0) - enclosures = append(enclosures, &model.Enclosure{URL: link.URL, MimeType: link.Type, Size: length}) + if _, found := duplicates[link.URL]; !found { + duplicates[link.URL] = true + length, _ := strconv.ParseInt(link.Length, 10, 0) + enclosures = append(enclosures, &model.Enclosure{URL: link.URL, MimeType: link.Type, Size: length}) + } + } + } + + for _, mediaContent := range a.AllMediaContents() { + if _, found := duplicates[mediaContent.URL]; !found { + duplicates[mediaContent.URL] = true + enclosures = append(enclosures, &model.Enclosure{ + URL: mediaContent.URL, + MimeType: mediaContent.MimeType(), + Size: mediaContent.Size(), + }) + } + } + + for _, mediaPeerLink := range a.AllMediaPeerLinks() { + if _, found := duplicates[mediaPeerLink.URL]; !found { + duplicates[mediaPeerLink.URL] = true + enclosures = append(enclosures, &model.Enclosure{ + URL: mediaPeerLink.URL, + MimeType: mediaPeerLink.MimeType(), + Size: mediaPeerLink.Size(), + }) } } diff --git a/reader/atom/parser_test.go b/reader/atom/parser_test.go index 746c767..37ab32e 100644 --- a/reader/atom/parser_test.go +++ b/reader/atom/parser_test.go @@ -472,31 +472,30 @@ func TestParseEntryWithEnclosures(t *testing.T) { } if len(feed.Entries[0].Enclosures) != 2 { - t.Errorf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures)) + t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures)) } - if feed.Entries[0].Enclosures[0].URL != "http://www.example.org/myaudiofile.mp3" { - t.Errorf("Incorrect enclosure URL, got: %s", feed.Entries[0].Enclosures[0].URL) + expectedResults := []struct { + url string + mimeType string + size int64 + }{ + {"http://www.example.org/myaudiofile.mp3", "audio/mpeg", 1234}, + {"http://www.example.org/myaudiofile.torrent", "application/x-bittorrent", 4567}, } - if feed.Entries[0].Enclosures[0].MimeType != "audio/mpeg" { - t.Errorf("Incorrect enclosure type, got: %s", feed.Entries[0].Enclosures[0].MimeType) - } - - if feed.Entries[0].Enclosures[0].Size != 1234 { - t.Errorf("Incorrect enclosure length, got: %d", feed.Entries[0].Enclosures[0].Size) - } - - if feed.Entries[0].Enclosures[1].URL != "http://www.example.org/myaudiofile.torrent" { - t.Errorf("Incorrect enclosure URL, got: %s", feed.Entries[0].Enclosures[1].URL) - } + for index, enclosure := range feed.Entries[0].Enclosures { + if expectedResults[index].url != enclosure.URL { + t.Errorf(`Unexpected enclosure URL, got %q instead of %q`, enclosure.URL, expectedResults[index].url) + } - if feed.Entries[0].Enclosures[1].MimeType != "application/x-bittorrent" { - t.Errorf("Incorrect enclosure type, got: %s", feed.Entries[0].Enclosures[1].MimeType) - } + if expectedResults[index].mimeType != enclosure.MimeType { + t.Errorf(`Unexpected enclosure type, got %q instead of %q`, enclosure.MimeType, expectedResults[index].mimeType) + } - if feed.Entries[0].Enclosures[1].Size != 4567 { - t.Errorf("Incorrect enclosure length, got: %d", feed.Entries[0].Enclosures[1].Size) + if expectedResults[index].size != enclosure.Size { + t.Errorf(`Unexpected enclosure size, got %d instead of %d`, enclosure.Size, expectedResults[index].size) + } } } @@ -596,3 +595,137 @@ func TestParseWithInvalidCharacterEntity(t *testing.T) { t.Errorf(`Incorrect URL, got: %q`, feed.SiteURL) } } + +func TestParseMediaGroup(t *testing.T) { + data := `<?xml version="1.0" encoding="utf-8"?> + <feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"> + <id>http://www.example.org/myfeed</id> + <title>My Video Feed</title> + <updated>2005-07-15T12:00:00Z</updated> + <link href="http://example.org" /> + <link rel="self" href="http://example.org/myfeed" /> + <entry> + <id>http://www.example.org/entries/1</id> + <title>Some Video</title> + <updated>2005-07-15T12:00:00Z</updated> + <link href="http://www.example.org/entries/1" /> + <media:group> + <media:title>Another title</media:title> + <media:content url="https://www.youtube.com/v/abcd" type="application/x-shockwave-flash" width="640" height="390"/> + <media:thumbnail url="https://example.org/thumbnail.jpg" width="480" height="360"/> + <media:description>Some description +A website: http://example.org/</media:description> + </media:group> + </entry> + </feed>` + + feed, err := Parse(bytes.NewBufferString(data)) + if err != nil { + t.Fatal(err) + } + + if len(feed.Entries) != 1 { + t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries)) + } + + if feed.Entries[0].URL != "http://www.example.org/entries/1" { + t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL) + } + + if feed.Entries[0].Content != `Some description<br>A website: <a href="http://example.org/">http://example.org/</a>` { + t.Errorf("Incorrect entry content, got: %q", feed.Entries[0].Content) + } + + if len(feed.Entries[0].Enclosures) != 2 { + t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures)) + } + + expectedResults := []struct { + url string + mimeType string + size int64 + }{ + {"https://example.org/thumbnail.jpg", "image/*", 0}, + {"https://www.youtube.com/v/abcd", "application/x-shockwave-flash", 0}, + } + + for index, enclosure := range feed.Entries[0].Enclosures { + if expectedResults[index].url != enclosure.URL { + t.Errorf(`Unexpected enclosure URL, got %q instead of %q`, enclosure.URL, expectedResults[index].url) + } + + if expectedResults[index].mimeType != enclosure.MimeType { + t.Errorf(`Unexpected enclosure type, got %q instead of %q`, enclosure.MimeType, expectedResults[index].mimeType) + } + + if expectedResults[index].size != enclosure.Size { + t.Errorf(`Unexpected enclosure size, got %d instead of %d`, enclosure.Size, expectedResults[index].size) + } + } +} + +func TestParseMediaElements(t *testing.T) { + data := `<?xml version="1.0" encoding="utf-8"?> + <feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"> + <id>http://www.example.org/myfeed</id> + <title>My Video Feed</title> + <updated>2005-07-15T12:00:00Z</updated> + <link href="http://example.org" /> + <link rel="self" href="http://example.org/myfeed" /> + <entry> + <id>http://www.example.org/entries/1</id> + <title>Some Video</title> + <updated>2005-07-15T12:00:00Z</updated> + <link href="http://www.example.org/entries/1" /> + <media:title>Another title</media:title> + <media:content url="https://www.youtube.com/v/abcd" type="application/x-shockwave-flash" width="640" height="390"/> + <media:thumbnail url="https://example.org/thumbnail.jpg" width="480" height="360"/> + <media:description>Some description +A website: http://example.org/</media:description> + </entry> + </feed>` + + feed, err := Parse(bytes.NewBufferString(data)) + if err != nil { + t.Fatal(err) + } + + if len(feed.Entries) != 1 { + t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries)) + } + + if feed.Entries[0].URL != "http://www.example.org/entries/1" { + t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL) + } + + if feed.Entries[0].Content != `Some description<br>A website: <a href="http://example.org/">http://example.org/</a>` { + t.Errorf("Incorrect entry content, got: %q", feed.Entries[0].Content) + } + + if len(feed.Entries[0].Enclosures) != 2 { + t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures)) + } + + expectedResults := []struct { + url string + mimeType string + size int64 + }{ + {"https://example.org/thumbnail.jpg", "image/*", 0}, + {"https://www.youtube.com/v/abcd", "application/x-shockwave-flash", 0}, + } + + for index, enclosure := range feed.Entries[0].Enclosures { + if expectedResults[index].url != enclosure.URL { + t.Errorf(`Unexpected enclosure URL, got %q instead of %q`, enclosure.URL, expectedResults[index].url) + } + + if expectedResults[index].mimeType != enclosure.MimeType { + t.Errorf(`Unexpected enclosure type, got %q instead of %q`, enclosure.MimeType, expectedResults[index].mimeType) + } + + if expectedResults[index].size != enclosure.Size { + t.Errorf(`Unexpected enclosure size, got %d instead of %d`, enclosure.Size, expectedResults[index].size) + } + } +} |