282 lines
5.5 KiB
Go
282 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"plugin"
|
|
"time"
|
|
)
|
|
|
|
type FeedSource struct {
|
|
Feeds []*Feed
|
|
|
|
// Plugin Functions
|
|
getSourceName func() string
|
|
refreshFeedList func() []map[string]string
|
|
getFeedUrl func(string, time.Time) (string, error)
|
|
getFeedDesc func(string, time.Time) (string, error)
|
|
}
|
|
|
|
func LoadFeedPlugin(p *plugin.Plugin) (*FeedSource, error) {
|
|
ret := new(FeedSource)
|
|
feedSourceSymbol, err := p.Lookup("GetSourceName")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret.getSourceName = feedSourceSymbol.(func() string)
|
|
|
|
feedListSymbol, err := p.Lookup("GetFeedList")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret.refreshFeedList = feedListSymbol.(func() []map[string]string)
|
|
feeds := ret.refreshFeedList()
|
|
// `feeds` is a []map, each map should contain keys: `slug`, `name`, `author`, `source`
|
|
for _, f := range feeds {
|
|
var slug, name, author, source string
|
|
var ok bool
|
|
if slug, ok = f["slug"]; !ok {
|
|
continue
|
|
}
|
|
if name, ok = f["name"]; !ok {
|
|
continue
|
|
}
|
|
if author, ok = f["author"]; !ok {
|
|
continue
|
|
}
|
|
if source, ok = f["source"]; !ok {
|
|
continue
|
|
}
|
|
ret.Feeds = append(ret.Feeds, NewFeed(slug, name, author, source))
|
|
}
|
|
|
|
feedUrlSymbol, err := p.Lookup("GetFeedUrl")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret.getFeedUrl = feedUrlSymbol.(func(string, time.Time) (string, error))
|
|
|
|
feedDescSymbol, err := p.Lookup("GetFeedDesc")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret.getFeedDesc = feedDescSymbol.(func(string, time.Time) (string, error))
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func (f *FeedSource) getFeed(slug string) *Feed {
|
|
for i := range f.Feeds {
|
|
if f.Feeds[i].Slug == slug {
|
|
return f.Feeds[i]
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Feed struct {
|
|
Name string
|
|
Author string
|
|
Slug string
|
|
Source string
|
|
Desc string
|
|
LastUpdate time.Time
|
|
}
|
|
|
|
func NewFeed(s, n, a, source string) *Feed {
|
|
return &Feed{
|
|
Name: n,
|
|
Author: a,
|
|
Slug: s,
|
|
Source: source,
|
|
}
|
|
}
|
|
|
|
func (f *Feed) GetBucket() []string {
|
|
return []string{"feeds", f.Source, f.Slug}
|
|
}
|
|
|
|
func (f *Feed) Update() error {
|
|
/*
|
|
dt := time.Now()
|
|
desc, err := getFeedDesc(f.Source, f.Slug, dt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if desc == f.Desc {
|
|
return errors.New("Feed didn't change")
|
|
}
|
|
f.Desc = desc
|
|
f.LastUpdate = dt
|
|
*/
|
|
return nil
|
|
}
|
|
|
|
func (f *Feed) GetUrl(dt time.Time) string {
|
|
var v string
|
|
/*
|
|
var e error
|
|
if v, e = getFeedUrl(f.Source, f.Slug, dt); e != nil {
|
|
return ""
|
|
}
|
|
*/
|
|
return v
|
|
}
|
|
|
|
func (f *Feed) GetDesc(dt time.Time) string {
|
|
var v string
|
|
/*
|
|
var e error
|
|
if v, e = getFeedDesc(f.Source, f.Slug, dt); e != nil {
|
|
return ""
|
|
}
|
|
*/
|
|
return v
|
|
}
|
|
|
|
func (f *Feed) GetRssItem() string {
|
|
var v string
|
|
/*
|
|
var e error
|
|
if v, e = getRssItem(f.Source, f.Slug); e != nil {
|
|
return ""
|
|
}
|
|
*/
|
|
return v
|
|
}
|
|
|
|
// DB Function to save a feed
|
|
func (m *model) SaveFeed(f *Feed) error {
|
|
var err error
|
|
if err = m.openDB(); err != nil {
|
|
return err
|
|
}
|
|
defer m.closeDB()
|
|
bkt := f.GetBucket()
|
|
if err = m.bolt.MkBucketPath(bkt); err != nil {
|
|
return err
|
|
}
|
|
if err = m.bolt.SetValue(bkt, "name", f.Name); err != nil {
|
|
return err
|
|
}
|
|
if err = m.bolt.SetValue(bkt, "author", f.Author); err != nil {
|
|
return err
|
|
}
|
|
if err = m.bolt.SetValue(bkt, "desc", f.Desc); err != nil {
|
|
return err
|
|
}
|
|
if err = m.bolt.SetTimestamp(bkt, "lastupdate", f.LastUpdate); err != nil {
|
|
return err
|
|
}
|
|
// Add it to the cached list
|
|
for i, v := range m.Feeds {
|
|
if v.Source == f.Source && v.Slug == f.Slug {
|
|
m.Feeds[i] = *f
|
|
return nil
|
|
}
|
|
}
|
|
m.Feeds = append(m.Feeds, *f)
|
|
return nil
|
|
}
|
|
|
|
// DB Function to get a feed
|
|
func (m *model) GetFeed(source, slug string) (*Feed, error) {
|
|
var err error
|
|
if err = m.openDB(); err != nil {
|
|
return nil, err
|
|
}
|
|
defer m.closeDB()
|
|
ret := new(Feed)
|
|
ret.Source = source
|
|
ret.Slug = slug
|
|
bkt := ret.GetBucket()
|
|
if ret.Name, err = m.bolt.GetValue(bkt, "name"); err != nil {
|
|
return nil, err
|
|
}
|
|
if ret.Author, err = m.bolt.GetValue(bkt, "author"); err != nil {
|
|
return nil, err
|
|
}
|
|
if ret.Desc, err = m.bolt.GetValue(bkt, "desc"); err != nil {
|
|
return nil, err
|
|
}
|
|
if ret.LastUpdate, err = m.bolt.GetTimestamp(bkt, "lastupdate"); err != nil {
|
|
return nil, err
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
// Load all feeds into the model
|
|
func (m *model) LoadFeeds() error {
|
|
m.Feeds = m.GetAllFeeds()
|
|
return nil
|
|
}
|
|
|
|
// Save all feeds to the DB
|
|
func (m *model) SaveAllFeeds(feedSources []FeedSource) {
|
|
var err error
|
|
if err = m.openDB(); err != nil {
|
|
return
|
|
}
|
|
defer m.closeDB()
|
|
for _, v := range feedSources {
|
|
for j := range v.Feeds {
|
|
fmt.Printf("Saving Feed to DB (%s;%s)\n", v.Feeds[j].Source, v.Feeds[j].Slug)
|
|
m.SaveFeed(v.Feeds[j])
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get all feeds from the db
|
|
func (m *model) GetAllFeeds() []Feed {
|
|
var ret []Feed
|
|
var err error
|
|
if err = m.openDB(); err != nil {
|
|
return ret
|
|
}
|
|
defer m.closeDB()
|
|
var srcs []string
|
|
bkt := []string{"feeds"}
|
|
if srcs, err = m.bolt.GetBucketList(bkt); err != nil {
|
|
return ret
|
|
}
|
|
for _, src := range srcs {
|
|
srcBkt := append(bkt, src)
|
|
var slugs []string
|
|
if slugs, err = m.bolt.GetBucketList(srcBkt); err != nil {
|
|
return ret
|
|
}
|
|
for _, slg := range slugs {
|
|
c, err := m.GetFeed(src, slg)
|
|
if err == nil {
|
|
ret = append(ret, *c)
|
|
}
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// Delete a feed from the DB
|
|
func (m *model) DeleteFeed(slug string) error {
|
|
var err error
|
|
if err = m.openDB(); err != nil {
|
|
return err
|
|
}
|
|
defer m.closeDB()
|
|
|
|
return m.bolt.DeleteBucket([]string{"feeds"}, slug)
|
|
}
|
|
|
|
func (m *model) RemoveMissingFeeds(feeds []Feed) {
|
|
for _, c := range m.Feeds {
|
|
var fnd bool
|
|
for _, nc := range feeds {
|
|
if nc.Slug == c.Slug {
|
|
fnd = true
|
|
break
|
|
}
|
|
}
|
|
if !fnd {
|
|
m.DeleteFeed(c.Slug)
|
|
}
|
|
}
|
|
}
|