From eca0447a350f28d3ee52de59416400e369669426 Mon Sep 17 00:00:00 2001 From: Case Date: Thu, 8 Sep 2022 22:57:19 -0500 Subject: [PATCH] Add feed generating capabilities `feed.tmpl.xml` should be RSS2.0-conforming. Ideally each news item would have a date of publication, but RSS doesn't require it. I found it easier to copy `genblog.go` to `genfeed.go` than to shoehorn in feed logic to the blog generator. As such, `genfeed.go` might have some unnecessary stuff in it (though the go compiler didn't complain, so who knows?!). I also added the necessary machinery in `generate_homepage`. Of course, I did very minimal testing. --- feed.tmpl.xml | 19 ++++++++ generate_homepage | 3 +- genfeed.go | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 feed.tmpl.xml create mode 100644 genfeed.go diff --git a/feed.tmpl.xml b/feed.tmpl.xml new file mode 100644 index 0000000..bedddb2 --- /dev/null +++ b/feed.tmpl.xml @@ -0,0 +1,19 @@ + + + + tilde.town blog + web log of tilde town + https://tilde.town/blog.html + + {{ range .News }} + + {{.Title}} + {{.Pubdate}} + + + + {{.Pubdate}}-{{.Title}} + + {{ end }} + + diff --git a/generate_homepage b/generate_homepage index 6344b92..6dec788 100644 --- a/generate_homepage +++ b/generate_homepage @@ -6,5 +6,6 @@ set -e cd /town/src/tilde.town /usr/bin/go run genblog.go > blog.html +/usr/bin/go run genfeed.go > blog.xml /usr/bin/go run genusers.go > users.html -/bin/cp index.html blog.html users.html blog.css style.css /var/www/tilde.town/ +/bin/cp index.html blog.html blog.xml users.html blog.css style.css /var/www/tilde.town/ diff --git a/genfeed.go b/genfeed.go new file mode 100644 index 0000000..1ed8e08 --- /dev/null +++ b/genfeed.go @@ -0,0 +1,121 @@ +package main + +import ( + "bytes" + _ "embed" + "encoding/json" + "fmt" + "os" + "os/exec" + "sort" + "text/template" +) + +const statsPath = "/usr/local/bin/stats" + +//go:embed feed.tmpl.xml +var feedTmpl string + +type newsEntry struct { + Title string // Title of entry + Pubdate string // Human readable date + Content string // HTML of entry +} + +type User struct { + Username string + Default bool +} + +type tildeData struct { + News []newsEntry + Users []User + ActiveUsers []string `json:"active_users"` +} + +type ByName []User + +func (n ByName) Len() int { return len(n) } +func (n ByName) Swap(i, j int) { n[i], n[j] = n[j], n[i] } +func (n ByName) Less(i, j int) bool { return n[i].Username < n[j].Username } + +func _main() error { + data, err := stats() + if err != nil { + return err + } + + type tmplData struct { + News []newsEntry + Lights string + } + + td := &tmplData{ + News: data.News, + Lights: "", + } + + sort.Sort(ByName(data.Users)) + + isActive := func(username string) bool { + for _, u := range data.ActiveUsers { + if u == username { + return true + } + } + + return false + } + + for _, u := range data.Users { + if isActive(u.Username) { + td.Lights += fmt.Sprintf("*", u.Username) + } else if !u.Default { + td.Lights += fmt.Sprintf("+", u.Username) + } else { + td.Lights += "." + } + } + + t, err := template.New("feed").Parse(feedTmpl) + if err != nil { + return fmt.Errorf("failed to parse the feed template: %w", err) + } + + out := bytes.Buffer{} + if err = t.Execute(&out, td); err != nil { + return fmt.Errorf("failed to render feed template: %w", err) + } + + fmt.Println(out.String()) + + return nil +} + +func stats() (*tildeData, error) { + sout := bytes.Buffer{} + cmd := exec.Command(statsPath) + cmd.Stdout = &sout + + err := cmd.Run() + if err != nil { + return nil, err + } + + var data tildeData + + err = json.Unmarshal(sout.Bytes(), &data) + if err != nil { + return nil, err + } + + return &data, nil +} + +func main() { + err := _main() + if err != nil { + fmt.Fprintf(os.Stderr, "error: %s\n", err) + os.Exit(1) + } +}