all repos — flounder @ fbba2837f74ed229dd1a9fc32a3ddf12d1a397d3

A small site builder for the Gemini protocol

gemfeed.go (view raw)

 1// Parses Gemfeed according to the companion spec: gemini://gemini.circumlunar.space/docs/companion/subscription.gmi
 2package main
 3
 4import (
 5	"bufio"
 6	"fmt"
 7	"io"
 8	"os"
 9	"path/filepath"
10	"sort"
11	"strings"
12	"time"
13)
14
15type Gemfeed struct {
16	Title   string
17	Entries []*FeedEntry
18}
19
20type FeedEntry struct {
21	Title      string
22	Url        string
23	Date       time.Time
24	FeedTitle  string
25	DateString string
26}
27
28// TODO definitely cache this function -- it reads EVERY gemini file on flounder.
29func getAllGemfeedEntries() ([]*FeedEntry, error) {
30	var feedEntries []*FeedEntry
31	err := filepath.Walk(c.FilesDirectory, func(thepath string, info os.FileInfo, err error) error {
32		if isGemini(info.Name()) {
33			f, err := os.Open(thepath)
34			feed, err := ParseGemfeed(f)
35			if err == nil {
36				feedEntries = append(feedEntries, feed.Entries...)
37			}
38		}
39		return nil
40	})
41	if err != nil {
42		return nil, err
43	} else {
44		sort.Slice(feedEntries, func(i, j int) bool {
45			return feedEntries[i].Date.After(feedEntries[j].Date)
46		})
47		return feedEntries, nil
48	}
49}
50
51// Parsed Gemfeed text Returns error if not a gemfeed
52// Doesn't sort output
53// Doesn't get posts dated in the future
54func ParseGemfeed(text io.Reader) (*Gemfeed, error) {
55	scanner := bufio.NewScanner(text)
56	gf := Gemfeed{}
57	for scanner.Scan() {
58		line := scanner.Text()
59		if gf.Title == "" && strings.HasPrefix(line, "#") && !strings.HasPrefix(line, "##") {
60			gf.Title = strings.Trim(line[1:], " \t")
61		} else if strings.HasPrefix(line, "=>") {
62			link := strings.Trim(line[2:], " \t")
63			splits := strings.SplitN(link, " ", 2)
64			if len(splits) == 2 && len(splits[1]) >= 10 {
65				dateString := splits[1][:10]
66				date, err := time.Parse("2006-01-02", dateString)
67				if err == nil && time.Now().After(date) {
68					title := strings.Trim(splits[1][10:], " -\t")
69					fe := FeedEntry{title, splits[0], date, gf.Title, dateString}
70					gf.Entries = append(gf.Entries, &fe)
71				}
72			}
73		}
74	}
75	if len(gf.Entries) == 0 {
76		return nil, fmt.Errorf("No Gemfeed entries found")
77	}
78	return &gf, nil
79}