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.pull/1/head
parent
3feec1a252
commit
eca0447a35
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>tilde.town blog</title>
|
||||
<description>web log of tilde town</description>
|
||||
<link>https://tilde.town/blog.html</link>
|
||||
<atom:link rel="self" type="application/rss+xml" href="https://tilde.town/blog.xml"/>
|
||||
{{ range .News }}
|
||||
<item>
|
||||
<title>{{.Title}}</title>
|
||||
<pubDate>{{.Pubdate}}</pubDate>
|
||||
<description>
|
||||
<![CDATA[{{.Content}}]]>
|
||||
</description>
|
||||
<guid isPermalink="false">{{.Pubdate}}-{{.Title}}</guid>
|
||||
</item>
|
||||
{{ end }}
|
||||
</channel>
|
||||
</rss>
|
|
@ -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/
|
||||
|
|
|
@ -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("<a href=\"/~%s\">*</a>", u.Username)
|
||||
} else if !u.Default {
|
||||
td.Lights += fmt.Sprintf("<a href=\"/~%s\">+</a>", 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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue