Skip to content

Instantly share code, notes, and snippets.

@alexispurslane
Last active December 22, 2024 23:01
Show Gist options
  • Save alexispurslane/1ccb7602ade4e209b2c0c54fbde8ccdd to your computer and use it in GitHub Desktop.
Save alexispurslane/1ccb7602ade4e209b2c0c54fbde8ccdd to your computer and use it in GitHub Desktop.
Generate a full-content RSS feed from an org-mode sitemap, so you can org-publish your blog properly
;;; org-rss-from-sitemap.el --- Generate a full-content RSS feed from an org-publish sitemap -*- lexical-binding: t -*-
;; Author: Alexis Purslane <alexispurlsane@pm.me>
;; This file is not part of GNU Emacs.
;; Copyright (c) by Alexis Purslane 2024.
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Pretty simple, does what it says on the tin. This is a special
;; `org-publish` `:publishing-function' that takes one or more
;; sitemaps and uses the links in them to generate an RSS feed
;; containing not just the links, but the full content of the
;; HTML files corresponding to the org files linked in the
;; sitemap. Proper usage:
;;
;; (add-to-list 'org-publish-project-alist '("neonvagabond-rss"
;; :base-directory ,(concat quake-org-home-directory "blog/")
;; :base-extension "org"
;; :recursive nil
;; :publishing-directory ,website-publish-dir
;; :exclude ".*"
;; :include ("index.org")
;; :publishing-function user/publish-sitemap-to-rss))
;;
;; NOTE: since this function assumes a pre-existing sitemap and
;; pre-existing HTML files corresponding to all of the org files
;; the sitemap references, it requires you to have a separate
;; `org-publish' project already for your actual posts. This is
;; then an additional system.
;;
;; I created this because ox-rss is unmaintained and doesn't work
;; with modern org anymore, and as a result all the other
;; tutorials and techniques for turning separate post-files in
;; org into an RSS feed don't work.
;;; Code:
(defun user/publish-sitemap-to-rss (plist filename pub-dir)
"Take an `org-publish' sitemap in FILENAME and create an RSS XML
feed for it in PUB-DIR using PLIST for project settings.
Assumes the global variable `website-url' refers to your eventual
website URL, the one you want to publish this to."
(with-temp-buffer
(insert-file-contents filename)
(let ((title (org-get-title (current-buffer)))
(items (org-element-map (org-element-parse-buffer) 'link
(lambda (link)
(let* ((path (org-element-property :path link))
(filename (file-name-sans-extension path))
(url (concat website-url (concat filename ".html")))
(title (buffer-substring-no-properties (org-element-property :contents-begin link)
(org-element-property :contents-end link))))
(when (and (eq (car link) 'link)
(string= (org-element-property :type link) "file"))
(message "Creating RSS item for %s"
(file-name-concat (plist-get plist :base-directory)
(concat filename ".org")))
`(item nil
(link nil ,url)
(guid nil ,url)
(title nil ,title)
(description nil ,(with-temp-buffer
(insert-file-contents (file-name-concat
pub-dir
(concat filename ".html")))
(let ((content (dom-by-id (libxml-parse-html-region) "content")))
(erase-buffer)
(insert "<![CDATA[")
(dom-print content)
(insert "]]>"))
(buffer-string))))))))))
(erase-buffer)
(dom-print `(rss nil
(channel nil
(title nil ,title)
(link nil ,website-url)
,@items))
nil
t))
(write-file (file-name-concat pub-dir "rss.xml"))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment