diff --git a/.gitignore b/.gitignore index 92ad372..5991c74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ rssd.conf output.conf +*.mp3 diff --git a/main.go b/main.go index 32d7fc5..e348174 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "log" "os" + "strconv" "time" "github.com/BurntSushi/toml" @@ -15,10 +16,11 @@ type Config struct { type Item struct { Title, Description, Url, Filename string + Length int } type Podcast struct { - Title, Description string + Title, Description, Url string Items []Item } @@ -26,32 +28,79 @@ type pcList struct { Podcasts []Podcast } +func newpcList(confs ...string) (ret *pcList) { + ret = &pcList{} + ret.Podcasts = make([]Podcast,0) + if len(confs) > 0 { + if _, err := toml.DecodeFile("output.conf", &ret); err != nil { + log.Print("Error reading podcast list:",err) + } + } + return +} + +func (p *pcList) Find(x *Podcast) (int, bool) { + for i,y := range p.Podcasts { + if y.Title == x.Title { + return i, true + } + } + return 0, false +} + func (p *pcList) Add(x *Podcast) { - (*p).Podcasts = append((*p).Podcasts,*x) + if x == nil { + return + } + if i,ok := p.Find(x); ok == true { + log.Print(" Existing podcast") + p.Podcasts[i].Merge(x) + } else { + log.Print(" New podcast") + p.Podcasts = append((*p).Podcasts,*x) + } } -type Db struct { - Podcasts []Podcast +func (p *Podcast) Merge(x *Podcast) { + for _,item := range x.Items { + if !p.Has(item) { + log.Print(" Appending '",item.Title,"'") + p.Items = append(p.Items,item) + } + } } -type Selector func(*gofeed.Item) bool - -func Any(ss []Selector, i *gofeed.Item) bool { - for _, s := range ss { - if s(i) { +func (p *Podcast) Has(i Item) bool { + for _,x := range p.Items { + if x.Title == i.Title { return true } } return false } -func All(ss []Selector, i *gofeed.Item) bool { - for _, s := range ss { - if !s(i) { - return false +type Selector func(*gofeed.Item) bool + +func AllSelectors(ss ...Selector) Selector { + return func(i *gofeed.Item) bool { + for _, s := range ss { + if !s(i) { + return false + } } + return true + } +} + +func AnySelector(ss ...Selector) Selector { + return func(i *gofeed.Item) bool { + for _, s := range ss { + if s(i) { + return true + } + } + return false } - return true } func newerThan(t time.Time) Selector { @@ -63,20 +112,46 @@ func newerThan(t time.Time) Selector { } } -func readFeed(url string,ss ...Selector) *Podcast { +func daysAgo(x int) Selector { + d := time.Now() + return newerThan(time.Date(d.Year(),d.Month(),d.Day()-x,0,0,0,0,time.Local)) +} + +func toPodcast(sel Selector, url string, feed *gofeed.Feed) (ret *Podcast) { + ret = &Podcast{ + Title: feed.Title, + Description: feed.Description, + Url: url, + Items: []Item{}, + } + for _, i := range feed.Items { + if sel(i) { + it := Item{ + Title: i.Title, + Description: i.Description, + } + for _, n := range i.Enclosures { + if n.Type == "audio/mpeg" { + it.Url = n.URL + if l, err := strconv.Atoi(n.Length); err == nil { + it.Length = l + } + } + } + ret.Items = append(ret.Items,it) + } + } + return +} + +func readFeed(url string,sel Selector) *Podcast { fp := gofeed.NewParser() feed, err := fp.ParseURL(url) if err != nil { - log.Fatal(err) + log.Print(err) + return nil } - pc := Podcast{ feed.Title, feed.Description, []Item{} } - for _, i := range feed.Items { - if All(ss,i) { - it := Item{ Title: i.Title, Description: i.Description } - pc.Items = append(pc.Items,it) - } - } - return &pc + return toPodcast(sel,url,feed) } func main() { @@ -86,15 +161,12 @@ func main() { if _, err := toml.DecodeFile("rssd.conf", &conf); err != nil { log.Fatal("Error reading config file:",err) } - pl := &pcList{} - pl.Podcasts = make([]Podcast,0) - - d := time.Now() - lastMonth := newerThan(time.Date(d.Year(),d.Month()-1,d.Day(),0,0,0,0,time.Local)) + pl := newpcList("output.conf") + sel := daysAgo(60) for _,url := range conf.Urls { log.Print(" -> ",url) - pl.Add(readFeed(url,lastMonth)) + pl.Add(readFeed(url,sel)) } of,err := os.Create("output.conf") if err != nil {