package main import ( "bytes" "flag" "log" "net/url" "text/template" "github.com/SlyMarbo/rss" ) var ( conf *config debug bool debugOrDryRun bool ) type article struct { Title, URL, Summary string } func main() { var ( configFile string dryRun bool ) flag.StringVar(&configFile, "c", "gof.yaml", "the configuration file to use") flag.BoolVar(&dryRun, "dry-run", false, "whether to perform a dry run or not") flag.BoolVar(&debug, "debug", false, "enable debugging") flag.Parse() debugOrDryRun = debug || dryRun log.Println(configFile) log.Println("gof starting up...") conf = readConfig(configFile) log.Printf("Version: %s\n", conf.Meta.Version) log.Printf("Build time: %s\n", conf.Meta.Buildtime) var tpls = make(map[string]*template.Template) var formats = make(map[string]string) for accountIndex, a := range conf.Accounts { for feedIndex, f := range a.Feeds { tmpl, err := template.New(f.URL).Parse(f.Template) if err != nil { log.Fatalf("Failed to parse template [%s]. Error: %s", f.Template, err.Error()) } // Default format to "plain", if blank if f.Format == "" { conf.Accounts[accountIndex].Feeds[feedIndex].Format = "plain" f.Format = "plain" } tpls[f.URL] = tmpl formats[f.URL] = f.Format } } for _, account := range conf.Accounts { var toot message // Get feeds log.Printf("Fetching feeds for account [%s]...", account.Name) var feeds []*rss.Feed for _, source := range account.Feeds { toot.feed = source if debug { log.Printf("source:\n\n%v", source) } feed, err := rss.Fetch(source.URL) if err != nil { log.Printf("Error fetching %s: %s", source.URL, err.Error()) continue } feeds = append(feeds, feed) log.Printf("Fetched [%s]", feed.Title) } if len(feeds) == 0 { log.Fatal("Expected at least one feed to successfully fetch.") } // Loop through feeds for _, feed := range feeds { // Get feed items if len(feed.Items) == 0 { log.Printf("Warning: feed %s has no items.", feed.Title) continue } items := feed.Items if len(items) > 1 { items = items[:1] } base, err := url.Parse(feed.UpdateURL) if err != nil { log.Fatal("failed parsing update URL of the feed") } feedLink, _ := url.Parse(feed.Link) if err != nil { log.Fatal("failed parsing canonical feed URL of the feed") } // Loop through items for _, item := range items { if item.Date.Before(conf.LastUpdated) && !debug { log.Println("No new items. Skipping.") continue } itemLink, err := url.Parse(item.Link) if err != nil { log.Fatal("failed parsing article URL of the feed item") } // Make sure data looks OK log.Printf("Item Data:\n\tTimestamp: %s\n\tSite URL: %s\n\tFeed Title: %s\n\tItem Title: %s\n\tItem URL: %s\n", item.Date, base.ResolveReference(feedLink).String(), feed.Title, item.Title, base.ResolveReference(itemLink).String()) i := article{ Title: item.Title, Summary: item.Summary, URL: base.ResolveReference(itemLink).String(), } buf := new(bytes.Buffer) err = tpls[base.String()].Execute(buf, i) if err != nil { log.Fatalf("Error executing template [%v]. Error: %s", tpls[base.String()], err.Error()) } toot.account = account toot.content = buf.String() if err = toot.post(); err != nil { log.Fatalf("Failed to post message \"%s\". Error: %s", buf.String(), err.Error()) } } } } if !debugOrDryRun { // update timestamp in config conf.updateLastUpdated() // save config err := conf.Save() if err != nil { log.Fatalf("Failed to save config to file. Error: %s", err.Error()) } } }