feed.go (view raw)
1package main
2
3import (
4 "bufio"
5 "fmt"
6 "github.com/mmcdole/gofeed"
7 "log"
8 "os"
9 "path"
10 "sort"
11 "time"
12)
13
14const followingPath = "following.txt"
15const followingFile = "following.gmi"
16
17// TODO also get gemini, gemfeed
18
19func feedsWorker() {
20 log.Println("Starting feeds worker")
21 for {
22 users, err := getActiveUserNames()
23 if err != nil {
24 // Handle error somehow
25 fmt.Println(err)
26 continue
27 }
28 for _, user := range users {
29 writeAllFeeds(user)
30 }
31 time.Sleep(time.Hour * 24)
32 }
33}
34
35func writeAllFeeds(user string) error {
36 // Open file
37 file, err := os.Open(path.Join(getUserDirectory(user), followingPath))
38 if err != nil {
39 if os.IsNotExist(err) {
40 // TODO
41 return nil
42 }
43 return err
44 }
45 log.Println("Writing feeds for user " + user)
46 defer file.Close()
47
48 feedData := []*gofeed.Feed{}
49 scanner := bufio.NewScanner(file)
50 for scanner.Scan() {
51 feedURL := scanner.Text()
52 // TODO if scheme is gemini and filetype is gemini... gemtext
53 // TODO if scheme is gemini and filetype is xml/rss... fetch data and parse
54 // TODO rate limit etc
55 fp := gofeed.NewParser()
56 feed, err := fp.ParseURL(feedURL)
57 if err != nil {
58 log.Println("Error getting feed " + feedURL)
59 } else {
60 log.Println("Got feed data from " + feedURL)
61 feedData = append(feedData, feed)
62 }
63 }
64 if err := scanner.Err(); err != nil {
65 return err
66 }
67 // Aggregate and sort by date
68 type feedPlusItem struct {
69 Feed *gofeed.Feed
70 FeedItem *gofeed.Item
71 Date string
72 }
73 data := struct {
74 User string
75 FeedItems []feedPlusItem
76 }{}
77 data.User = user
78 for _, feed := range feedData {
79 for _, item := range feed.Items {
80 if item.UpdatedParsed == nil {
81 item.UpdatedParsed = item.PublishedParsed
82 }
83 if item.UpdatedParsed != nil {
84 date := item.UpdatedParsed.Format("2006-01-02")
85 data.FeedItems = append(data.FeedItems, feedPlusItem{feed, item, date})
86 }
87 }
88 }
89 sort.Slice(data.FeedItems, func(i, j int) bool {
90 return data.FeedItems[i].FeedItem.UpdatedParsed.After(*data.FeedItems[j].FeedItem.UpdatedParsed)
91 })
92
93 outputf, err := os.OpenFile(path.Join(getUserDirectory(user), followingFile), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
94 if err != nil {
95 return err
96 }
97 err = gt.ExecuteTemplate(outputf, "following.gmi", data)
98 if err != nil {
99 return err
100 }
101 defer outputf.Close()
102 // convert to gemini template
103 // write template to file
104 return nil
105}