-
Notifications
You must be signed in to change notification settings - Fork 1
/
feed.go
155 lines (129 loc) · 3.59 KB
/
feed.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package instant
import (
"bytes"
"crypto/md5"
"encoding/xml"
"fmt"
)
// Feed struct represents Facebook Instant Articles RSS feed.
// See https://developers.facebook.com/docs/instant-articles/publishing/setup-rss-feed for more info.
type Feed struct {
Version string `xml:"version,attr"`
Content string `xml:"xmlns:content,attr"`
Channel channel `xml:"channel"`
}
type channel struct {
Title string `xml:"title"`
LastBuildDate string `xml:"lastBuildDate"`
Language string `xml:"language"`
Link string `xml:"link"`
Description string `xml:"description"`
Item []item `xml:"item"`
}
type item struct {
Title string `xml:"title"`
GUID string `xml:"guid"`
Description string `xml:"description"`
Link string `xml:"link"`
Author []string `xml:"author"`
PubDate string `xml:"pubDate"`
Encoded []byte `xml:",innerxml"`
}
// SetTitle of feed. Optional.
func (f *Feed) SetTitle(s string) {
f.Channel.Title = s
}
// SetLink for feed. Optional.
func (f *Feed) SetLink(url string) {
f.Channel.Link = url
}
// SetDescription set feed description. Optional.
func (f *Feed) SetDescription(s string) {
f.Channel.Description = s
}
// SetLanguage sets feed language, default is set to en-us.
func (f *Feed) SetLanguage(l string) {
f.Channel.Language = l
}
// // SetLastBuildDate sets feed last build date.
// func (f *Feed) setLastBuildDate(d time.Time) {
// }
// AddArticle to feed. Md5 checksum of URL will be used as GUID.
func (f *Feed) AddArticle(a Article) error {
return f.addArticle(a, "")
}
// AddArticleWithGUID to feed.
func (f *Feed) AddArticleWithGUID(a Article, guid string) error {
return f.addArticle(a, guid)
}
func (f *Feed) addArticle(a Article, guid string) error {
b, err := xml.Marshal(a)
if err != nil {
return err
}
if guid == "" {
guid = fmt.Sprintf("%x", md5.Sum([]byte(a.Head.Link.Href)))
}
var buff bytes.Buffer
buff.WriteString("\n<content:encoded><![CDATA[\n")
buff.Write(b)
buff.WriteString("\n]]></content:encoded>")
i := item{
Title: a.Body.Article.Header.H1,
Description: a.Body.Article.Header.H2,
Link: a.Head.Link.Href,
GUID: guid,
Encoded: buff.Bytes(),
}
// if no subtitle, set first para as description
if i.Description == "" && a.Body.Article.Content != nil {
loop:
for _, ifc := range a.Body.Article.Content {
switch ifc.(type) {
case P:
if ifc.(P).Text != "" {
i.Description = string(ifc.(P).Text)
break loop
}
}
}
}
// set latest article date as pubDate
for _, d := range a.Body.Article.Header.Time {
if d.Datetime > i.PubDate {
i.PubDate = d.Datetime
}
}
// set latest article date to feed LastBuildDate
if i.PubDate > f.Channel.LastBuildDate {
f.Channel.LastBuildDate = i.PubDate
}
for _, auth := range a.Body.Article.Header.Address {
i.Author = append(i.Author, auth.A.Text)
}
f.Channel.Item = append(f.Channel.Item, i)
return nil
}
// MarshalXML for xml.Marshaler interface
func (f Feed) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
feed := struct {
Version string `xml:"version,attr"`
Content string `xml:"xmlns:content,attr"`
Channel channel `xml:"channel"`
}{
Version: f.Version,
Content: f.Content,
Channel: f.Channel,
}
feed.Version = "2.0"
feed.Content = "http://purl.org/rss/1.0/modules/content/"
if feed.Channel.Language == "" {
feed.Channel.Language = "en-us"
}
start.Name.Local = "rss" // rename root element from Article to html
return e.EncodeElement(feed, start)
}
// RSS is synonym for xml.Marshal(f)
func (f Feed) RSS() ([]byte, error) {
return xml.Marshal(f)
}