happy hacking emacs!

首页   归档   分类   关于   留言  

自动生成org blog摘要页

分类: 博客 · 字数: 806 · ...

博客摘要页面可以让读者快速了解文章的大概信息,因此一般将它作为博客首页,其重要性不言而喻。摘要页的主要信息包括:标题,摘要,日期,分类等。每篇文章都手动输入这些文字太麻烦,于是我用elisp自动生成博客摘要页。

先来看看折腾的效果:

post-digest-page.png

由于摘要页对排版有一定的要求,所以纯orgMode导出不能满足需求,我采取的办法是在orgMode中直接插入html。和Markdown不同,orgMode中插入html需要将代码包裹在 #+begin_export html#+end_export 之间。

从上图看出,每篇文章的html代码有相同的格式:

<div class="post-div">
  <h3><a href="post-url">title</a></h3>
  <p>
    digest......
    <a href="post-url">阅读全文</a>
  </p>
  <code><a href="category-url">category</a></code>
  <span>date</span>
</div>

接下来,需要使用elisp获取org文章目录下所有文章名,根据文章名获取每篇文章的 title digest date category post-url category-url 信息,使用我自己写的 print-html 函数生成上面的html,并把相关变量插入html中。最后输出到 index.org 的html导出模块中。代码如下:

(require 'print-html)

(defvar blog-root-dir "~/iCloud/blog_site/")
(defvar blog-post-dir "~/iCloud/blog_site/org/")
(defvar blog-html-dir "~/iCloud/blog_site/post/")
(defvar blog-page-dir "~/iCloud/blog_site/page/")
(defvar blog-site-domain "https://blog.geekinney.com/")

(defun list-car-string-less (list1 list2)
  "compare the car of list1 to list2, which is a string"
  (if (string< (car list1) (car list2))
      (eq t t)
    (eq t nil)))

(defun my/blog-posts-sorted-by-date ()
  "make all posts name a list by date"
  (interactive)
  (let ((post-files (cdr (cdr (directory-files blog-post-dir))))
	(date-post-list '())
	(post-list '()))
    (mapcar (lambda (post)
	      (with-temp-buffer
		(insert-file-contents (concat blog-post-dir post))
		(goto-char (point-min))
		(re-search-forward "^#\\+DATE")
		(setq date (plist-get (cadr (org-element-at-point)) :value))
		(setq date-post-pair (list date post))
		(setq date-post-list (cons date-post-pair date-post-list))
		(erase-buffer)
		))
	    post-files)
    (setq date-post-list-sorted (sort date-post-list 'list-car-string-less))
    (mapcar (lambda (e)
	      (setq post-list (cons (cadr e) post-list)))
	    date-post-list-sorted)
    post-list))

(defun my/blog-generate-digest-html (posts)
  "generate blog's digest page html"
  (let ((html-str "")
	(category-url (concat blog-site-domain "category.html")))
    (mapcar (lambda (post)
	      (with-temp-buffer
		(setq post-url (concat blog-site-domain (string-trim blog-html-dir blog-root-dir) (car (split-string post "\\.")) ".html"))
		(setq valine-visitor-url (concat (string-trim blog-html-dir blog-root-dir) (car (split-string post "\\.")) ".html"))
		(insert-file-contents (concat blog-post-dir post))
		(setq count (my/word-count))
		(goto-char (point-min))
		(re-search-forward "^#\\+TITLE")
		(setq title (plist-get (cadr (org-element-at-point)) :value))
		(goto-char (point-min))
		(re-search-forward "^#\\+DATE")
		(setq date (plist-get (cadr (org-element-at-point)) :value))
		(goto-char (point-min))
		(re-search-forward "^#\\+CATEGORY")
		(setq category (plist-get (cadr (org-element-at-point)) :value))
		(setq buffer-string (replace-regexp-in-string "^#\\+.+\n+" "" (buffer-substring-no-properties (point-min) (point-max)))
		      buffer-string (replace-regexp-in-string "\\([a-zA-Z0-9]\\)[ ]+\\(\\cc\\)" "" buffer-string)
		      buffer-string (replace-regexp-in-string "\\[\\[.+\\]\\[" "" buffer-string)
		      buffer-string (replace-regexp-in-string "\\]\\]" "" buffer-string)
		      buffer-string (replace-regexp-in-string "\\*+" "" buffer-string)
		      buffer-string (replace-regexp-in-string "|-*" "" buffer-string)
		      buffer-string (replace-regexp-in-string "\n+" "" buffer-string)
		      buffer-string (replace-regexp-in-string " =" "" buffer-string)
		      buffer-string (replace-regexp-in-string "= " "" buffer-string))
		(setq digest (substring buffer-string 0 155))
		(erase-buffer)
		(insert
		 (print-html t `(div :class "post-div"
				     (h1 (a :href ,post-url ,title))
				     (p ,digest " ......" (a :href ,post-url "「阅读全文」"))
				     (code (a :href ,category-url ,category))
				     (span :class "post-date" ,date))))
		(setq html-str (concat html-str (buffer-substring-no-properties (point-min) (point-max))))
		))
	    posts)
    html-str))

(defun my/blog-generate-index-org (&optional proj)
  "generate blog index.org file"
  (interactive)
  (let* ((html-str (my/blog-generate-digest-html (my/blog-posts-sorted-by-date)))
	 (index-str (concat "#+TITLE: Geekinney Blog\n#+OPTIONS: title:nil\n#+begin_export html\n" html-str "#+end_export")))
    (with-temp-buffer
      (insert index-str)
      (write-file (concat blog-page-dir "index.org")))))

my/blog-posts-sorted-by-date 函数按照日期获取 blog-post-dir 下的所有org文章名称,结果返回一个列表。 my/blog-generate-digest-html 函数将文章列表作为参数,返回生成页面的所有html。 my/blog-generate-index-org 将生成的html写入 index.org 的html导出模块内。

最后,将 my/blog-generate-index-org 函数设为 org-publish-project-alist 变量的 :preparation-function 选项的值,这样每次在项目发布前会自动执行生成index页面的函数。然后在发布时导出为index.html。

Posted on 2020-02-22


©2020 戈楷旎 | Licensed under 知识共享许可协议

Generated by Emacs 26.3 (Org mode 9.1.9)