Skip to content

Commit 7b639e9

Browse files
committed
initial rss 2.0 support
1 parent cc91ea6 commit 7b639e9

File tree

6 files changed

+139
-44
lines changed

6 files changed

+139
-44
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ Usage:
44

55
```golang
66

7+
import "syndicate"
8+
79
```
810

atom.go

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,55 +11,50 @@ import (
1111

1212
const ns = "http://www.w3.org/2005/Atom"
1313

14-
type atomSummary struct {
14+
type AtomSummary struct {
1515
S string `xml:",chardata"`
1616
Type string `xml:"type,attr"`
1717
}
1818

19-
type atomEntry struct {
19+
type AtomEntry struct {
2020
XMLName xml.Name `xml:"entry"`
2121
Title string `xml:"title"`
22-
Link *atomLink
22+
Link *AtomLink
2323
Updated string `xml:"updated"`
2424
Id string `xml:"id"`
25-
Summary *atomSummary `xml:"summary"`
25+
Summary *AtomSummary `xml:"summary,omitempty"`
2626
}
2727

28-
type atomLink struct {
28+
type AtomLink struct {
2929
XMLName xml.Name `xml:"link"`
3030
Href string `xml:"href,attr"`
31-
Rel string `xml:"rel,attr"`
31+
Rel string `xml:"rel,attr,omitempty"`
3232
}
3333

34-
type atomFeed struct {
34+
type AtomFeed struct {
3535
XMLName xml.Name `xml:"feed"`
3636
Ns string `xml:"xmlns,attr"`
3737
Title string `xml:"title"`
38-
Link *atomLink
39-
Id string `xml:"id"`
38+
Link *AtomLink
39+
Id string `xml:"id,omitempty"`
4040
Updated string `xml:"updated"`
41-
Entries []*atomEntry
41+
Summary string `xml:"summary,omitempty"`
42+
Entries []*AtomEntry
4243
}
4344

4445
type Atom struct {
4546
*Feed
4647
}
4748

48-
func newAtomEntry(i *Item) *atomEntry {
49+
func newAtomEntry(i *Item) *AtomEntry {
4950
id := i.Id
5051
// assume the description is html
51-
s := &atomSummary{i.Description, "html"}
52+
s := &AtomSummary{i.Description, "html"}
5253

53-
// try to get a single timestamp, since we only have one in atom
54-
ts := i.Updated
55-
if ts.IsZero() {
56-
ts = i.Created
57-
}
58-
// <id>tag:blog.kowalczyk.info,2012-09-11:/item/1.html</id>
5954
if len(id) == 0 {
6055
// if there's no id set, try to create one, either from data or just a uuid
6156
if len(i.Link.Href) > 0 && (!i.Created.IsZero() || !i.Updated.IsZero()) {
62-
dateStr := ts.Format("2006-01-02")
57+
dateStr := anyTimeFormat("2006-01-02", i.Updated, i.Created)
6358
host, path := i.Link.Href, "/invalid.html"
6459
if url, err := url.Parse(i.Link.Href); err == nil {
6560
host, path = url.Host, url.Path
@@ -69,29 +64,27 @@ func newAtomEntry(i *Item) *atomEntry {
6964
id = "urn:uuid:" + NewUUID().String()
7065
}
7166
}
72-
x := &atomEntry{
67+
x := &AtomEntry{
7368
Title: i.Title,
74-
Link: &atomLink{Href: i.Link.Href, Rel: i.Link.Rel},
69+
Link: &AtomLink{Href: i.Link.Href, Rel: i.Link.Rel},
7570
Summary: s,
7671
Id: id,
7772
Updated: i.Updated.Format(time.RFC3339)}
7873
return x
7974
}
8075

8176
func (a *Atom) FeedXml() interface{} {
82-
ts := a.Updated
83-
if ts.IsZero() {
84-
ts = a.Created
85-
}
86-
feed := &atomFeed{
77+
updated := anyTimeFormat(time.RFC3339, a.Updated, a.Created)
78+
feed := &AtomFeed{
8779
Ns: ns,
8880
Title: a.Title,
89-
Link: &atomLink{Href: a.Link.Href, Rel: a.Link.Rel},
81+
Link: &AtomLink{Href: a.Link.Href, Rel: a.Link.Rel},
82+
Summary: a.Description,
9083
Id: a.Link.Href,
91-
Updated: ts.Format(time.RFC3339)}
84+
Updated: updated,
85+
}
9286
for _, e := range a.Items {
9387
feed.Entries = append(feed.Entries, newAtomEntry(e))
9488
}
95-
9689
return feed
9790
}

feed.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,15 @@ package syndicate
22

33
import (
44
"encoding/xml"
5-
"fmt"
65
"time"
76
)
87

98
type Link struct {
10-
Href string
11-
Rel string
9+
Href, Rel string
1210
}
1311

1412
type Author struct {
15-
Name string
16-
Email string
13+
Name, Email string
1714
}
1815

1916
type Item struct {
@@ -42,6 +39,16 @@ func (f *Feed) Add(item *Item) {
4239
f.Items = append(f.Items, item)
4340
}
4441

42+
// returns the first non-zero time formatted as a string or ""
43+
func anyTimeFormat(format string, times ...time.Time) string {
44+
for _, t := range times {
45+
if !t.IsZero() {
46+
return t.Format(format)
47+
}
48+
}
49+
return ""
50+
}
51+
4552
type XmlFeed interface {
4653
FeedXml() interface{}
4754
}
@@ -62,14 +69,7 @@ func (f *Feed) ToAtom() (string, error) {
6269
return ToXML(a)
6370
}
6471

65-
func (f *Feed) ToRss(version ...float64) (string, error) {
66-
vers := 2.0
67-
if len(version) > 0 {
68-
vers = version[0]
69-
}
70-
/*
71-
r := &RssFeed{f}
72-
return ToXML(r)
73-
*/
74-
return fmt.Sprint(vers), nil
72+
func (f *Feed) ToRss() (string, error) {
73+
r := &Rss{f}
74+
return ToXML(r)
7575
}

feed_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ func TestFeed(t *testing.T) {
1616
}
1717

1818
fmt.Println(feed.ToAtom())
19+
fmt.Println(feed.ToRss())
1920
}

rss.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,99 @@
11
package syndicate
2+
3+
import (
4+
"encoding/xml"
5+
"fmt"
6+
//"net/url"
7+
"time"
8+
)
9+
10+
type RssFeed struct {
11+
XMLName xml.Name `xml:"rss"`
12+
Version string `xml:"version,attr"`
13+
Channel *RssChannel
14+
}
15+
16+
type RssChannel struct {
17+
XMLName xml.Name `xml:"channel"`
18+
Title string `xml:"title"` // required
19+
Link string `xml:"link"` // required
20+
Description string `xml:"description"` // required
21+
Language string `xml:"language,omitempty"`
22+
Copyright string `xml:"copyright,omitempty"`
23+
ManagingEditor string `xml:"managingEditor,omitempty"` // Author used
24+
WebMaster string `xml:"webMaster,omitempty"`
25+
PubDate string `xml:"pubDate,omitempty"` // created or updated
26+
LastBuildDate string `xml:"lastBuildDate,omitempty"` // updated used
27+
Category string `xml:"category,omitempty"`
28+
Generator string `xml:"generator,omitempty"`
29+
Docs string `xml:"docs,omitempty"`
30+
Cloud string `xml:"cloud,omitempty"`
31+
Ttl string `xml:"ttl,omitempty"`
32+
Image string `xml:"image,omitempty"`
33+
Rating string `xml:"rating,omitempty"`
34+
TextInput string `xml:"textInput,omitempty"`
35+
SkipHours string `xml:"skipHours,omitempty"`
36+
SkipDays string `xml:"skipDays,omitempty"`
37+
Items []*RssItem
38+
}
39+
40+
type RssItem struct {
41+
XMLName xml.Name `xml:"item"`
42+
Title string `xml:"title"` // required
43+
Link string `xml:"link"` // required
44+
Description string `xml:"description"` // required
45+
Author string `xml:"author,omitempty"`
46+
Category string `xml:"category,omitempty"`
47+
Comments string `xml:"comments,omitempty"`
48+
Enclosure *RssEnclosure
49+
Guid string `xml:"guid,omitempty"` // Id used
50+
PubDate string `xml:"pubDate,omitempty"` // created or updated
51+
Source string `xml:"source,omitempty"`
52+
}
53+
54+
type RssEnclosure struct {
55+
XMLName xml.Name `xml:"enclosure"`
56+
Url string `xml:"url,attr"`
57+
Length string `xml:"length,attr"`
58+
Type string `xml:"type,attr"`
59+
}
60+
61+
type Rss struct {
62+
*Feed
63+
}
64+
65+
func newRssItem(i *Item) *RssItem {
66+
item := &RssItem{
67+
Title: i.Title,
68+
Link: i.Link.Href,
69+
Description: i.Description,
70+
Guid: i.Id,
71+
}
72+
return item
73+
}
74+
75+
func (r *Rss) FeedXml() interface{} {
76+
// only generate version 2.0 feeds for now
77+
pub := anyTimeFormat(time.RFC3339, r.Created, r.Updated)
78+
build := anyTimeFormat(time.RFC3339, r.Updated)
79+
author := r.Author.Email
80+
if len(r.Author.Name) > 0 {
81+
author = fmt.Sprintf("%s (%s)", r.Author.Email, r.Author.Name)
82+
}
83+
feed := &RssFeed{
84+
Version: "2.0",
85+
Channel: &RssChannel{
86+
Title: r.Title,
87+
Link: r.Link.Href,
88+
Description: r.Description,
89+
ManagingEditor: author,
90+
PubDate: pub,
91+
LastBuildDate: build,
92+
},
93+
}
94+
for _, i := range r.Items {
95+
feed.Channel.Items = append(feed.Channel.Items, newRssItem(i))
96+
}
97+
return feed
98+
99+
}

uuid.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
type UUID [16]byte
1111

12+
// create a new uuid v4
1213
func NewUUID() *UUID {
1314
u := &UUID{}
1415
_, err := rand.Read(u[:16])

0 commit comments

Comments
 (0)