package main import ( "fmt" "net/http" "strings" "time" "github.com/gorilla/feeds" "github.com/russross/blackfriday/v2" ) func generateAtomFeed(w http.ResponseWriter, blogs []Blog, siteURL string) { feed := &feeds.Feed{ Title: "Spitfire News", Link: &feeds.Link{Href: siteURL}, Description: "Blog about Spitfire browser news/updates.", // Blog subtitle (Atom uses "subtitle" for description) Author: &feeds.Author{Name: "Internet Addict", Email: "noone@none.no"}, Created: time.Now(), } // Add self link feed.Link = &feeds.Link{Href: fmt.Sprintf("%s/rss", siteURL), Rel: "self"} for _, blog := range blogs { for _, entry := range blog.Entries { // Convert Markdown content to HTML htmlContent := blackfriday.Run([]byte(entry.Content)) // Ensure all image paths are absolute URLs (Idiot proofing) absoluteContent := strings.ReplaceAll(string(htmlContent), "src=\"/", fmt.Sprintf("src=\"%s/", siteURL)) // Ensure unique and stable ID entryID := fmt.Sprintf("%s/%s/%d", siteURL, blog.Name, entry.Number) // Create a summary if needed (using the first 200 characters of the content, for example) summary := entry.Description if summary == "" { if len(entry.Content) > 200 { summary = entry.Content[:200] + "..." } else { summary = entry.Content } } feed.Items = append(feed.Items, &feeds.Item{ Title: entry.Title, Link: &feeds.Link{Href: entryID, Rel: "alternate"}, Description: summary, // This can be used as the summary Author: &feeds.Author{Name: entry.Author}, Id: entryID, Updated: entry.Date, Content: absoluteContent, }) } } // Generate Atom feed with the correct content-type and charset w.Header().Set("Content-Type", "application/atom+xml; charset=UTF-8") atom, err := feed.ToAtom() if err != nil { http.Error(w, "Error generating Atom feed", http.StatusInternalServerError) return } w.Write([]byte(atom)) } func generateBlogAtomFeed(w http.ResponseWriter, blog Blog, siteURL string) { feed := &feeds.Feed{ Title: blog.Name, Link: &feeds.Link{Href: fmt.Sprintf("%s/%s", siteURL, blog.Name)}, Description: blog.Name, // Blog subtitle (Atom uses "subtitle" for description) Author: &feeds.Author{Name: "Internet Addict", Email: "noone@none.no"}, Created: time.Now(), } // Add self link feed.Link = &feeds.Link{Href: fmt.Sprintf("%s/%s/rss", siteURL, blog.Name), Rel: "self"} for _, entry := range blog.Entries { // Convert Markdown content to HTML htmlContent := blackfriday.Run([]byte(entry.Content)) // Ensure all image paths are absolute URLs (Idiot proofing) absoluteContent := strings.ReplaceAll(string(htmlContent), "src=\"/", fmt.Sprintf("src=\"%s/", siteURL)) // Ensure unique and stable ID entryID := fmt.Sprintf("%s/%s/%d", siteURL, blog.Name, entry.Number) // Create a summary if needed (using the first 200 characters of the content, for example) summary := entry.Description if summary == "" { if len(entry.Content) > 200 { summary = entry.Content[:200] + "..." } else { summary = entry.Content } } feed.Items = append(feed.Items, &feeds.Item{ Title: entry.Title, Link: &feeds.Link{Href: entryID, Rel: "alternate"}, Description: summary, // This can be used as the summary Author: &feeds.Author{Name: entry.Author}, Id: entryID, Updated: entry.Date, Content: absoluteContent, }) } // Generate Atom feed with the correct content-type and charset w.Header().Set("Content-Type", "application/atom+xml; charset=UTF-8") atom, err := feed.ToAtom() if err != nil { http.Error(w, "Error generating Atom feed", http.StatusInternalServerError) return } w.Write([]byte(atom)) }