simplest rss without packages

This is a simple very simple follow-up from my previous post about generating a static website using Emacs. The only element really missing from the website was an RSS feed (which now exists and has a nifty icon at the bottom of the website!). I looked into options and it seemed like I could either use the sitemap org-publish can generate along with the third-party package ox-rss, but this already seemed overkill for something that is literally an acronym for "Really Simple Syndication". After reading the format specification (I recommend doing so, it is really a quite simple XML specification), I added the following code to build-site.el:

;; Fixing locale (for RSS)
(setq system-time-locale "C")

This is a small bit of code to fix the date-time locale POSIX, since my computer is Finnish and currently uses Finnish locale (which is normally fine by me, I'm training my Finnish so it's a good habit - but this messes up the publishing date for the RSS feed).

(defun generate-rss-items ()
  (let ((ret ""))
    (dolist (el (list-files-in-directory (concat project-root "org/posts/")))
      (let ((post-keywords (get-post-keywords el)) (link (concat "https://henriquelalves.com/posts/" (file-name-base el) ".html") ))
        (setq ret (concat
                   ret
                   "<item>\n"
                   "<title>" (cadr (assoc "TITLE" post-keywords)) "</title>\n"
                   "<link>" link "</link>\n"
                   "<pubDate>" (format-time-string "%a, %d %b %Y %H:%M:%S %z" (date-to-time (cadr (assoc "DATE" post-keywords)))) "</pubDate>\n"
                   "</item>\n"
                   )
              )))
    ret
    )
  )

This function is used to generate the individual items (blog posts) of the RSS feed. Each item consists of a title (the blog post title), a link (the complete website link), and a publishing date in RFC 822 format. The only tricky thing was converting the previous date format ("YYYY-MM-DD") to a date in RFC 822 format (on English locale, fixed by the code at the beginning). I found the solution by digging a little bit further from the Emacs documentation on time parsing to the libc documentation page on date formatting, where there is a reference for the formatting to RFC 822. So the following things are happening here:

  1. First, I get the element "DATE" from the post keywords alist. This is a string in the format of "YYYY-MM-DD".
  2. Convert the string to Lisp date time value, required by the format-time-string function.
  3. Use format-time-string with that lengthy parameter to convert to RFC 822 date time format.

The items are concatenated in a big string and then returned.

(defun generate-rss-content ()
  (concat
   "<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n"
   "<channel>\n"
   "<atom:link href=\"https://henriquelalves.com/rss.xml\" rel=\"self\" type=\"application/rss+xml\" />"
   "<title>henriquelalves.com blog posts</title>\n"
   "<link>https://henriquelalves.com/posts.html</link>\n"
   "<description>latest blog posts from henriquelalves.com</description>\n"
   (generate-rss-items)
   "</channel>\n"
   "</rss>"
   )
  )

This function generates the complete RSS file, concatenating the blog posts items in it. I'm only adding the properties that are absolutely necessary for the RSS feed to work on most apps, plus some bits advised by the RSS validator to make the file more compatible.

(defun generate-rss ()
  (with-temp-file (concat project-root "public/" "rss.xml") (insert (generate-rss-content))))

Finally, I have a method that saves the big generated RSS string into a file. I'm calling (generate-rss) after the website is built and static files added, so it's the last step in the site building.

It was honestly quite liberating to see a dumb problem, think "all other solutions look like overkill", and then making a much simpler solution myself. Those are the kinds of small victories I got while making the static website builder that made the whole process much more fun.