UP | HOME

用denote配合ox-publish导出博客

[2025-03-21 五 18:01]

之前写过一篇org-roam的相关教程:使用advice自动更新ox-publish的待发布org-roam文件目录。现在切换到了denote,有必要更新一下相关代码了。

直接使用denote时,可以把形如 [[denote:]] 的denote链接当作普通的 [[file:]] 链接。但是由于denote文件的文件名变化频繁,如果你和我一样选择通过网页手动上传导出的html文件到GitHub,则会遇见恼人的重复问题。另一方面,直接生成的文件链接也很长,很不直观。所以我们可以通过以下设置,将导出的文件名设置为denote标识符。

[2025-03-25 二 11:17]: 这个函数自定义涉及到了许多导出的方面,缺乏可维护性。如果没有执着需求,建议不修改该函数。

代码参考:使用 org-mode 写博客

1. 确定导出文件范围

(defun my/ox-files ()
  "Return a list of note files containing 'blog' tag."
  (denote-directory-files "_blog"))

2. 自定义导出配置

(defun my/org-project-update (&optional ARG PRED) ;;使用before会接收到原函数参数,因此需要添加optional
  (setq org-publish-project-alist
        `(("posts"
           ;; 帖子配置项,略去了其他无关选项
           :exclude ".*"
           :include ,(my/ox-files)
           :auto-sitemap t
           :html-link-home "index.html"
           :sitemap-filename "index.org"
           :sitemap-title "目录"
           :sitemap-format-entry my/org-publish-sitemap-format-entry
           )
          ("static"
           ;; 静态资源配置项,略去)
          ("rss"
           ;; rss配置项,略去了其他无关选项
           :exclude ".*"
           :include ,(my/ox-files)
           :publishing-function publish-posts-rss-feed
           :auto-sitemap t
           :sitemap-function posts-rss-feed
           :sitemap-format-entry format-posts-rss-feed-entry)
          ("personal-website" :components ("posts" "static" "rss")))))

;; 为了确保及时动态更新导出文件目录,需要在导出函数执行前重新赋值一次 org-publish-project-alist
(advice-add 'org-export-dispatch :before 'my/org-project-update)
  
;; 以下函数用于修改index.html/index.org的链接
(defun my/org-publish-sitemap-format-entry (entry style project)
  "格式化站点地图中的每个条目,显示标题、日期和摘要。"
  (let* ((title (or (org-publish-find-title entry project)
                        (file-name-base entry)))
         (id (denote-retrieve-filename-identifier (file-name-base entry))))
    (format "[[denote:%s][%s]]\n"
            id
            title)))

;; 以下函数用于修改rss.xml/rss.org的链接
(defun publish-posts-rss-feed (plist filename dir)
  "Publish PLIST to RSS when FILENAME is rss.org.
DIR is the location of the output."
  (if (equal "rss.org" (file-name-nondirectory filename))
      (org-rss-publish-to-rss plist filename dir)))

(defun format-posts-rss-feed-entry (entry _style project)
  "Format ENTRY for the posts RSS feed in PROJECT."
  (let* (
         (title (org-publish-find-title entry project))
         (link (concat (denote-retrieve-filename-identifier (file-name-sans-extension entry)) ".html"))
         (pubdate (format-time-string (car org-time-stamp-formats)
                                      (org-publish-find-date entry project))))
    (message pubdate)
    (format "%s
:properties:
:rss_permalink: %s
:pubdate: %s
:end:\n"
            title
            link
            pubdate)))

有了上述函数,导出denote文件为html时就可以用标识符作为文件名称了。

3. 修改导出链接处理函数

[2025-03-25 二 09:39]

(defun denote-link-ol-export (link description format)
  "Modified version of `denote-link-ol-export'.
Retrieve ID, replace anchor with it

Original docstring below:
Export a `denote:' link from Org files.
The LINK, DESCRIPTION, and FORMAT are handled by the export
backend."
  (let* ((path-id (denote-link--ol-resolve-link-to-target link :full-data))
         (path (file-relative-name (nth 0 path-id)))
         (id (nth 1 path-id))
         (query (nth 2 path-id))
         (anchor (file-name-sans-extension path))
         (desc (cond
                (description)
                (query (format "denote:%s::%s" id query))
                (t (concat "denote:" id)))))
    (cond
     ((eq format 'html)
      (if query
          (format "<a href=\"%s.html%s\">%s</a>" (denote-retrieve-filename-identifier anchor) query desc)
        (format "<a href=\"%s.html\">%s</a>" (denote-retrieve-filename-identifier anchor) desc)))
     ((eq format 'latex) (format "\\href{%s}{%s}" (replace-regexp-in-string "[\\{}$%&_#~^]" "\\\\\\&" path) desc))
     ((eq format 'texinfo) (format "@uref{%s,%s}" path desc))
     ((eq format 'ascii) (format "[%s] <denote:%s>" desc path))
     ((eq format 'md) (format "[%s](%s)" desc path))
     (t path))))

▲ 编辑于 [2025-03-25 二 11:17] | © Published by Emacs 31.0.50 (Org mode 9.7.26) on [2025-03-25 二 11:18] | RSS