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 }
72 data := struct {
73 FeedItems []feedPlusItem
74 }{}
75 for _, feed := range feedData {
76 for _, item := range feed.Items {
77 if item.PublishedParsed != nil {
78 data.FeedItems = append(data.FeedItems, feedPlusItem{feed, item})
79 }
80 }
81 }
82 sort.Slice(data.FeedItems, func(i, j int) bool {
83 return data.FeedItems[i].FeedItem.PublishedParsed.After(*data.FeedItems[j].FeedItem.PublishedParsed)
84 })
85
86 outputf, err := os.OpenFile(path.Join(getUserDirectory(user), followingFile), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755)
87 if err != nil {
88 return err
89 }
90 err = gt.ExecuteTemplate(outputf, "following.gmi", data)
91 if err != nil {
92 return err
93 }
94 defer outputf.Close()
95 // convert to gemini template
96 // write template to file
97 return nil
98}