|
@@ -2,97 +2,146 @@ package main
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
+ "io"
|
|
|
"log"
|
|
|
+ "net/http"
|
|
|
"net/url"
|
|
|
+ "strings"
|
|
|
"text/template"
|
|
|
+ "time"
|
|
|
|
|
|
"github.com/SlyMarbo/rss"
|
|
|
)
|
|
|
|
|
|
+var (
|
|
|
+ conf *config
|
|
|
+)
|
|
|
+
|
|
|
type article struct {
|
|
|
Title, URL, Summary string
|
|
|
}
|
|
|
|
|
|
func main() {
|
|
|
log.Println("gof starting up...")
|
|
|
- config := readConfig()
|
|
|
+ conf = readConfig()
|
|
|
+ log.Print(conf.Accounts)
|
|
|
|
|
|
var tpls = make(map[string]*template.Template)
|
|
|
- for _, f := range config.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())
|
|
|
- }
|
|
|
- tpls[f.URL] = tmpl
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- log.Println("Fetching feeds...")
|
|
|
- var feeds []*rss.Feed
|
|
|
- for _, source := range config.Feeds {
|
|
|
- feed, err := rss.Fetch(source.URL)
|
|
|
- if err != nil {
|
|
|
- log.Printf("Error fetching %s: %s", source.URL, err.Error())
|
|
|
- continue
|
|
|
+ for _, a := range conf.Accounts {
|
|
|
+ for _, 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())
|
|
|
+ }
|
|
|
+ tpls[f.URL] = tmpl
|
|
|
}
|
|
|
- feeds = append(feeds, feed)
|
|
|
- log.Printf("Fetched %s", feed.Title)
|
|
|
- }
|
|
|
- if len(feeds) == 0 {
|
|
|
- log.Fatal("Expected at least one feed to successfully fetch.")
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- for _, feed := range feeds {
|
|
|
-
|
|
|
- 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")
|
|
|
+ for _, account := range conf.Accounts {
|
|
|
+
|
|
|
+ log.Println("Fetching feeds...")
|
|
|
+ var feeds []*rss.Feed
|
|
|
+ for _, source := range account.Feeds {
|
|
|
+ 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)
|
|
|
}
|
|
|
- feedLink, _ := url.Parse(feed.Link)
|
|
|
- if err != nil {
|
|
|
- log.Fatal("failed parsing canonical feed URL of the feed")
|
|
|
+ if len(feeds) == 0 {
|
|
|
+ log.Fatal("Expected at least one feed to successfully fetch.")
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- for _, item := range items {
|
|
|
- if item.Date.Before(config.LastUpdated) {
|
|
|
- log.Println("No new items. Skipping.")
|
|
|
+
|
|
|
+ for _, feed := range feeds {
|
|
|
+
|
|
|
+ if len(feed.Items) == 0 {
|
|
|
+ log.Printf("Warning: feed %s has no items.", feed.Title)
|
|
|
continue
|
|
|
}
|
|
|
- itemLink, err := url.Parse(item.Link)
|
|
|
- if err != nil {
|
|
|
- log.Fatal("failed parsing article URL of the feed item")
|
|
|
+ items := feed.Items
|
|
|
+ if len(items) > 1 {
|
|
|
+ items = items[:1]
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- 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,
|
|
|
- URL: base.ResolveReference(itemLink).String(),
|
|
|
+ base, err := url.Parse(feed.UpdateURL)
|
|
|
+ if err != nil {
|
|
|
+ log.Fatal("failed parsing update URL of the feed")
|
|
|
}
|
|
|
- buf := new(bytes.Buffer)
|
|
|
- err = tpls[base.String()].Execute(buf, i)
|
|
|
+ feedLink, _ := url.Parse(feed.Link)
|
|
|
if err != nil {
|
|
|
- log.Fatalf("Error executing template [%s]. Error: %s", tpls[base.String()], err.Error())
|
|
|
+ log.Fatal("failed parsing canonical feed URL of the feed")
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ for _, item := range items {
|
|
|
+ if item.Date.Before(conf.LastUpdated) {
|
|
|
+ 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")
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ 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,
|
|
|
+ URL: base.ResolveReference(itemLink).String(),
|
|
|
+ }
|
|
|
+ buf := new(bytes.Buffer)
|
|
|
+ err = tpls[base.String()].Execute(buf, i)
|
|
|
+ if err != nil {
|
|
|
+ log.Fatalf("Error executing template [%s]. Error: %s", tpls[base.String()], err.Error())
|
|
|
+ }
|
|
|
+ if err = postMessage(account, buf.String()); err != nil {
|
|
|
+ log.Fatalf("Failed to post message \"%s\". Error: %s", buf.String(), err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
- log.Println("Message: ", buf.String())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
- config.updateLastUpdated()
|
|
|
+ conf.updateLastUpdated()
|
|
|
|
|
|
- config.Save()
|
|
|
+ conf.Save()
|
|
|
+}
|
|
|
+
|
|
|
+func postMessage(account Account, message string) error {
|
|
|
+ apiURL := account.InstanceURL + "/api/v1/statuses"
|
|
|
+
|
|
|
+ data := url.Values{}
|
|
|
+ data.Set("status", message)
|
|
|
+ data.Set("visibility", "unlisted")
|
|
|
+
|
|
|
+ var req *http.Request
|
|
|
+ var body io.Reader
|
|
|
+ body = strings.NewReader(data.Encode())
|
|
|
+
|
|
|
+ req, err := http.NewRequest("POST", apiURL, body)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
+ req.Header.Set("Authorization", "Bearer "+account.AccessToken)
|
|
|
+
|
|
|
+ c := &http.Client{Timeout: time.Second * 10}
|
|
|
+
|
|
|
+ resp, err := c.Do(req)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ defer resp.Body.Close()
|
|
|
+
|
|
|
+ log.Println("response Status: ", resp.Status)
|
|
|
+
|
|
|
+ return nil
|
|
|
}
|