From 2e544388bf3f51c9406e9141375aa027acca165e Mon Sep 17 00:00:00 2001 From: Himanshu Sardana Date: Thu, 26 Mar 2026 22:53:22 +0000 Subject: feat: add rss feed generation feat: add siteurl to config --- internal/build/rss.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 internal/build/rss.go (limited to 'internal/build/rss.go') diff --git a/internal/build/rss.go b/internal/build/rss.go new file mode 100644 index 0000000..ad22615 --- /dev/null +++ b/internal/build/rss.go @@ -0,0 +1,129 @@ +package build + +import ( + "fmt" + "os" + "time" + + "github.com/HimanshuSardana/kite/pkg/config" + "github.com/HimanshuSardana/kite/pkg/content" +) + +type RSSItem struct { + Title string + Link string + Date string + Content string +} + +type RSSFeed struct { + Title string + Link string + Description string + Items []RSSItem +} + +func GenerateRSS(outputDir, configPath, siteURL string, posts []content.PostSummary) error { + if configPath == "" { + configPath = "config.yaml" + } + + cfg, err := config.Load(configPath) + if err != nil { + return fmt.Errorf("loading config: %w", err) + } + + feed := RSSFeed{ + Title: cfg.SiteTitle, + Link: siteURL, + Description: cfg.AuthorBio, + Items: make([]RSSItem, 0, len(posts)), + } + + for _, post := range posts { + dateStr := post.Date + var pubDate time.Time + + if t, err := time.Parse("2006-01-02", post.Date); err == nil { + pubDate = t + dateStr = pubDate.Format(time.RFC1123) + } else if t, err := time.Parse("Jan 2006", post.Date); err == nil { + pubDate = t + dateStr = pubDate.Format(time.RFC1123) + } + + feed.Items = append(feed.Items, RSSItem{ + Title: post.Title, + Link: fmt.Sprintf("%s/%s/", siteURL, post.Slug), + Date: dateStr, + Content: fmt.Sprintf("Read more at %s/%s/", siteURL, post.Slug), + }) + } + + rssContent := renderRSS(feed) + + feedPath := "feed.xml" + if outputDir != "" && outputDir != "." { + feedPath = outputDir + "/feed.xml" + } + + if err := os.WriteFile(feedPath, []byte(rssContent), 0644); err != nil { + return fmt.Errorf("writing feed: %w", err) + } + + fmt.Println("Feed written to", feedPath) + return nil +} + +func renderRSS(feed RSSFeed) string { + updated := time.Now().Format(time.RFC1123) + + s := ` + + + ` + escapeXML(feed.Title) + ` + ` + escapeXML(feed.Link) + ` + ` + escapeXML(feed.Description) + ` + en-us + ` + updated + ` + +` + + for _, item := range feed.Items { + s += ` + ` + escapeXML(item.Title) + ` + ` + escapeXML(item.Link) + ` + ` + escapeXML(item.Link) + ` + ` + item.Date + ` + ` + escapeXML(item.Content) + ` + +` + } + + s += ` +` + + return s +} + +func escapeXML(s string) string { + s = replaceAll(s, "&", "&") + s = replaceAll(s, "<", "<") + s = replaceAll(s, ">", ">") + s = replaceAll(s, "\"", """) + s = replaceAll(s, "'", "'") + return s +} + +func replaceAll(s, old, new string) string { + result := "" + for i := 0; i < len(s); i++ { + if i+len(old) <= len(s) && s[i:i+len(old)] == old { + result += new + i += len(old) - 1 + } else { + result += string(s[i]) + } + } + return result +} -- cgit v1.3.1