Rssmon2/rss/feed.go

125 lines
2.6 KiB
Go

package rss
import (
"bytes"
"encoding/gob"
"fmt"
"io/ioutil"
"net/http"
"regexp"
"strings"
"time"
"github.com/mmcdole/gofeed"
)
type Feed struct {
Updated time.Time
Items []string
ItemFilter string
ContentFilter string
Link string
Interval time.Duration
}
func (feed *Feed) String() string {
return fmt.Sprintf("Updated: %v, Items: %v, ItemFilter: %q, ContentFilter: %q, Link: %v, Interval: %s",
feed.Updated.Local(),
feed.Items,
feed.ItemFilter,
feed.ContentFilter,
feed.Link,
feed.Interval,
)
}
func (feed *Feed) ID() string {
return strings.Join(regexp.MustCompile("[a-zA-Z0-9]*").FindAllString(feed.Link, -1), "_")
}
func New(source, itemFilter, contentFilter string, interval time.Duration) (*Feed, error) {
if _, err := regexp.Compile(itemFilter); err != nil {
return nil, err
}
if _, err := regexp.Compile(contentFilter); err != nil {
return nil, err
}
f := &Feed{
Items: []string{},
ItemFilter: itemFilter,
ContentFilter: contentFilter,
Link: source,
Interval: interval,
}
return f, nil
}
func Deserialize(src []byte) (*Feed, error) {
buffer := bytes.NewBuffer(src)
dec := gob.NewDecoder(buffer)
var dst Feed
err := dec.Decode(&dst)
return &dst, err
}
func (feed *Feed) Serialize() ([]byte, error) {
var buffer bytes.Buffer
enc := gob.NewEncoder(&buffer)
err := enc.Encode(feed)
return buffer.Bytes(), err
}
func (feed *Feed) Update() ([]*Item, error) {
resp, err := http.Get(feed.Link)
if err != nil {
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
parser := gofeed.NewParser()
gofeed, err := parser.Parse(bytes.NewBuffer(body))
if err != nil {
return nil, err
}
return feed.fromGofeed(gofeed)
}
func (feed *Feed) fromGofeed(gofeed *gofeed.Feed) ([]*Item, error) {
updated := gofeed.PublishedParsed
if updated == nil {
updated = gofeed.UpdatedParsed
}
if updated == nil && len(gofeed.Items) > 0 {
updated = gofeedItemTS(gofeed.Items[0])
}
if updated == nil {
t := time.Now()
updated = &t
}
newitems, err := feed.appendNewItems(gofeed.Items)
if err != nil {
return nil, err
}
feed.Updated = *updated
return newitems, nil
}
func (feed *Feed) appendNewItems(items []*gofeed.Item) ([]*Item, error) {
newitems := []*Item{}
for i := range items {
t := gofeedItemTS(items[i])
if t.Before(feed.Updated) {
continue
}
if ok, _ := regexp.MatchString(feed.ItemFilter, items[i].Title); !ok {
continue
}
item := fromGofeedItem(items[i], feed.ContentFilter)
newitems = append(newitems, item)
feed.Items = append(feed.Items, item.Name)
}
return newitems, nil
}