gof.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package main
  2. import (
  3. "bytes"
  4. "io"
  5. "log"
  6. "net/http"
  7. "net/url"
  8. "strings"
  9. "text/template"
  10. "time"
  11. "github.com/SlyMarbo/rss"
  12. )
  13. var (
  14. conf *config
  15. )
  16. type article struct {
  17. Title, URL, Summary string
  18. }
  19. func main() {
  20. log.Println("gof starting up...")
  21. conf = readConfig()
  22. var tpls = make(map[string]*template.Template)
  23. for _, a := range conf.Accounts {
  24. for _, f := range a.Feeds {
  25. tmpl, err := template.New(f.URL).Parse(f.Template)
  26. if err != nil {
  27. log.Fatalf("Failed to parse template [%s]. Error: %s", f.Template, err.Error())
  28. }
  29. tpls[f.URL] = tmpl
  30. }
  31. }
  32. for _, account := range conf.Accounts {
  33. // Get feeds
  34. log.Println("Fetching feeds...")
  35. var feeds []*rss.Feed
  36. for _, source := range account.Feeds {
  37. feed, err := rss.Fetch(source.URL)
  38. if err != nil {
  39. log.Printf("Error fetching %s: %s", source.URL, err.Error())
  40. continue
  41. }
  42. feeds = append(feeds, feed)
  43. log.Printf("Fetched %s", feed.Title)
  44. }
  45. if len(feeds) == 0 {
  46. log.Fatal("Expected at least one feed to successfully fetch.")
  47. }
  48. // Loop through feeds
  49. for _, feed := range feeds {
  50. // Get feed items
  51. if len(feed.Items) == 0 {
  52. log.Printf("Warning: feed %s has no items.", feed.Title)
  53. continue
  54. }
  55. items := feed.Items
  56. if len(items) > 1 {
  57. items = items[:1]
  58. }
  59. base, err := url.Parse(feed.UpdateURL)
  60. if err != nil {
  61. log.Fatal("failed parsing update URL of the feed")
  62. }
  63. feedLink, _ := url.Parse(feed.Link)
  64. if err != nil {
  65. log.Fatal("failed parsing canonical feed URL of the feed")
  66. }
  67. // Loop through items
  68. for _, item := range items {
  69. if item.Date.Before(conf.LastUpdated) {
  70. log.Println("No new items. Skipping.")
  71. continue
  72. }
  73. itemLink, err := url.Parse(item.Link)
  74. if err != nil {
  75. log.Fatal("failed parsing article URL of the feed item")
  76. }
  77. // Make sure data looks OK
  78. // TODO: remove before release
  79. log.Printf("Item Data:\n\tTimestamp: %s\n\tSite URL: %s\n\tFeed Title: %s\n\tItem Title: %s\n\tItem URL: %s\n",
  80. item.Date, base.ResolveReference(feedLink).String(),
  81. feed.Title, item.Title, base.ResolveReference(itemLink).String())
  82. i := article{
  83. Title: item.Title,
  84. URL: base.ResolveReference(itemLink).String(),
  85. }
  86. buf := new(bytes.Buffer)
  87. err = tpls[base.String()].Execute(buf, i)
  88. if err != nil {
  89. log.Fatalf("Error executing template [%s]. Error: %s", tpls[base.String()], err.Error())
  90. }
  91. if err = postMessage(account, buf.String()); err != nil {
  92. log.Fatalf("Failed to post message \"%s\". Error: %s", buf.String(), err.Error())
  93. }
  94. }
  95. }
  96. }
  97. // update timestamp in config
  98. conf.updateLastUpdated()
  99. // save config
  100. conf.Save()
  101. }
  102. func postMessage(account Account, message string) error {
  103. apiURL := account.InstanceURL + "/api/v1/statuses"
  104. data := url.Values{}
  105. data.Set("status", message)
  106. data.Set("visibility", "unlisted")
  107. var req *http.Request
  108. var body io.Reader
  109. body = strings.NewReader(data.Encode())
  110. req, err := http.NewRequest("POST", apiURL, body)
  111. if err != nil {
  112. return err
  113. }
  114. // Set Headers
  115. req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  116. req.Header.Set("Authorization", "Bearer "+account.AccessToken)
  117. c := &http.Client{Timeout: time.Second * 10}
  118. resp, err := c.Do(req)
  119. if err != nil {
  120. return err
  121. }
  122. defer resp.Body.Close()
  123. log.Println("response Status: ", resp.Status)
  124. return nil
  125. }