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",