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/build.go | 19 ++++++- internal/build/rss.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 internal/build/rss.go (limited to 'internal/build') diff --git a/internal/build/build.go b/internal/build/build.go index 743942b..721b568 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -6,6 +6,7 @@ import ( "log" "time" + "github.com/HimanshuSardana/kite/pkg/config" "github.com/HimanshuSardana/kite/pkg/content" "github.com/HimanshuSardana/kite/pkg/themes" ) @@ -43,6 +44,11 @@ func Build(opts BuildOptions) error { opts.ConfigPath = DefaultConfigPath } + cfg, err := config.Load(opts.ConfigPath) + if err != nil { + log.Printf("Warning: Could not load config: %v", err) + } + themePath := themes.GetThemePath(opts.ThemesDir, opts.ThemeName) files, err := content.ListContentFiles(opts.ContentDir) @@ -53,7 +59,7 @@ func Build(opts BuildOptions) error { summaries := make([]content.PostSummary, 0, len(files)) for _, file := range files { - fmt.Println("Processing:", file.Path) + start := time.Now() parsed, err := ParseMarkdown(file.Path) if err != nil { @@ -89,6 +95,9 @@ func Build(opts BuildOptions) error { if err := RenderPage(tmpl, outputPath, page); err != nil { log.Printf("Error rendering page: %v", err) } + + elapsed := time.Since(start).Milliseconds() + fmt.Printf("Compiling %s (%dms)\n", parsed.Frontmatter.Title, elapsed) } fmt.Println("All files processed!") @@ -97,6 +106,14 @@ func Build(opts BuildOptions) error { log.Printf("Error rendering home page: %v", err) } + siteURL := "https://your-site.com" + if cfg != nil && cfg.SiteURL != "" { + siteURL = cfg.SiteURL + } + if err := GenerateRSS(opts.OutputDir, opts.ConfigPath, siteURL, summaries); err != nil { + log.Printf("Error generating RSS feed: %v", err) + } + return nil } 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