玩了幾個晚上,總算可以順利從 emacs 裡將文章送到 Blog 了。
自從開始用 emacs 後就一直改用 muse 在寫筆記和報告,設定好以後可以透過 LaTeX 轉換成 PDF 檔,相當方便。用習慣後也曾興起透過 muse 寫 Blog 的念頭,找了很多資料,也知道有很多人實作成功,但說真的要拿來用還是有點問題,主要還是 elisp 不熟,而且大部份的實作竟然都是直接在 emacs 裡寫 html 後送出去 (還有人推薦用 nxml);就算直接在後台寫也有方便的 wysiwyg editor,但 emacs 還有 muse 這個好東西,何必那麼苦命呢。
目前的做法還是透過 xml-rpc 加 weblogger,後來找到有人針對 wordpress 的修改,安裝上並不難,只需稍微自訂一下就可以使用。
首先必須透過 weblogger-setup-weblog 建立設定檔,可以有多組設定,每一組設定會有一個名字作為識別。要注意的是預設並不儲存密碼,往後傳送資料時必須手動輸入。如果想偷懶可以設定一下 weblogger-save-password,建立設定資料時就會自動儲存密碼。
開始撰寫文章時先 M-x weblogger-start-entry,會自動建立簡單的樣板,填入 Subject 與內容即可。需要加上 Category 的話,可以在 header section 手動加入一行 "Keywords: ",各分類之間以逗點分隔 (必須是 server 上存在的 Category 名稱)。目前似乎還不支援 Tag。發布文件的方式很簡單,熱鍵跟存檔一樣是 C-x C-s,也可以用 C-c C-c 存成 Draft。日後需要修改時也可以把文章抓回來修改後再回存,相當方便1。
Weblogger 的使用不難,比較麻煩的是跟 muse 銜接的部份,研究了一晚找出需要的資料結構,原來是建構在 message-mode 之上,所以得先產生類似 message header 的資料。這部份我直接以 html style 為基礎,建立一個新的 muse style 來處理:
(muse-derive-style "my-blog" "html"
:suffix ".wp.html"
:header
"Subject: <lisp>(muse-publishing-directive \"title\")</lisp>
From: <lisp>(muse-publishing-directive \"author\")</lisp>
Keywords: <lisp>(muse-publishing-directive \"desc\")</lisp>
--text follows this line--
"
:footer ""
:browser 'find-file
:regexps `((100000 "!!more!!" 0 more) )
:functions '((more . muse-mywp-markup-more))
:strings '(
(image-link . "<a target=\"_blank\" class=\"image-link\" href=\"%s\">
<img src=\"%s.%s\"></a>")
(url . "<a target=\"_blank\" href=\"%s\">%s</a>")
(link . "<a target=\"_blank\" href=\"%s\">%s</a>")
(link-and-anchor . "<a target=\"_blank\" href=\"%s#%s\">%s</a>")))
當然在 project 部份也要新增一個項目
(setq muse-project-alist
'(("blog" ("~/Note/blog" )
(:base "my-blog" :path "~/Note/blog/convert"))))
本來的想法是找出 muse 資料的產生方式,直接丟到 webloger buffer,但是一堆括號看到頭暈,所以用了比較笨的方式:先用 muse 轉換過,再呼叫修改過的 weblogger 函式將結果轉換出必要的資料結構,最後丟上 server。
修改這些其實還算簡單,但我有個需求是要同時送到多個地方備份用,這可要我命了…因為裡面一堆全域變數,從帳號設定對應到內部資料結構的部份又太複雜 (誰說用 functional language 不會有 side-effect…XD),所以我還是用最笨的方式,每次連線前先重置相關的全域變數:
(defun muse-blog-start-entry ()
(unless weblogger-entry-ring
(setq weblogger-entry-ring
(make-ring weblogger-max-entries-in-ring)))
(ring-insert weblogger-entry-ring '(("content" "")))
(setq weblogger-ring-index 0)
(unless weblogger-server-username
(setq weblogger-server-username ""))
(unless weblogger-server-password
(setq weblogger-server-password ""))
(weblogger-edit-entry (weblogger-entry-buffer-to-struct)))
(defun muse-blog-send-post (&optional blogConfName)
"send current to blog"
(unless blogConfName
(read-from-minibuffer "Select a blog conf: " blogConfName))
(setq weblogger-server-username nil)
(setq weblogger-server-password nil)
(setq weblogger-server-url nil)
(setq weblogger-weblog-id nil)
(weblogger-select-configuration blogConfName)
(weblogger-start-entry)
(set-buffer-modified-p t)
(weblogger-save-entry t)
(bury-buffer))
(defvar muse-blog-conf-name-alist nil)
(defun muse-blog-publish ()
(interactive)
(when muse-blog-conf-name-alist
(mapcar 'muse-blog-send-post muse-blog-conf-name-alist)))
使用前需要先設定 muse-blog-conf-name-alist,內容是一個字串的 list,就是先前在 weblogger 中建立的 profile 名稱,發布文章時就會丟到所有在清單中的 Blog 位置。
muse 文稿的部份,要注意的是利用了三個 directives:title、author 與 desc,分別對應到 message header 中的 Subject、From 與 Keywords。以本文為例,開頭的前幾行如下:
#title Blogging with Emacs
#author letoh
#desc note, emacs
產生出來的 header 如下:
Subject: Blogging with Emacs
From: letoh
Keywords: note, emacs
–text follows this line–
到這樣已經相當好用了,同一份 muse 文件除了生成 LaTeX / ConTeXt 文稿或 PDF 外,也可以發布到 Blog 上,當然產生 static page 或整理起來變成 Wiki 更不是問題。只剩一個小小的缺憾,就是還沒把 blogger 分舵加進來,因為 blogger 已經不用 xmlrpc,改用 Blogger Data API 了,這兩天再努力看看吧。有任何建議也歡迎指教。
1. 實際使用後發現抓回來的文章如果包含 <!--more--> (wordpress 設定摘要位置用的記號),只會抓回摘要的部份;此時若回存會把文章後半部份蓋掉XD 修改方法還在研究中…