Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## gorilla/feeds
[![GoDoc](https://godoc.org/github.com/gorilla/feeds?status.svg)](https://godoc.org/github.com/gorilla/feeds) [![Build Status](https://travis-ci.org/gorilla/feeds.png?branch=master)](https://travis-ci.org/gorilla/feeds)
[![GoDoc](https://godoc.org/github.com/gorilla/feeds?status.svg)](https://godoc.org/github.com/gorilla/feeds)

feeds is a web feed generator library for generating RSS, Atom and JSON feeds from Go
applications.
Expand Down
17 changes: 9 additions & 8 deletions atom.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"encoding/xml"
"fmt"
"net/url"
"strconv"
"time"
)

Expand Down Expand Up @@ -52,11 +51,12 @@ type AtomEntry struct {
Source string `xml:"source,omitempty"`
Published string `xml:"published,omitempty"`
Contributor *AtomContributor
Link *AtomLink // required if no child 'content' elements
Links []AtomLink // required if no child 'content' elements
Summary *AtomSummary // required if content has src or content is base64
Author *AtomAuthor // required if feed lacks an author
}

// Multiple links with different rel can coexist
type AtomLink struct {
//Atom 1.0 <link rel="enclosure" type="audio/mpeg" title="MP3" href="http://www.example.org/myaudiofile.mp3" length="1234" />
XMLName xml.Name `xml:"link"`
Expand Down Expand Up @@ -110,19 +110,20 @@ func newAtomEntry(i *Item) *AtomEntry {
name, email = i.Author.Name, i.Author.Email
}

link_rel := i.Link.Rel
if link_rel == "" {
link_rel = "alternate"
}
x := &AtomEntry{
Title: i.Title,
Link: &AtomLink{Href: i.Link.Href, Rel: i.Link.Rel, Type: i.Link.Type},
Links: []AtomLink{{Href: i.Link.Href, Rel: link_rel, Type: i.Link.Type}},
Content: c,
Id: id,
Updated: anyTimeFormat(time.RFC3339, i.Updated, i.Created),
}

intLength, err := strconv.ParseInt(i.Link.Length, 10, 64)

if err == nil && (intLength > 0 || i.Link.Type != "") {
i.Link.Rel = "enclosure"
x.Link = &AtomLink{Href: i.Link.Href, Rel: i.Link.Rel, Type: i.Link.Type, Length: i.Link.Length}
if i.Enclosure != nil && link_rel != "enclosure" {
x.Links = append(x.Links, AtomLink{Href: i.Enclosure.Url, Rel: "enclosure", Type: i.Enclosure.Type, Length: i.Enclosure.Length})
}

if len(name) > 0 || len(email) > 0 {
Expand Down
11 changes: 11 additions & 0 deletions feed.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ type Author struct {
Name, Email string
}

type Image struct {
Url, Title, Link string
Width, Height int
}

type Enclosure struct {
Url, Length, Type string
}

type Item struct {
Title string
Link *Link
Expand All @@ -24,6 +33,7 @@ type Item struct {
Id string // used as guid in rss, id in atom
Updated time.Time
Created time.Time
Enclosure *Enclosure
}

type Feed struct {
Expand All @@ -37,6 +47,7 @@ type Feed struct {
Subtitle string
Items []*Item
Copyright string
Image *Image
}

// add a new Item to a Feed
Expand Down
16 changes: 11 additions & 5 deletions feed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var atomOutput = `<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.
<updated>2013-01-16T21:52:35-05:00</updated>
<id>tag:jmoiron.net,2013-01-16:/blog/limiting-concurrency-in-go/</id>
<content type="html">A discussion on controlled parallelism in golang</content>
<link href="http://jmoiron.net/blog/limiting-concurrency-in-go/"></link>
<link href="http://jmoiron.net/blog/limiting-concurrency-in-go/" rel="alternate"></link>
<author>
<name>Jason Moiron</name>
<email>jmoiron@jmoiron.net</email>
Expand All @@ -33,28 +33,30 @@ var atomOutput = `<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.
<updated>2013-01-16T21:52:35-05:00</updated>
<id>tag:jmoiron.net,2013-01-16:/blog/logicless-template-redux/</id>
<content type="html">More thoughts on logicless templates</content>
<link href="http://jmoiron.net/blog/logicless-template-redux/"></link>
<link href="http://jmoiron.net/blog/logicless-template-redux/" rel="alternate"></link>
</entry>
<entry>
<title>Idiomatic Code Reuse in Go</title>
<updated>2013-01-16T21:52:35-05:00</updated>
<id>tag:jmoiron.net,2013-01-16:/blog/idiomatic-code-reuse-in-go/</id>
<content type="html">How to use interfaces &lt;em&gt;effectively&lt;/em&gt;</content>
<link href="http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"></link>
<link href="http://jmoiron.net/blog/idiomatic-code-reuse-in-go/" rel="alternate"></link>
<link href="http://example.com/cover.jpg" rel="enclosure" type="image/jpg" length="123456"></link>
</entry>
<entry>
<title>Never Gonna Give You Up Mp3</title>
<updated>2013-01-16T21:52:35-05:00</updated>
<id>tag:example.com,2013-01-16:/RickRoll.mp3</id>
<content type="html">Never gonna give you up - Never gonna let you down.</content>
<link href="http://example.com/RickRoll.mp3" rel="alternate"></link>
<link href="http://example.com/RickRoll.mp3" rel="enclosure" type="audio/mpeg" length="123456"></link>
</entry>
<entry>
<title>String formatting in Go</title>
<updated>2013-01-16T21:52:35-05:00</updated>
<id>tag:example.com,2013-01-16:/strings</id>
<content type="html">How to use things like %s, %v, %d, etc.</content>
<link href="http://example.com/strings"></link>
<link href="http://example.com/strings" rel="alternate"></link>
</entry>
</feed>`

Expand Down Expand Up @@ -83,6 +85,7 @@ var rssOutput = `<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">
<title>Idiomatic Code Reuse in Go</title>
<link>http://jmoiron.net/blog/idiomatic-code-reuse-in-go/</link>
<description>How to use interfaces &lt;em&gt;effectively&lt;/em&gt;</description>
<enclosure url="http://example.com/cover.jpg" length="123456" type="image/jpg"></enclosure>
<pubDate>Wed, 16 Jan 2013 21:52:35 -0500</pubDate>
</item>
<item>
Expand Down Expand Up @@ -132,6 +135,7 @@ var jsonOutput = `{
"url": "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/",
"title": "Idiomatic Code Reuse in Go",
"summary": "How to use interfaces \u003cem\u003eeffectively\u003c/em\u003e",
"image": "http://example.com/cover.jpg",
"date_published": "2013-01-16T21:52:35-05:00"
},
{
Expand Down Expand Up @@ -186,11 +190,13 @@ func TestFeed(t *testing.T) {
Title: "Idiomatic Code Reuse in Go",
Link: &Link{Href: "http://jmoiron.net/blog/idiomatic-code-reuse-in-go/"},
Description: "How to use interfaces <em>effectively</em>",
Enclosure: &Enclosure{Url: "http://example.com/cover.jpg", Length: "123456", Type: "image/jpg"},
Created: now,
},
{
Title: "Never Gonna Give You Up Mp3",
Link: &Link{Href: "http://example.com/RickRoll.mp3", Length: "123456", Type: "audio/mpeg"},
Link: &Link{Href: "http://example.com/RickRoll.mp3"},
Enclosure: &Enclosure{Url: "http://example.com/RickRoll.mp3", Length: "123456", Type: "audio/mpeg"},
Description: "Never gonna give you up - Never gonna let you down.",
Created: now,
},
Expand Down
4 changes: 4 additions & 0 deletions json.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package feeds

import (
"encoding/json"
"strings"
"time"
)

Expand Down Expand Up @@ -172,6 +173,9 @@ func newJSONItem(i *Item) *JSONItem {
if !i.Updated.IsZero() {
item.ModifiedDate = &i.Created
}
if i.Enclosure != nil && strings.HasPrefix(i.Enclosure.Type, "image/") {
item.Image = i.Enclosure.Url
}

return item
}
15 changes: 10 additions & 5 deletions rss.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package feeds
import (
"encoding/xml"
"fmt"
"strconv"
"time"
)

Expand Down Expand Up @@ -98,11 +97,11 @@ func newRssItem(i *Item) *RssItem {
item.Source = i.Source.Href
}

intLength, err := strconv.ParseInt(i.Link.Length, 10, 64)

if err == nil && (intLength > 0 || i.Link.Type != "") {
item.Enclosure = &RssEnclosure{Url: i.Link.Href, Type: i.Link.Type, Length: i.Link.Length}
// Define a closure
if i.Enclosure != nil && i.Enclosure.Type != "" && i.Enclosure.Length != "" {
item.Enclosure = &RssEnclosure{Url: i.Enclosure.Url, Type: i.Enclosure.Type, Length: i.Enclosure.Length}
}

if i.Author != nil {
item.Author = i.Author.Name
}
Expand All @@ -121,6 +120,11 @@ func (r *Rss) RssFeed() *RssFeed {
}
}

var image *RssImage
if r.Image != nil {
image = &RssImage{Url: r.Image.Url, Title: r.Image.Title, Link: r.Image.Link, Width: r.Image.Width, Height: r.Image.Height}
}

channel := &RssFeed{
Title: r.Title,
Link: r.Link.Href,
Expand All @@ -129,6 +133,7 @@ func (r *Rss) RssFeed() *RssFeed {
PubDate: pub,
LastBuildDate: build,
Copyright: r.Copyright,
Image: image,
}
for _, i := range r.Items {
channel.Items = append(channel.Items, newRssItem(i))
Expand Down
20 changes: 20 additions & 0 deletions to-implement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[Full iTunes list](https://help.apple.com/itc/podcasts_connect/#/itcb54353390)

[Example of ideal iTunes RSS feed](https://help.apple.com/itc/podcasts_connect/#/itcbaf351599)

```
<itunes:author>
<itunes:block>
<itunes:catergory>
<itunes:image>
<itunes:duration>
<itunes:explicit>
<itunes:isClosedCaptioned>
<itunes:order>
<itunes:complete>
<itunes:new-feed-url>
<itunes:owner>
<itunes:subtitle>
<itunes:summary>
<language>
```