atom/atom.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
package atom import ( "bufio" "fmt" "log" "net/http" "os" "path/filepath" "sort" "strings" "time" ) const maxFeed = 10 var timeLayoutPost = "2006-01-02" var timeLayoutAtom = "2006-01-02T15:04:05.000Z" type post struct { title string updated string link string // starting with content disabled because a lot of my content is nonsensical // to any reasonable xml parser tbh // content string } func Handler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/atom+xml") posts, err := getPosts("thought/*") if err != nil { log.Println(err) } sort.Slice(posts, func(i, j int) bool { // we assume that timeLayoutAtom is correct here because // it was passed up correctly hopefully ti, _ := time.Parse(timeLayoutAtom, posts[i].updated) tj, _ := time.Parse(timeLayoutAtom, posts[j].updated) return ti.After(tj) }) if len(posts) > maxFeed { posts = posts[:maxFeed] } var updated string if len(posts) > 0 { updated = posts[0].updated } fmt.Fprintf(w, `<?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>j3s.sh</title> <link rel="self" href="https://j3s.sh/feed.atom" /> <link href="https://j3s.sh/" /> <updated>%s</updated> <author> <name>Jes Olson</name> </author> <id>https://j3s.sh/</id> `, updated) for _, p := range posts { // add content in future? idk prob not fmt.Fprintf(w, ` <entry> <title>%s</title> <link href="%s"/> <id>%s</id> <updated>%s</updated> </entry> `, p.title, p.link, p.link, p.updated) } fmt.Fprint(w, ` </feed>`) } func getPosts(dir string) ([]post, error) { var posts []post files, err := filepath.Glob(dir) if err != nil { return nil, err } for _, f := range files { post, err := fileToPost(f) if err != nil { // this can be failed intentionally for drafts or posts too small for rss updoots // add a print statement here if blog posts mysteriously vanish from the atom feed // // lmao continue } posts = append(posts, post) } return posts, err } func fileToPost(file string) (post, error) { var p post f, err := os.Open(file) if err != nil { return p, err } defer f.Close() scanner := bufio.NewScanner(f) scanner.Scan() // this moves to the next token // strip spaces title := scanner.Text() p.title = strings.TrimSpace(title) scanner.Scan() timestr := strings.TrimSpace(scanner.Text()) updated, err := time.Parse(timeLayoutPost, timestr) if err != nil { return p, err } // for scanner.Scan() { // p.content = p.content + scanner.Text() // } p.updated = updated.Format(timeLayoutAtom) p.link = "https://j3s.sh/" + file return p, err } |