fast and minimal static site generator
ssg
at master 125 lines 2.9 kB view raw
1package atom 2 3import ( 4 "encoding/xml" 5 "fmt" 6 "net/url" 7 "path/filepath" 8 "time" 9 10 "tangled.sh/icyphox.sh/vite/config" 11 "tangled.sh/icyphox.sh/vite/types" 12) 13 14type AtomLink struct { 15 XMLName xml.Name `xml:"link"` 16 Href string `xml:"href,attr"` 17 Rel string `xml:"rel,attr,omitempty"` 18} 19 20type AtomSummary struct { 21 XMLName xml.Name `xml:"summary"` 22 Content string `xml:",chardata"` 23 Type string `xml:"type,attr"` 24} 25 26type AtomAuthor struct { 27 XMLName xml.Name `xml:"author"` 28 Name string `xml:"name"` 29 Email string `xml:"email"` 30} 31 32type AtomEntry struct { 33 XMLName xml.Name `xml:"entry"` 34 Title string `xml:"title"` 35 Updated string `xml:"updated"` 36 ID string `xml:"id"` 37 Link *AtomLink 38 Summary *AtomSummary 39} 40 41type AtomFeed struct { 42 XMLName xml.Name `xml:"feed"` 43 Xmlns string `xml:"xmlns,attr"` 44 Title string `xml:"title"` 45 Subtitle string `xml:"subtitle"` 46 ID string `xml:"id"` 47 Updated string `xml:"updated"` 48 Link *AtomLink 49 Author *AtomAuthor `xml:"author"` 50 Entries []AtomEntry 51} 52 53// Creates a new Atom feed. 54func NewAtomFeed(srcDir string, posts []types.Post) ([]byte, error) { 55 entries := []AtomEntry{} 56 57 for _, p := range posts { 58 dateStr := p.Meta["date"].(string) 59 date, err := time.Parse("2006-01-02", dateStr) 60 if err != nil { 61 return nil, err 62 } 63 rfc3339 := date.Format(time.RFC3339) 64 65 var summaryContent string 66 if subtitle, ok := p.Meta["subtitle"]; ok { 67 summaryContent = fmt.Sprintf("<h2>%s</h2>\n%s", 68 subtitle.(string), 69 string(p.Body)) 70 } else { 71 summaryContent = string(p.Body) 72 } 73 74 entry := AtomEntry{ 75 Title: p.Meta["title"].(string), 76 Updated: rfc3339, 77 // tag:icyphox.sh,2019-10-23:blog/some-post/ 78 ID: fmt.Sprintf( 79 "tag:%s,%s:%s", 80 config.Config.URL[8:], // strip https:// 81 dateStr, 82 filepath.Join(srcDir, p.Meta["slug"].(string)), 83 ), 84 Link: newAtomLink(config.Config.URL, srcDir, p.Meta["slug"].(string)), 85 Summary: &AtomSummary{ 86 Content: summaryContent, 87 Type: "html", 88 }, 89 } 90 entries = append(entries, entry) 91 } 92 93 // 2021-07-14T00:00:00Z 94 now := time.Now().Format(time.RFC3339) 95 feed := &AtomFeed{ 96 Xmlns: "http://www.w3.org/2005/Atom", 97 Title: config.Config.Title, 98 ID: config.Config.URL, 99 Subtitle: config.Config.Desc, 100 Link: &AtomLink{Href: config.Config.URL}, 101 Author: &AtomAuthor{ 102 Name: config.Config.Author.Name, 103 Email: config.Config.Author.Email, 104 }, 105 Updated: now, 106 Entries: entries, 107 } 108 109 feedXML, err := xml.MarshalIndent(feed, " ", " ") 110 if err != nil { 111 return nil, err 112 } 113 // Add the <?xml...> header. 114 return []byte(xml.Header + string(feedXML)), nil 115} 116 117func newAtomLink(base, subDir, slug string) *AtomLink { 118 baseURL, err := url.Parse(base) 119 if err != nil { 120 return nil 121 } 122 123 baseURL.Path = filepath.Join(subDir, slug) 124 return &AtomLink{Href: baseURL.String()} 125}