diff --git a/reader/atom/atom_10.go b/reader/atom/atom_10.go index 53230708..4e49a8d4 100644 --- a/reader/atom/atom_10.go +++ b/reader/atom/atom_10.go @@ -161,6 +161,10 @@ func (a *atom10Entry) entryEnclosures() model.EnclosureList { for _, link := range a.Links { if strings.ToLower(link.Rel) == "enclosure" { + if link.URL == "" { + continue + } + if _, found := duplicates[link.URL]; !found { duplicates[link.URL] = true length, _ := strconv.ParseInt(link.Length, 10, 0) diff --git a/reader/atom/atom_10_test.go b/reader/atom/atom_10_test.go index 3129e292..1e763ca4 100644 --- a/reader/atom/atom_10_test.go +++ b/reader/atom/atom_10_test.go @@ -503,6 +503,43 @@ func TestParseEntryWithEnclosures(t *testing.T) { } } +func TestParseEntryWithoutEnclosureURL(t *testing.T) { + data := ` + + http://www.example.org/myfeed + My Podcast Feed + 2005-07-15T12:00:00Z + + + + http://www.example.org/entries/1 + Atom 1.0 + 2005-07-15T12:00:00Z + + An overview of Atom 1.0 + + Test + + ` + + 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 len(feed.Entries[0].Enclosures) != 0 { + t.Fatalf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures)) + } +} + func TestParseEntryWithPublished(t *testing.T) { data := ` diff --git a/reader/json/json.go b/reader/json/json.go index af059f07..5eca5e34 100644 --- a/reader/json/json.go +++ b/reader/json/json.go @@ -136,6 +136,10 @@ func (j *jsonItem) GetEnclosures() model.EnclosureList { enclosures := make(model.EnclosureList, 0) for _, attachment := range j.Attachments { + if attachment.URL == "" { + continue + } + enclosures = append(enclosures, &model.Enclosure{ URL: attachment.URL, MimeType: attachment.MimeType, diff --git a/reader/json/parser_test.go b/reader/json/parser_test.go index d55eb922..191423a0 100644 --- a/reader/json/parser_test.go +++ b/reader/json/parser_test.go @@ -33,7 +33,7 @@ func TestParseJsonFeed(t *testing.T) { feed, err := Parse(bytes.NewBufferString(data)) if err != nil { - t.Error(err) + t.Fatal(err) } if feed.Title != "My Example Feed" { @@ -115,7 +115,7 @@ func TestParsePodcast(t *testing.T) { feed, err := Parse(bytes.NewBufferString(data)) if err != nil { - t.Error(err) + t.Fatal(err) } if feed.Title != "The Record" { @@ -131,7 +131,7 @@ func TestParsePodcast(t *testing.T) { } if len(feed.Entries) != 1 { - t.Errorf("Incorrect number of entries, got: %d", len(feed.Entries)) + t.Fatalf("Incorrect number of entries, got: %d", len(feed.Entries)) } if feed.Entries[0].Hash != "6b678e57962a1b001e4e873756563cdc08bbd06ca561e764e0baa9a382485797" { @@ -156,7 +156,7 @@ func TestParsePodcast(t *testing.T) { } if len(feed.Entries[0].Enclosures) != 1 { - 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://therecord.co/downloads/The-Record-sp1e1-ChrisParrish.m4a" { @@ -172,6 +172,45 @@ func TestParsePodcast(t *testing.T) { } } +func TestParseEntryWithoutAttachmentURL(t *testing.T) { + data := `{ + "version": "https://jsonfeed.org/version/1", + "user_comment": "This is a podcast feed. You can add this feed to your podcast client using the following URL: http://therecord.co/feed.json", + "title": "The Record", + "home_page_url": "http://therecord.co/", + "feed_url": "http://therecord.co/feed.json", + "items": [ + { + "id": "http://therecord.co/chris-parrish", + "title": "Special #1 - Chris Parrish", + "url": "http://therecord.co/chris-parrish", + "content_text": "Chris has worked at Adobe and as a founder of Rogue Sheep, which won an Apple Design Award for Postage. Chris’s new company is Aged & Distilled with Guy English — which shipped Napkin, a Mac app for visual collaboration. Chris is also the co-host of The Record. He lives on Bainbridge Island, a quick ferry ride from Seattle.", + "date_published": "2014-05-09T14:04:00-07:00", + "attachments": [ + { + "url": "", + "mime_type": "audio/x-m4a", + "size_in_bytes": 0 + } + ] + } + ] + }` + + feed, err := Parse(bytes.NewBufferString(data)) + if err != nil { + t.Fatal(err) + } + + if len(feed.Entries) != 1 { + t.Fatalf("Incorrect number of entries, got: %d", len(feed.Entries)) + } + + if len(feed.Entries[0].Enclosures) != 0 { + t.Errorf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures)) + } +} + func TestParseFeedWithRelativeURL(t *testing.T) { data := `{ "version": "https://jsonfeed.org/version/1", @@ -189,7 +228,7 @@ func TestParseFeedWithRelativeURL(t *testing.T) { feed, err := Parse(bytes.NewBufferString(data)) if err != nil { - t.Error(err) + t.Fatal(err) } if feed.Entries[0].URL != "https://example.org/something.html" { @@ -221,7 +260,7 @@ func TestParseAuthor(t *testing.T) { feed, err := Parse(bytes.NewBufferString(data)) if err != nil { - t.Error(err) + t.Fatal(err) } if len(feed.Entries) != 1 { @@ -250,7 +289,7 @@ func TestParseFeedWithoutTitle(t *testing.T) { feed, err := Parse(bytes.NewBufferString(data)) if err != nil { - t.Error(err) + t.Fatal(err) } if feed.Title != "https://example.org/" { @@ -276,7 +315,7 @@ func TestParseFeedItemWithInvalidDate(t *testing.T) { feed, err := Parse(bytes.NewBufferString(data)) if err != nil { - t.Error(err) + t.Fatal(err) } if len(feed.Entries) != 1 { @@ -304,7 +343,7 @@ func TestParseFeedItemWithoutID(t *testing.T) { feed, err := Parse(bytes.NewBufferString(data)) if err != nil { - t.Error(err) + t.Fatal(err) } if len(feed.Entries) != 1 { @@ -331,7 +370,7 @@ func TestParseFeedItemWithoutTitle(t *testing.T) { feed, err := Parse(bytes.NewBufferString(data)) if err != nil { - t.Error(err) + t.Fatal(err) } if len(feed.Entries) != 1 { @@ -358,7 +397,7 @@ func TestParseTruncateItemTitle(t *testing.T) { feed, err := Parse(bytes.NewBufferString(data)) if err != nil { - t.Error(err) + t.Fatal(err) } if len(feed.Entries) != 1 { diff --git a/reader/rss/parser_test.go b/reader/rss/parser_test.go index b7ebd0a4..e41eec88 100644 --- a/reader/rss/parser_test.go +++ b/reader/rss/parser_test.go @@ -741,6 +741,42 @@ func TestParseEntryWithEnclosures(t *testing.T) { } } +func TestParseEntryWithEmptyEnclosureURL(t *testing.T) { + data := ` + + + My Podcast Feed + http://example.org + some.email@example.org + + Podcasting with RSS + http://www.example.org/entries/1 + An overview of RSS podcasting + Fri, 15 Jul 2005 00:00:00 -0500 + http://www.example.org/entries/1 + + + + ` + + 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 len(feed.Entries[0].Enclosures) != 0 { + t.Errorf("Incorrect number of enclosures, got: %d", len(feed.Entries[0].Enclosures)) + } +} + func TestParseEntryWithFeedBurnerEnclosures(t *testing.T) { data := ` diff --git a/reader/rss/rss.go b/reader/rss/rss.go index 172f6f89..3619ec68 100644 --- a/reader/rss/rss.go +++ b/reader/rss/rss.go @@ -278,6 +278,10 @@ func (r *rssItem) entryEnclosures() model.EnclosureList { } } + if enclosureURL == "" { + continue + } + if _, found := duplicates[enclosureURL]; !found { duplicates[enclosureURL] = true diff --git a/storage/enclosure.go b/storage/enclosure.go index 6684c781..785e2dd2 100644 --- a/storage/enclosure.go +++ b/storage/enclosure.go @@ -57,6 +57,10 @@ func (s *Storage) GetEnclosures(entryID int64) (model.EnclosureList, error) { // CreateEnclosure creates a new attachment. func (s *Storage) CreateEnclosure(enclosure *model.Enclosure) error { + if enclosure.URL == "" { + return nil + } + query := ` INSERT INTO enclosures (url, size, mime_type, entry_id, user_id) diff --git a/template/html/entry.html b/template/html/entry.html index 83215b5f..f9872d9f 100644 --- a/template/html/entry.html +++ b/template/html/entry.html @@ -95,6 +95,7 @@
{{ t "page.entry.attachments" }} ({{ len .entry.Enclosures }}) {{ range .entry.Enclosures }} + {{ if ne .URL "" }}
{{ if hasPrefix .MimeType "audio/" }}
@@ -119,6 +120,7 @@ {{ if gt .Size 0 }} - {{ formatFileSize .Size }}{{ end }}
+ {{ end }} {{ end }}
{{ end }} diff --git a/template/views.go b/template/views.go index b19da6cf..6d495bf5 100644 --- a/template/views.go +++ b/template/views.go @@ -645,6 +645,7 @@ var templateViewsMap = map[string]string{
{{ t "page.entry.attachments" }} ({{ len .entry.Enclosures }}) {{ range .entry.Enclosures }} + {{ if ne .URL "" }}
{{ if hasPrefix .MimeType "audio/" }}
@@ -669,6 +670,7 @@ var templateViewsMap = map[string]string{ {{ if gt .Size 0 }} - {{ formatFileSize .Size }}{{ end }}
+ {{ end }} {{ end }}
{{ end }} @@ -1316,7 +1318,7 @@ var templateViewsMapChecksums = map[string]string{ "edit_category": "b1c0b38f1b714c5d884edcd61e5b5295a5f1c8b71c469b35391e4dcc97cc6d36", "edit_feed": "cc0b5dbb73f81398410958b41771ed38246bc7ae4bd548228f0d48c49a598c2a", "edit_user": "c692db9de1a084c57b93e95a14b041d39bf489846cbb91fc982a62b72b77062a", - "entry": "9aac76b1cfa80428f136edf292f8610b14289ca9595d725c1365bc0a2847a21d", + "entry": "513183f0f0b11a199630562f5a85eb9a5646051aae278cbc682bac13d62e65cc", "feed_entries": "9c70b82f55e4b311eff20be1641733612e3c1b406ce8010861e4c417d97b6dcc", "feeds": "ec7d3fa96735bd8422ba69ef0927dcccddc1cc51327e0271f0312d3f881c64fd", "history_entries": "87e17d39de70eb3fdbc4000326283be610928758eae7924e4b08dcb446f3b6a9",