Tom Willemse
ac9f751e69
The rss project also creates and updates the ‘index.org’ file that the posts project uses to export the index of blog posts.
180 lines
7 KiB
EmacsLisp
180 lines
7 KiB
EmacsLisp
;;; publish.el --- Publishing configuration for ryuslash.org -*- lexical-binding: t; -*-
|
||
|
||
;; Copyright (C) 2020 Tom Willemse
|
||
|
||
;; Author: Tom Willemse <tom@ryuslash.org>
|
||
;; Keywords:
|
||
;; Version: 1
|
||
;; Package-Requires: (dockerfile-mode htmlize org org-contrib rainbow-delimiters ox-rss)
|
||
|
||
;; 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 <https://www.gnu.org/licenses/>.
|
||
|
||
;;; Commentary:
|
||
|
||
;;
|
||
|
||
;;; Code:
|
||
|
||
(require 'dockerfile-mode)
|
||
(require 'ob-dot)
|
||
(require 'ox-publish)
|
||
(require 'ox-rss)
|
||
(require 'rainbow-delimiters)
|
||
(require 'subr-x)
|
||
|
||
(defconst publish-root
|
||
(file-name-directory
|
||
(or load-file-name
|
||
(buffer-file-name)))
|
||
"The directory where ‘oni-org’ was loaded from.")
|
||
|
||
(add-hook 'prog-mode-hook 'rainbow-delimiters-mode)
|
||
|
||
(defun publish-calculate-reading-time (buffer)
|
||
"Calculate the amount of minutes it would take to read the contents of BUFFER."
|
||
(with-current-buffer buffer
|
||
(max 1 (/ (count-words (point-min) (point-max)) 228))))
|
||
|
||
(defun publish-format-reading-time (time)
|
||
"Return a string describing TIME."
|
||
(format "%d minute%s"
|
||
time
|
||
(if (= time 1) "" "s")))
|
||
|
||
(defun publish-extract-summary-from-file (file props)
|
||
"Extract a summary from FILE.
|
||
PROPS is used as an aid in getting the right information from the file."
|
||
(format "* %s\n:PROPERTIES:\n:CUSTOM_ID: %s\n:PUBDATE: %s\n:RSS_PERMALINK: %s\n:END:\n\n%s\n\n[[file:%s][Read More]]\n\n"
|
||
(car (org-publish-find-property file :title props))
|
||
(file-name-nondirectory file)
|
||
(format-time-string "[%Y-%m-%d %a %H:%M]" (org-timestamp-to-time (car (org-publish-find-property file :date props))))
|
||
(file-name-nondirectory file)
|
||
(car (org-map-entries (lambda () (let ((element-data (cadr (org-element-at-point))))
|
||
(buffer-substring-no-properties
|
||
(map-elt element-data :contents-begin)
|
||
(map-elt element-data :contents-end))))
|
||
"summary"
|
||
(list file)))
|
||
(file-name-nondirectory file)))
|
||
|
||
(defun publish-get-latest-modified-time (files)
|
||
"Get the latest modification time of any file from the list FILES."
|
||
(car
|
||
(last
|
||
(sort (mapcar #'org-publish-cache-mtime-of-src files) #'time-less-p))))
|
||
|
||
(defun publish-time>= (a b)
|
||
"Check if time A is greater than or equal to time B."
|
||
(not (time-less-p a b)))
|
||
|
||
(defun publish-empty-time ()
|
||
"Get an empty time value."
|
||
(let ((current-time (current-time)))
|
||
(time-subtract current-time current-time)))
|
||
|
||
(defun publish-generate-index (props)
|
||
"Generate an index from my posts.
|
||
Argument PROPS
|
||
."
|
||
(let* ((index-file (expand-file-name "posts/index.org"))
|
||
(index-generated-time (or (and (file-exists-p index-file)
|
||
(org-publish-cache-mtime-of-src index-file))
|
||
(publish-empty-time)))
|
||
(files (directory-files "posts/" t (rx bos (= 8 digit) "-" (= 4 digit) "-" (one-or-more nonl) (not "~") eos)))
|
||
(latest-modification-time (publish-get-latest-modified-time files)))
|
||
(if (publish-time>= index-generated-time latest-modification-time)
|
||
(message "Not generating index...")
|
||
(progn
|
||
(message "Generating index...")
|
||
(with-temp-buffer
|
||
(insert "#+title: ryuslash's blog\n")
|
||
(insert "#+options: num:nil\n")
|
||
(insert "\n")
|
||
(apply 'insert
|
||
(mapcar (lambda (file) (publish-extract-summary-from-file file props))
|
||
(take 30 (reverse files))))
|
||
(write-file "posts/index.org"))))))
|
||
|
||
(setq org-export-exclude-tags '("noexport" "draft"))
|
||
|
||
(setq org-confirm-babel-evaluate nil)
|
||
|
||
(setq org-html-head-include-default-style nil)
|
||
|
||
(setq org-html-htmlize-output-type 'css)
|
||
|
||
(setq org-publish-timestamp-directory
|
||
(concat default-directory "/.org-timestamps/"))
|
||
|
||
(setq org-html-html5-fancy t)
|
||
|
||
(setq org-html-doctype "html5")
|
||
|
||
(setq org-publish-project-alist
|
||
`(("index"
|
||
:base-directory "."
|
||
:base-extension "org"
|
||
:publishing-directory "public/"
|
||
:recursive t
|
||
:exclude ,(rx string-start
|
||
(or "posts/"
|
||
(and "README.org" string-end)))
|
||
:publishing-function org-html-publish-to-html
|
||
:html-head "<link rel=\"stylesheet\" href=\"/assets/css/main.css\" type=\"text/css\"/>"
|
||
:html-postamble t
|
||
:html-postamble-format (("en" "<p class=\"social social-mastodon\">Find me on <a href=\"https://fosstodon.org/@ryuslash\" rel=\"me\">Mastodon</a></p>
|
||
<p class=\"date\">Date: %C</p>
|
||
<p class=\"creator\">%c</p>")))
|
||
("posts"
|
||
:base-directory "posts/"
|
||
:base-extension "org"
|
||
:publishing-directory "public/posts/"
|
||
:recursive t
|
||
:publishing-function org-html-publish-to-html
|
||
:html-head "<link rel=\"stylesheet\" href=\"/assets/css/main.css\" type=\"text/css\"/>"
|
||
:html-preamble (lambda (project)
|
||
(let ((buffer (find-file-noselect (buffer-file-name))))
|
||
(unless (member (car (org-publish-find-property (buffer-file-name) :title project))
|
||
'("ryuslash.org" "ryuslash's blog"))
|
||
(publish-format-reading-time
|
||
(publish-calculate-reading-time buffer))))))
|
||
("rss"
|
||
:base-directory "posts/"
|
||
:base-extension "org"
|
||
:rss-extension "xml"
|
||
:preparation-function publish-generate-index
|
||
:publishing-directory "public/posts/"
|
||
:publishing-function (org-rss-publish-to-rss)
|
||
:html-link-home "https://ryuslash.org/posts/"
|
||
:html-link-use-abs-url t
|
||
:section-numbers nil
|
||
:exclude ".*"
|
||
:include ("index.org")
|
||
:table-of-contents nil)
|
||
("assets"
|
||
:base-directory "."
|
||
:recursive t
|
||
:exclude "^public/"
|
||
:base-extension "svg\\|png\\|jpg"
|
||
:publishing-function org-publish-attachment
|
||
:publishing-directory "public/")
|
||
("all" :components ("index" "rss" "posts" "assets"))))
|
||
|
||
(defvar publish-feed-url-format
|
||
;"https://gitlab.com/ryuslash/ryuslash.org/-/commits/master/%s?feed_token=Rf8otgpS8YEiYakJN4NR&format=atom"
|
||
"https://code.ryuslash.org/new-ryuslash.org/atom/%s?h=master"
|
||
"Format string for the URL to the page’s atom feed.")
|
||
|
||
(provide 'publish)
|
||
;;; publish.el ends here
|