diff options
| -rw-r--r-- | ennum.el | 245 |
1 files changed, 173 insertions, 72 deletions
diff --git a/ennum.el b/ennum.el index b58a205..7cdf374 100644 --- a/ennum.el +++ b/ennum.el @@ -1,5 +1,6 @@ ;; -*- lexical-binding: t -*- +(require 'ennum-gemini) (require 'ennum-html) (require 'ennum-image) (require 'ennum-link) @@ -32,10 +33,16 @@ this path. `:output-directory' -Path to output directory. All output paths (`:atom-feed-file', +Path to output HTML directory. All output paths (`:atom-feed-file', `:tag-directory', etc.) are interpreted relative to `:output-directory'. +`:output-gemini-directory' + +Path to output gemini directory. All output paths (`:posts-directory', +`:tag-directory', etc.) are interpreted relative to +`:output-gemini-directory'. + `:posts-directory' Source directory with blog posts to publish. All posts in this @@ -507,19 +514,27 @@ output." (file-name-as-directory (expand-file-name directory))) files)))) -(defun ennum--org-output-filename (filename) - (concat (file-name-sans-extension filename) ".html")) +(defun ennum--export-extension (backend) + (pcase backend + ((or 'ennum-html 'html) "html") + ((or 'ennum-gemini 'gemini) "gmi") + (_ (error "Unrecognized backend %s" backend)))) -(defun ennum-export-post (post interned-org-file &optional output-html-file body-only) - "Export INTERNED-ORG-FILE of POST to OUTPUT-HTML-FILE using the -ennum-html backend. INTERNED-ORG-FILE must be an org file -interned into the ennum store. +(defun ennum--org-output-filename (backend filename) + (concat (file-name-sans-extension filename) + "." + (ennum--export-extension backend))) + +(defun ennum-export-post (post interned-org-file backend &optional output-file body-only) + "Export INTERNED-ORG-FILE of POST to OUTPUT-FILE using +BACKEND. INTERNED-ORG-FILE must be an org file interned into the ennum +store. When optional argument BODY-ONLY is non-nil, only return body code, without surrounding template. See `org-export-as'. -When optional argument OUTPUT-HTML-FILE is nil, return exported -result as a string." +When optional argument OUTPUT-FILE is nil, return exported result as a +string." (let ((system-time-locale (map-elt (ennum-setting :locale-alist) (ennum-post-language post))) (ext-plist (list :ennum-post post))) @@ -542,19 +557,21 @@ result as a string." (ennum-setting :open-graph-fallback-image)))))) (ennum-with-file-contents interned-org-file (cond - (output-html-file - (ennum-mkdir-p (file-name-directory output-html-file)) - (org-export-to-file 'ennum-html output-html-file nil nil nil body-only ext-plist)) - (t (org-export-as 'ennum-html nil nil body-only ext-plist))))))) + (output-file + (ennum-mkdir-p (file-name-directory output-file)) + (org-export-to-file backend output-file nil nil nil body-only ext-plist)) + (t (org-export-as backend nil nil body-only ext-plist))))))) -(defun ennum-publish-post (post) +(defun ennum-publish-post (backend post) (let ((interned-org-file (ennum-intern (ennum-post-filename post)))) (append (list (ennum-exp (ennum-export-post post interned-org-file - (ennum--org-output-filename (ennum-post-filename post))))) + backend + (ennum--org-output-filename + backend (ennum-post-filename post))))) (when (ennum-post-tangle post) (list (ennum-exp @@ -570,23 +587,25 @@ result as a string." (ennum-copy interned-org-file post-file-copy) (org-babel-tangle-file post-file-copy)) (delete-file post-file-copy)))))) - (seq-mapcat 'ennum-publish-link (ennum-post-links post))))) + (seq-mapcat (apply-partially 'ennum-publish-link + backend) + (ennum-post-links post))))) -(defun ennum-publish-generic (other-files-directory file) +(defun ennum-publish-generic (other-files-directory backend file) (let ((interned-file (ennum-intern (ennum--file-join other-files-directory file)))) (ennum-exp (let ((output-file (pcase (file-name-extension file) - ("org" (ennum--org-output-filename file)) + ("org" (ennum--org-output-filename backend file)) (_ file)))) (pcase (file-name-extension interned-file) ("org" (when (file-name-directory output-file) (ennum-mkdir-p (file-name-directory output-file))) (ennum-with-file-contents interned-file - (org-export-to-file 'html output-file))) + (org-export-to-file backend output-file))) (_ (ennum-copy interned-file output-file))))))) (defun ennum-video-poster (video) @@ -613,68 +632,98 @@ result as a string." (concat filename-prefix extension)) tongue))) -(defun ennum-publish-index-page (filename-prefix title last-page posts page-number tongue output-file) +(defun ennum-publish-index-page (backend filename-prefix title last-page posts page-number tongue output-file) (ennum-exp (let ((system-time-locale (map-elt (ennum-setting :locale-alist) tongue))) (when (file-name-directory output-file) (ennum-mkdir-p (file-name-directory output-file))) - (with-temp-buffer - (insert (format "#+TITLE: %s\n" title)) - (insert (format "#+LANGUAGE: %s\n" tongue)) - (insert "#+OPTIONS: num:nil toc:nil\n\n") - (dolist (post posts) - (insert (format "* [[post:%s][%s]]\n" - (ennum-post-slug post) - (ennum-post-title post))) - (insert (format-time-string "/%b %e, %Y/\n\n" (ennum-post-date post))) - (when-let ((thumbnail (ennum-post-thumbnail post))) - (insert (format "[[thumbnail:%s]]\n\n" thumbnail))) - (when-let ((summary (ennum-post-summary post))) - (insert summary) - (insert "\n\n")) - (when-let ((tags (ennum-post-tags post))) - (insert "Tags: ") - (insert - (string-join - (seq-map (lambda (tag) - (format "[[tag:%s][%s]]" (ennum-add-tongue-suffix tag tongue) tag)) - tags) - ", ")) - (insert "\n\n"))) - (unless (= page-number 1) - (insert (format "[[./%s][Newer posts]]\n\n" - (ennum-index-filename (file-name-nondirectory filename-prefix) - tongue nil (1- page-number))))) - (unless last-page - (insert (format "[[./%s][Older posts]]\n" - (ennum-index-filename (file-name-nondirectory filename-prefix) - tongue nil (1+ page-number))))) - (org-export-to-file 'html output-file))))) - -(defun ennum-publish-index-home (first-index-page-output filename-prefix tongue) + (pcase backend + ('html + (with-temp-buffer + (insert (format "#+TITLE: %s\n" title)) + (insert (format "#+LANGUAGE: %s\n" tongue)) + (insert "#+OPTIONS: num:nil toc:nil\n\n") + (dolist (post posts) + (insert (format "* [[post:%s][%s]]\n" + (ennum-post-slug post) + (ennum-post-title post))) + (insert (format-time-string "/%b %e, %Y/\n\n" (ennum-post-date post))) + (when-let ((thumbnail (ennum-post-thumbnail post))) + (insert (format "[[thumbnail:%s]]\n\n" thumbnail))) + (when-let ((summary (ennum-post-summary post))) + (insert summary) + (insert "\n\n")) + (when-let ((tags (ennum-post-tags post))) + (insert "Tags: ") + (insert + (string-join + (seq-map (lambda (tag) + (format "[[tag:%s][%s]]" (ennum-add-tongue-suffix tag tongue) tag)) + tags) + ", ")) + (insert "\n\n"))) + (unless (= page-number 1) + (insert (format "[[./%s][Newer posts]]\n\n" + (ennum-index-filename (file-name-nondirectory filename-prefix) + tongue nil (1- page-number))))) + (unless last-page + (insert (format "[[./%s][Older posts]]\n" + (ennum-index-filename (file-name-nondirectory filename-prefix) + tongue nil (1+ page-number))))) + (org-export-to-file backend output-file))) + ('gemini + (with-temp-file output-file + (insert (format "# %s\n\n" title)) + (dolist (post posts) + (insert (format "=> %s.gmi %s: %s\n\n" + (url-encode-url + (expand-file-name* (ennum-post-slug post) + (ennum-setting :posts-directory))) + (format-time-string "%b %e, %Y" + (ennum-post-date post)) + (ennum-post-title post))) + (when-let ((summary (ennum-post-summary post))) + (insert summary) + (insert "\n\n"))) + (unless (= page-number 1) + (insert (format "=> ./%s.gmi Newer posts\n" + (ennum-index-filename (file-name-nondirectory filename-prefix) + tongue nil (1- page-number))))) + (unless last-page + (insert (format "=> ./%s.gmi Older posts\n" + (ennum-index-filename (file-name-nondirectory filename-prefix) + tongue nil (1+ page-number))))))))))) + +(defun ennum-publish-index-home (first-index-page-output backend filename-prefix tongue) (ennum-exp (lambda (first-index-page-output) - (ennum-copy (ennum--file-join first-index-page-output - (ennum-index-filename filename-prefix tongue "html" 1)) - (ennum-add-tongue-suffix (format "%s.html" filename-prefix) tongue))) + (let ((extension (ennum--export-extension backend))) + (ennum-copy (ennum--file-join first-index-page-output + (ennum-index-filename filename-prefix + tongue + extension + 1)) + (ennum-add-tongue-suffix (format "%s.%s" filename-prefix extension) + tongue)))) first-index-page-output)) -(defun ennum-publish-index (filename-prefix title posts-per-page tongue posts) +(defun ennum-publish-index (backend filename-prefix title posts-per-page tongue posts) (let* ((number-of-pages (ceiling (length posts) posts-per-page)) (page-numbers (number-sequence 1 number-of-pages)) (output-files (seq-map (apply-partially - 'ennum-index-filename filename-prefix tongue "html") + 'ennum-index-filename filename-prefix tongue + (ennum--export-extension backend)) page-numbers)) (outputs (seq-mapn (lambda (post page-number output-file) (ennum-publish-index-page - filename-prefix title + backend filename-prefix title (= page-number number-of-pages) post page-number tongue output-file)) (seq-partition posts posts-per-page) page-numbers output-files))) - (cons (ennum-publish-index-home (seq-first outputs) filename-prefix tongue) + (cons (ennum-publish-index-home (seq-first outputs) backend filename-prefix tongue) outputs))) (defun ennum--absolute-uri (path) @@ -720,7 +769,7 @@ result as a string." (defun ennum--feed-entry (post interned-post-file) (let ((link (url-encode-url (ennum--absolute-uri (ennum--org-output-filename - (ennum-post-filename post)))))) + 'ennum-html (ennum-post-filename post)))))) `(entry (id ,link) (title :xml:lang ,(ennum-post-language post) ,(ennum-post-title post)) (updated ,(ennum--atom-date (ennum-post-date post))) @@ -729,7 +778,7 @@ result as a string." (name ,(ennum-post-author post)) (email ,user-mail-address)))) (content :type "html" :xml:lang ,(ennum-post-language post) - ,(ennum-export-post post interned-post-file nil t)) + ,(ennum-export-post post interned-post-file 'ennum-html nil t)) (summary :xml:lang ,(ennum-post-language post) ,(ennum-post-summary post)) (link :rel "alternate" :href ,link) @@ -739,9 +788,9 @@ result as a string." (defun ennum-setting (property) (pcase property ((or :blog-domain :blog-license :blog-title - :images-directory :output-directory :posts-directory - :static-directory :videos-directory :working-directory - :open-graph-fallback-image) + :images-directory :output-directory :output-gemini-directory + :posts-directory :static-directory :videos-directory + :working-directory :open-graph-fallback-image) (or (plist-get ennum-blog property) (user-error "Property %s not defined" property))) ((or :atom-feed-number-of-posts :atom-feed-file @@ -845,14 +894,15 @@ recognized as a directory, it should end in a slash. See (ennum-intern (ennum--file-join (ennum-setting :images-directory) path)))) -(defun ennum-publish-link (link) +(defun ennum-publish-link (backend link) (pcase (ennum-link-type link) ('image (seq-map (lambda (width) (ennum-publish-image (ennum--find-image (ennum-link-path link)) width)) - (list (ennum-setting :image-width) - (ennum-setting :image-link-width)))) + (cons (ennum-setting :image-link-width) + (and (eq backend 'ennum-html) + (list (ennum-setting :image-width)))))) ((or 'pdf 'static) (list (ennum-publish-copy @@ -913,7 +963,9 @@ as keys. Keys are compared using `equal'." (ennum-store-item-union (append ;; Publish posts - (seq-mapcat 'ennum-publish-post posts) + (seq-mapcat (apply-partially 'ennum-publish-post + 'ennum-html) + posts) ;; Publish feeds (seq-map (pcase-lambda (`(,tongue . ,posts)) @@ -927,7 +979,7 @@ as keys. Keys are compared using `equal'." ;; Publish indices (seq-mapcat (pcase-lambda (`(,tongue . ,posts)) - (ennum-publish-index "index" blog-title posts-per-page tongue posts)) + (ennum-publish-index 'html "index" blog-title posts-per-page tongue posts)) (seq-group-by 'ennum-post-language posts)) ;; Publish tag indices (seq-mapcat @@ -935,6 +987,7 @@ as keys. Keys are compared using `equal'." (seq-mapcat (pcase-lambda (`(,tongue . ,posts)) (ennum-publish-index + 'html (ennum--file-join (ennum-setting :tag-directory) tag) tag posts-per-page tongue posts)) (seq-group-by 'ennum-post-language posts))) @@ -945,7 +998,9 @@ as keys. Keys are compared using `equal'." (ennum-setting :image-thumbnail-width))) (ennum--filter-map 'ennum-post-thumbnail posts)) ;; Publish other files - (seq-map (apply-partially 'ennum-publish-generic other-files-directory) + (seq-map (apply-partially 'ennum-publish-generic + other-files-directory + 'html) (ennum-with-current-directory (ennum-setting :other-files-directory) (ennum-directory-files))) (ennum-setting :other-items))))) @@ -957,6 +1012,52 @@ as keys. Keys are compared using `equal'." (ennum-setting :output-directory)) (message "Ennum published to %s" (expand-file-name (ennum-setting :output-directory)))))) +(defun ennum-gemini-publish () + (interactive) + (ennum-with-current-directory (ennum-setting :working-directory) + (let* ((blog-title (ennum-setting :blog-title)) + (posts (ennum-posts (ennum-setting :posts-directory))) + (posts-per-page (ennum-setting :index-posts-per-page)) + (other-files-directory (ennum-setting :other-files-directory)) + (result + (ennum-store-item-union + (append + ;; Publish posts + (seq-mapcat (apply-partially 'ennum-publish-post + 'ennum-gemini) + posts) + ;; Publish indices + (seq-mapcat + (pcase-lambda (`(,tongue . ,posts)) + (ennum-publish-index 'gemini "index" blog-title posts-per-page tongue posts)) + (seq-group-by 'ennum-post-language posts)) + ;; Publish tag indices + (seq-mapcat + (pcase-lambda (`(,tag . ,posts)) + (seq-mapcat + (pcase-lambda (`(,tongue . ,posts)) + (ennum-publish-index + 'gemini + (ennum--file-join (ennum-setting :tag-directory) tag) + tag posts-per-page tongue posts)) + (seq-group-by 'ennum-post-language posts))) + (ennum-many-to-many-group-by 'ennum-post-tags posts)) + ;; Publish other files + (seq-map (apply-partially 'ennum-publish-generic + other-files-directory + 'gemini) + (ennum-with-current-directory (ennum-setting :other-files-directory) + (ennum-directory-files))) + (ennum-setting :other-items))))) + ;; Replace old output directory + (when (file-exists-p (ennum-setting :output-gemini-directory)) + (ennum--set-file-modes-recursively (ennum-setting :output-gemini-directory) + #o755 #o644 #o755) + (delete-directory (ennum-setting :output-gemini-directory) t)) + (copy-directory (ennum-eval result) + (ennum-setting :output-gemini-directory)) + (message "Ennum published to %s" (expand-file-name (ennum-setting :output-gemini-directory)))))) + ;;; Server ;;; ;;; Test HTTP server to serve the blog locally |
