org-mode 写 cnblogs 博客

 

1. 为什么用org-mode写博客

我最开始用Emacs, 是因为org-mode。这是一个专注于写,而让我忽略展示结果的一种写作方式。为 什么这么说?因为所有内容的格式都是可定制的。按照自己喜欢的格式编写一些格式化配置, 就可以 把org-mode写的内容输出到拥有特定格式的文件,比如html、pdf,这两种常用的文件类型。

除此外,org-mode还可以做计划(TODO list) 等等。这些对于日常的工作都是非常有帮助的。

我喜欢上了org-mode.

与此同时,我又写技术类博客,把自己总结的内容发布到网络上,以飨读者。而很多时候,为了在博客 上格式化自己的文档,又是一件让我兴奋到五体投地的事情。

我尝试把导出成html文件的内容直接copy进博客,发现有些内容无法copy,或者原本的格式已经面目全非。 然后就研究了下,怎么样能把org-mode的内容直接发布到博客,这样可以保持原有的简约格式。

说白了,最根本的原因就是: 我懒!我懒!我懒!重要的事情说三遍!我不想花太多的时间去对文字图片进行重复格式化

说明

org-mode 写博客园的方法,主要 是copy 了huwenbiao GITHUB 的代码, 而他的代码是在GITHUB:hexmode 的基础上 针对cnblogs进行了扩展开发,已经很久很久没有更新了,可能已经不再维护了吧。我按照自己的想法对Open_Source的代码做了一些简单的修改。

修改内容:

  1. 取消从网站下载博文 原代码,在每次连接cnblogs前,在设置cnblogs的个人信息时,都会像苍蝇一样问我,是不是要把cnblogs里的博文下载下来,下载的博文是以博文ID命名的html内容文件。个人感觉没有太大的意义 。 而每次都得输入: no. 再次声明: 我懒! 所以我把下载博文的代码给删除了。
  2. 减少输入个人信息次数 每次要发布博文之前,都要手动设置自己的博客信息(blog id/ 登录名/密码)。 就像老婆让我睡觉前一定要洗澡一样烦(不会被老婆看到吧~哈哈), 所以我修改了原代码,将个人信息的相关变量单独配置, 以后每次写完org文件,直接 C-c c p 就可以直接发布,而不用每次都要先输入一次个人信息。而如果 没有配置,修改以后的程序会提醒你输入。
  3. 更新xml-rpc 因为 "huwenbiao"已经很久没有更新代码,所以我从GITHUB:hexmode 上复制了最新的内容。

主要是这些修改,其他还有一些细节和修复一些BUG。

总体来说,已经能满足我的需求了。

下面提供我修改以后的cnblogs.el

;;;cnblogs.el --- Emacs :Configuration for writing cnblogs with org-mode.

;; Created: Tue Jun 11 00:18:39 2019

;;

;; Copyright © 2019-

;;

;; Author: halberd.lee@gmail.com

;; URL:

;; Version: 20190610

;; Keywords: convenience

;; This file is not part of GNU Emacs.

;;; Commentary:

;; Some Linux specific stuff.

;;; License:

;; 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 GNU Emacs; see the file COPYING.  If not, write to the

;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,

;; Boston, MA 02110-1301, USA.

;;; Code:

;; On Linux Emacs doesn't use the shell PATH if it's not started from

;; the shell. Let's fix that:

;;todo检查所有的底层函数,正常运行返回t,否则返回nil

;;给所有的操作加上反馈信息

;;; entry type

;;

;; (id   title   postid      categories src-file state)

;; (int  string  int(string) list       string   string)

(require 'metaweblog)

(defgroup cnblogs nil

  "博客园客户端分组"

  :group 'emacs)

;;(defun cnblogs-define-variables ()

  "定义及初始化各变量"

(defcustom blog-base-url "https://www.cnblogs.com/"

  "blog 域名."

  :group 'cnblogs

  :type 'string)

(defcustom cnblogs-server-url nil

  "MetaWeblog访问地址"

  :group 'cnblogs

  :type 'string)

(defcustom cnblogs-blog-id "halberd-lee"

  "博客ID"

  :group 'cnblogs

  :type 'string)

(defcustom cnblogs-user-name "halberd.lee"

  "登录用户名"

  :group 'cnblogs

  :type 'string)

(defcustom cnblogs-user-passwd "12345678"

  "用户密码."

  :group 'cnblogs

  :type 'string)

(defcustom cnblogs-media-object-suffix-list '("jpg" "jpeg" "png" "gif" "mp4")

  "希望处理的媒体文件类型"

  :group 'cnblogs

  :type 'list)

(defcustom cnblogs-src-file-extension-list '("org" "html")

  "希望处理的媒体文件类型"

  :group 'cnblogs

  :type 'list)

(defcustom cnblogs-template-head

  "#TITLE:    #KEYWORDS: #DATE:    "

  "博客头模板."

  :group 'cnblogs

  :type 'list)

(defcustom cnblogs-file-root-path "~/wiki/cnblogs/"

  "数据文件的根目录."

  :group 'cnblogs

  :type 'string)

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defvar cnblogs-posts-in-category nil

  "分类之后的博文,这是显示在Cnblogs-Manager缓冲区里的主要内容.")

(defvar cnblogs-entry-list-file

  "博文项列表文件."

  (concat cnblogs-file-root-path "entry-list-file"))

(defvar cnblogs-file-post-path

  "博文内容文件根目录,其中的博文内容文件以博文id命名."

  (expand-file-name "post/" cnblogs-file-root-path ))

(defvar cnblogs-category-list nil

  "博文分类列表.")

(defvar cnblogs-category-list-file

  "博文分类列表."

  (expand-file-name "category-list-file" cnblogs-file-root-path ))

(defvar cnblogs-blog-info nil

  "博客信息.")

(defvar cnblogs-entry-list nil

  "本地博客列表.")

(defvar cnblogs-category-list nil

  "分类列表.")

(defvar cnblogs-post-list-window nil

  "博文列表窗口.")

(setq  test-post  `(("title" . "博文题目")

                    ("dateCreated" :datetime (20423 52590))

                    ("categories"  "categories" "[随笔分类]Emacs" "[随笔分类]Linux应用")

                    ("description" . "博文正文。")))

;;;;;;;;;;;;;;;;;;;;;;;;;;Menu;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;"cnblogs博客客户端菜单")

(defvar cnblogs-mode-map

  (make-sparse-keymap "Cnblogs"))

;;(define-key cnblogs-mode-map [tags-getUsersBlogs]

;;  '(menu-item "User information" cnblogs-get-users-blogs

;;              :help "获取用户的博客信息"))

;;

;;(define-key cnblogs-mode-map [tags-getRecentPosts]

;;  '(menu-item "Get recent posts" cnblogs-get-recent-posts

;;              :help "获取最近发布的N篇博客"))

;;

;;(define-key cnblogs-mode-map [tags-getCategories]

;;  '(menu-item "Get(Update) categories" cnblogs-get-categories

;;              :help "获取并更新本地博客分类"))

;;

;;(define-key cnblogs-mode-map [tags-getPost]

;;  '(menu-item "Get post" cnblogs-get-post

;;              :help "获取并更新本地指定的博客"))

;;(define-key cnblogs-mode-map [separator-cnblogs-tags]

;;  '(menu-item "--"))

;;

;;(define-key cnblogs-mode-map [tags-editPost]

;;  '(menu-item "Update post" cnblogs-edit-post

;;              :help "更新已发布的博客"))

;;

;;(define-key cnblogs-mode-map [tags-deletePost]

;;  '(menu-item "Delete post" cnblogs-delete-post

;;              :help "将当前缓冲区对应的博客删除"))

;;

;;(define-key cnblogs-mode-map [tags-saveDraft]

;;  '(menu-item "Save draft" cnblogs-save-draft

;;              :help "将草稿保存到服务器,但状态为“未发布”"))

;;

;;(define-key cnblogs-mode-map [tags-newPost]

;;  '(menu-item "Publish post" cnblogs-new-post

;;              :help "发布当前缓冲区"))

;;

;;(define-key cnblogs-mode-map [C-S-mouse-1]

;;  cnblogs-mode-map)

;;  )

                                        ;(cnblogs-define-variables)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;LoadData;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                                        ;(cnblogs-load-entry-list) ;; todo: 放在初始化中

(defun cnblogs-load-entry-list ()

  (setq cnblogs-entry-list

        (condition-case ()

            (with-temp-buffer

              (insert-file-contents cnblogs-entry-list-file)

              (car (read-from-string (buffer-string))))

          (error nil))))

(defun cnblogs-save-entry-list ()

  "保存cnblogs-entry-list,成功返回t,否则返回nil"

  (condition-case ()

      (with-temp-file cnblogs-entry-list-file

        (print cnblogs-entry-list

               (current-buffer)))

    (error nil)))

(defun cnblogs-load-category-list ()

  (setq cnblogs-category-list

        (condition-case ()

            (with-temp-buffer

              (insert-file-contents cnblogs-category-list-file)

              (car (read-from-string (buffer-string))))

          (error nil))))

(defun cnblogs-save-category-list ()

                                        ;先将分类格式简化,只留取名字

  (setq cnblogs-category-list

        (mapcar (lambda (category)

                  (cdr (assoc "description" category))

                  )

                cnblogs-category-list))

  (with-temp-file cnblogs-category-list-file

    (print cnblogs-category-list

           (current-buffer))))

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;底层函数;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun cnblogs-check-legal-for-publish (src-file)

  "检查文件是否可以发布"

  (and

   (if (member (file-name-extension src-file)

               cnblogs-src-file-extension-list)

       t

     (progn

       (message "Failed: UNSUPPORTED file!")

       nil))

   (if (equal (cnblogs-check-src-file-state (buffer-file-name))

              "PUBLISHED")

       (progn

         (message "This post has been published, you can update it, using M-x cnblogs-edit-post")

         nil)

     t)))

(defun cnblogs-check-legal-for-delete (src-file)

  "检查文件是否可以删除相应的博文"

  (and

   (if (member (file-name-extension src-file)

               cnblogs-src-file-extension-list)

       t

     (progn

       (message "Failed: UNSUPPORTED file!")

       nil))

   (if (equal (cnblogs-check-src-file-state (buffer-file-name))

              "PUBLISHED")

       t

     (progn

       (message "This post has not been published, so you cann't delete it!")

       nil))))

(defun cnblogs-check-legal-for-edit (src-file)

  "检查文件是否可以更新"

  (and

   (if (member (file-name-extension src-file)

               cnblogs-src-file-extension-list)

       t

     (progn

       (message "Failed: UNSUPPORTED file!")

       nil))

   (if (equal (cnblogs-check-src-file-state (buffer-file-name))

              "PUBLISHED")

       t

     (progn

       (message "This post has not been published, you can't update it. You can publish it using M-x cnblogs-new-post")

       nil))))

(defun cnblogs-check-src-file-state (src-file)

  (let ((state nil))

    (mapc (lambda (entry)

            (if (equal src-file (nth 4 entry))

                (setq state (nth 5 entry))))

          cnblogs-entry-list)

    state))

(defun cnblogs-gen-id ()

  "给entry产生一个id,从1开始"

  (let ((id 0)

        (flag t))

    (while flag

      (progn

        (setq flag nil id (1+ id))

        (mapc (lambda (entry)

                (and (equal id

                            (car entry))

                     (setq flag t)))

              cnblogs-entry-list)))

    id))

(defun cnblogs-push-post-to-entry-list (post)

  "将博文保存到cnblogs-entry-list变量中。但并不立即保存到文件中"

  (let ((title (cdr (assoc "title" post)))

        (postid (cdr (assoc "postid" post)))

        (categories (cdr (assoc "categories" post)))

        (done nil)

        (index 0))

    (progn

      (if (integerp postid)

          (setq postid (int-to-string postid)))

      ;;保存博文

      (with-temp-file (concat cnblogs-file-post-path postid)

        (print post (current-buffer)))

      ;;如果有相同标题的博文项,则提示是否合并到同一项中去,如果有已经存在多个相同的项,对每个都询问,直到回答是或者完

      (mapc (lambda (entry)

              (progn

                (or done

                    (not (equal title (nth 1 entry)))

                    (not (y-or-n-p (format "merge the post %s with entry %S" postid entry)))

                                        ;下面是将该博文合并到该项中

                    (progn

                      (setq done t)

                      (setcar (nthcdr index cnblogs-entry-list)

                                        ;id

                              (list (nth 0 entry)

                                        ;title

                                    title

                                        ;postid

                                    postid

                                        ;categories

                                    categories

                                        ;src-file

                                    (nth 4 entry)

                                        ;state

                                    "PUBLISHED"))))

                (setq index (1+ index))))

            cnblogs-entry-list)

                                        ;还没有插入则新建项

      (or done

          (push

                                        ;id

           (list (cnblogs-gen-id)

                                        ;title

                 title

                                        ;postid

                 postid

                                        ;categories

                 categories

                                        ;src-file

                 nil

                                        ;state

                 "PUBLISHED")

           cnblogs-entry-list)))))

(defun cnblogs-push-src-file-to-entry-list (src-file)

  "将一个源文件加入到博文项中,但并不立即保存博文项到文件中。"

  (if (cnblogs-check-file-in-entry-list src-file)

      t

    (let ((title

           (with-temp-buffer

             (insert-file-contents src-file)

             (cnblogs-fetch-field "TITLE")))

          (done nil)

          (index 0))

      (progn (mapc (lambda (entry)

                     (progn

                       (or done

                           (not title)

                           (not (equal title (nth 1 entry)))

                           (not (y-or-n-p (format "merge the file %s with entry %S" src-file entry)))

                                        ;下面是将该文件合并到该项中

                           (progn

                             (setq done t)

                             (setcar (nthcdr 4 (nth index cnblogs-entry-list))

                                     src-file)))

                       (setq index (1+ index))))

                   cnblogs-entry-list)

                                        ;还没有插入则新建项

             (or done

                 (push

                                        ;id

                  (list (cnblogs-gen-id)

                                        ;title

                        title

                                        ;postid

                        nil

                                        ;categories

                        nil

                                        ;src-file

                        src-file

                                        ;state

                        "UNPUBLISHED")

                  cnblogs-entry-list))))))

(defun cnblogs-assign-post-to-file (post src-file)

  "将post合并到一个指定源文件的列表项中,成功返回t,不立即保存列表项"

  (condition-case()

      (progn

        (setq cnblogs-entry-list

              (mapcar (lambda (entry)

                        (if (equal src-file

                                   (nth 4 entry))

                                        ;id

                            (list (nth 0 entry)

                                        ;title

                                  (cdr (assoc "title" post))

                                        ;postid

                                  (cdr (assoc "postid" post))

                                        ;categories

                                  (cdr (assoc "categories" post))

                                        ;src-file

                                  src-file

                                  "PUBLISHED")

                          entry))

                      cnblogs-entry-list))

        t)

    (error nil)))

(defun cnblogs-categories-string-to-list (categories-string)

  "将分类字符串按空白符分成字符串列表"

  (if (or (eq categories-string nil)

          (eq categories-string ""))

      nil

    (let ((idx1

           (string-match "[^  ]+"    ;圆角半角空格

                         categories-string)))

      (if (not idx1)

          nil

        (setq categories-string         ;圆角半角空格

              (substring categories-string idx1))

        (let ((idx2

               (string-match "[  ]+"

                             categories-string)))

          (if idx2

              (cons (concat "[随笔分类]"

                            (substring categories-string

                                       0

                                       idx2))

                    (cnblogs-categories-string-to-list (substring categories-string

                                                                  idx2)))

            (cons (concat "[随笔分类]"

                          categories-string)

                  nil)))))))

(defun cnblogs-fetch-field (field)

  (let* ((regexp

          (concat "^[ ]*[#]+[\+]?"

                  field

                  ":[^ ]*"))

         (idx (string-match regexp

                            (buffer-substring-no-properties (point-min)

                                                            (point-max)))))

    (if idx

        (let* ((field-val (match-string  0

                                         (buffer-substring-no-properties (point-min)

                                                                         (point-max))))

               (val (substring field-val

                               (1+ (string-match  ":"  field-val))))

               (idx2 (string-match "[^ ]+"

                                   val)))

          (and idx2

               (substring val

                          idx2)))

      nil)))

(defun cnblogs-make-media-object-file-data (media-path) ;todo: type可能要详细分类

  "根据给出的文件路径返回相应的FileData,文件不存在返回nil"

  (and (file-exists-p media-path)

       (list

        ;;media-path name

        (cons "name"

              (file-name-nondirectory media-path))

        ;; bits

        (cons "bits"

              (base64-encode-string

               (with-temp-buffer

                 (insert-file-contents-literally media-path)

                 (buffer-string))))

        (cons "type" "image/jpg"))))

(defun cnblogs-org-mode-buffer-to-post ()

  (delq nil(list

            ;; title

            (cons "title"

                  (or (cnblogs-fetch-field "TITLE")

                      "新随笔"))

            ;; excerpt

            (cons "mt_excerpt"

                  (or (cnblogs-fetch-field "DESCRIPTION")

                      ""))

            ;; categories

            (cons "categories"

                  (let ((categories-list

                         (cnblogs-categories-string-to-list

                          (cnblogs-fetch-field "CATEGORIES"))))

                    (or

                     categories-list

                     '("[随笔分类]未分类"))))

            ;; tags

            (cons "mt_keywords"

                  (or

                   (cnblogs-fetch-field "KEYWORDS")

                   ""))

            ;; dateCreated

            (cons "dateCreated"

                  (list

                   :datetime

                   (condition-case ()

                       (date-to-time (cnblogs-fetch-field "DATE")) ;todo: 要转化

                     (error (progn

                              (message "时间格式不支持,使用默认时间:1989-05-17 00:00")

                              (date-to-time "1989-05-17 00:00"))))))

            ;; description

            (cons "description"

                  (with-current-buffer (org-html-export-as-html)

                    (let ((buf-str

                           (cnblogs-replace-media-object-location

                            (buffer-substring-no-properties

                             (point-min)

                             (point-max)))))

                      (kill-buffer)

                      buf-str))))))

(defun cnblogs-other-mode-buffer-to-post () ;todo: post还不完全

  (delq nil

        (list

         ;; title

         (cons "title"

               (or (cnblogs-fetch-field "TITLE")

                   "新随笔"))

         ;; categories

         (cons "categories"

               (let ((categories-list

                      (cnblogs-categories-string-to-list

                       (cnblogs-fetch-field "CATEGORIES"))))

                 (or

                  categories-list

                  '("[随笔分类]未分类"))))

         ;; tags

         (cons "mt_keywords"

               (or

                (cnblogs-fetch-field "KEYWORDS")

                ""))

         ;; dateCreated

         (cons "dateCreated"

               (list

                :datetime

                (condition-case ()

                    (date-to-time (cnblogs-fetch-field "DATE")) ;todo: 要转化

                  (error (progn

                           (message "时间格式不支持,使用默认时间:1989-05-17 00:00")

                           (date-to-time "1989-05-17 00:00"))))))

         ;; description

         (cons "description"

               (cnblogs-replace-media-object-location

                (buffer-substring-no-properties

                 (cnblogs-point-template-head-end)

                 (point-max)))))))

(defun cnblogs-insert-template-head ()

  "插入头模板"

  (interactive)

  (save-excursion

    (goto-char (point-min))

    (insert cnblogs-template-head)))

(defun cnblogs-delete-entry-from-entry-list (postid)

  "通过postid删除博文项及posts目录下相应的文件,POSTID是string类型"

  (condition-case ()

      (progn

        (setq cnblogs-entry-list

              (remove-if (lambda (entry)

                           (equal postid

                                  (nth 2 entry)))

                         cnblogs-entry-list))

        (cnblogs-save-entry-list)

        (and (file-exists-p (concat cnblogs-file-post-path postid))

             (delete-file (concat cnblogs-file-post-path postid)))

        t)

    (error nil)))

(defun cnblogs-get-postid-by-title (title)

  (and (stringp title)

       (let ((postid nil))

         (mapc (lambda (entry)

                 (or postid

                     (and (equal title

                                 (nth 4 cnblogs-entry-list))

                          (setq postid

                                (nth 2 cnblogs-entry-list)))))

               cnblogs-entry-list)

         (and postid

              (integerp postid)

              (int-to-string postid))

         (or postid

             (setq postid "0"))))

  postid)

(defun cnblogs-get-postid-by-src-file-name (filename)

  "在cnblogs-entry-list中查找src-file为filename的项的博文id,找不到返回"0""

  (let ((postid nil))

    (mapc (lambda (entry)

            (if (equal filename (nth 4 entry))

                (setq postid (nth 2 entry))))

          cnblogs-entry-list)

    (or postid

        (setq postid "0"))

    postid))

(defun cnblogs-replace-media-object-location (buf-str)

  "处理BUF-STR中的媒体文件,返回处理后的字符串"

  (mapc (lambda (suffix)

          (let ((regexp

                 (concat "[file]*[:]?[/\]*[a-z]?[:]?[^:*"?<>|#]+."

                         suffix))

                (current 0))

            (while (string-match regexp

                                 buf-str

                                 current)

              (let* ((media-path (match-string 0

                                               buf-str))

                     (media-url

                      (save-match-data

                        (and (file-exists-p media-path)

                             (cnblogs-metaweblog-new-media-object

                              (cnblogs-make-media-object-file-data

                               media-path))))))

                (if media-url

                    (progn

                      (setq current

                            (+ (match-beginning 0)

                               (length media-url)))

                      (setq buf-str

                            (replace-match media-url

                                           t

                                           t

                                           buf-str)))

                  (setq current

                        (match-end 0)))))))

        cnblogs-media-object-suffix-list)

  buf-str)

(defun cnblogs-point-template-head-end ()

  (print  (save-excursion

            (goto-char (point-min))

            (forward-paragraph)

            (point))))

(defun cnblogs-current-buffer-to-post ()

  (cond

   ((equal mode-name

           "Org")

    (cnblogs-org-mode-buffer-to-post))

   (t

    (cnblogs-other-mode-buffer-to-post))))

(defun cnblogs-check-file-in-entry-list (src-file)

  "检查文件是否已经在列表项中"

  (let ((res nil))

    (mapc (lambda (entry)

            (or res

                (setq res

                      (equal src-file (nth 4 entry)))))

          cnblogs-entry-list)

    res))

(defun cnblogs-delete-post-from-entry-list (postid)

  "通过postid将相应的entry的postid设置为nil并删除posts目录下相应的文件,成功返回t.POSTID是string类型或者int类型"

  (if (integerp postid)

      (setq postid (int-to-string postid)))

  (condition-case ()

      (progn

        (setq cnblogs-entry-list

              (mapcar (lambda (entry)

                        (if (equal postid

                                   (if (integerp (nth 2 entry))

                                       (int-to-string (nth 2 entry))

                                     (nth 2 entry)))

                            (progn

                              (setcar (nthcdr 2 entry) nil)

                              (setcar (nthcdr 3 entry) nil)

                              (setcar (nthcdr 5 entry) "UNPUBLISHED")))

                        entry)

                      cnblogs-entry-list))

        (cnblogs-save-entry-list)

        (and (file-exists-p (concat cnblogs-file-post-path postid))

             (delete-file (concat cnblogs-file-post-path postid)))

        t)

    (error nil)))

(defun cnblogs-import-directory (directory)

  ;; 滤掉所有以.开头的文件,这样就没有了..和.以及所有的隐藏文件

  ;; 滤掉所有以~结尾的文件,这样就没有了自动备份

  (let ((files (directory-files directory t "^[^.].*[^~]$" t)))

    (mapc (lambda (file)

                                        ;目录

            (cond ((file-directory-p file)

                   (cnblogs-import-directory file))

                                        ;合法文件

                  ((member (file-name-extension file) cnblogs-src-file-extension-list)

                   (cnblogs-push-src-file-to-entry-list file))))

          files)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;功能函数;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun cnblogs-import-current-file ()

  "将当前文件加入到库中(增加到博文项cnblogs-entry-list中)"

  (interactive)

  (let ((src-file (buffer-file-name)))

    (if (member (file-name-extension src-file)

                cnblogs-src-file-extension-list)

        (progn

          (cnblogs-push-src-file-to-entry-list src-file)

          (cnblogs-save-entry-list)

          (message "Succeed!"))

      (message "Failed: UNSUPPORTED file!"))))

(defun cnblogs-import-file ()

  "添加一个文件加入到库中(增加到博文项cnblogs-entry-list中)"

  (interactive)

  (let ((src-file (read-file-name "Import file: ")))

    (if (member (file-name-extension src-file)

                cnblogs-src-file-extension-list)

        (progn

          (cnblogs-push-src-file-to-entry-list src-file)

          (cnblogs-save-entry-list)

          (message "Succeed!"))

      (message "Failed: UNSUPPORTED file!"))))

(defun cnblogs-import-folder ()

  "递归添加一个目录中的所有合法文件到库中,这个是给用户用的,主要是调用cnblogs-import-directory"

  (interactive)

  (let ((directory (read-directory-name "Import folder: ")))

    (cnblogs-import-directory directory)

    (cnblogs-save-entry-list)))

(defun cnblogs-setup-blog ()

  (interactive)

  (unless (stringp cnblogs-blog-id)

    (setq cnblogs-blog-id

          (read-string "Your blog ID:" nil nil)))

  (unless (stringp cnblogs-user-name)

  (setq cnblogs-user-name

        (read-string "Your username:" nil nil)))

  (unless (stringp cnblogs-user-passwd)

    (setq cnblogs-user-passwd

          (read-passwd "Your password:" nil )))

  (unless (stringp cnblogs-server-url)

    (setq cnblogs-server-url

          (concat blog-base-url

                  cnblogs-blog-id

                  "/services/metaweblog.aspx")))

  (unless (stringp cnblogs-category-list)

  (setq cnblogs-category-list

        (cnblogs-metaweblog-get-categories)))

  (unless (stringp cnblogs-blog-info)

    (setq cnblogs-blog-info

          (cnblogs-metaweblog-get-users-blogs)))

  (or (file-directory-p cnblogs-file-root-path)

      (make-directory cnblogs-file-root-path))

  ;; 如果没有posts目录,则新建这个目录

  (or (file-directory-p cnblogs-file-post-path)

      (make-directory cnblogs-file-post-path))

  ;;  (if cnblogs-blog-info

  ;;      (progn

  ;;        (customize-save-variable 'cnblogs-blog-id  cnblogs-blog-id)

  ;;        (customize-save-variable 'cnblogs-user-name cnblogs-user-name)

  ;;        (customize-save-variable 'cnblogs-user-passwd cnblogs-user-passwd)

  ;;        (customize-save-variable 'cnblogs-server-url cnblogs-server-url)

  ;;        ;; 如果没有根目录,则新建这个目录

  ;;        (cnblogs-save-category-list)

  ;;        ;; 从博客下载博文

  ;;        (and (yes-or-no-p "Should I pull all your posts now, it may talk a long time?")

  ;;             (let ((posts (cnblogs-metaweblog-get-recent-posts 0)))

  ;;               (mapc (lambda (post)

  ;;                       (cnblogs-push-post-to-entry-list post))

  ;;                     posts))

  ;;             (cnblogs-save-entry-list))

  ;;        (message "设置成功"))

  ;;    (message "设置失败"))

  )

(defun cnblogs-new-post ()

  (interactive)

  (cnblogs-setup-blog)

  (if (cnblogs-check-legal-for-publish (buffer-file-name))

      ;; 下面发布处理

      (let* ((postid  ;得到博文id

              (cnblogs-metaweblog-new-post (cnblogs-current-buffer-to-post) t))

                                        ;得到博文内容

             (post (cnblogs-metaweblog-get-post postid)))

                                        ;todo:这里要刷新列表

        ;;保存博文项和博文内容

        (if (integerp postid)

            (setq postid (int-to-string postid)))

        ;;保存博文

        (with-temp-file (concat cnblogs-file-post-path postid)

          (print post (current-buffer)))

        (if (cnblogs-check-file-in-entry-list (buffer-file-name))

            (cnblogs-assign-post-to-file post (buffer-file-name))

          (push

                                        ;id

           (list (cnblogs-gen-id)

                                        ;title

                 (cdr (assoc "title" post))

                                        ;postid

                 postid

                                        ;categories

                 (cdr (assoc "categories" post))

                 (buffer-file-name)

                 "PUBLISHED")

           cnblogs-entry-list))

                                        ;保存博文项列表

        (cnblogs-save-entry-list)

        (message "Post published!"))))

(defun cnblogs-save-draft ()

  (interactive)

  (let ((postid

         (cnblogs-metaweblog-new-post (cnblogs-current-buffer-to-post)

                                      nil)))

    (setq cnblogs-entry-list

          (cons

           (cnblogs-metaweblog-get-post postid)

           cnblogs-entry-list))

    (cnblogs-save-entry-list))

  (message "保存草稿成功!"))

(defun cnblogs-delete-post ()

  (interactive)

  (cnblogs-setup-blog)

  (if (cnblogs-check-legal-for-delete (buffer-file-name))

      (let ((postid

             (cnblogs-get-postid-by-src-file-name (buffer-file-name))))

        (if (and postid

                 (yes-or-no-p "Are you sure?")

                 (cnblogs-metaweblog-delete-post postid t)

                 (cnblogs-delete-post-from-entry-list postid)

                 (cnblogs-save-entry-list))

            (message "Succeed!")

          (message "Failed!")))))

(defun cnblogs-edit-post ()

  ;;todo:更新本地

  (interactive)

  (if (cnblogs-check-legal-for-edit (buffer-file-name))

      (let ((postid

             (cnblogs-get-postid-by-src-file-name

              (buffer-file-name))))

        (if (and postid

                 (yes-or-no-p "Are you sure to update?")

                 (cnblogs-metaweblog-edit-post postid

                                               (cnblogs-current-buffer-to-post)

                                               t)

                 (cnblogs-assign-post-to-file (cnblogs-metaweblog-get-post postid)

                                              (buffer-file-name))

                 (cnblogs-save-entry-list))

            (message "Succeed!")

          (message "Failed!")))))

(defun cnblogs-get-post ()

  (interactive)

  (let* ((postid

          (read-string "Post ID:"))

         (post

          (condition-case ()

              (cnblogs-metaweblog-get-post postid)

            (error nil))))

    (if (and postid

             (cnblogs-delete-post-from-entry-list postid)

             post

             (setq cnblogs-entry-list

                   (cons post cnblogs-entry-list)))

        (message "获取成功!")

      (message "获取失败"))))

;; 获取并保存分类

(defun cnblogs-get-categories ()

  (interactive)

  (setq cnblogs-category-list

        (condition-case ()

            (cnblogs-metaweblog-get-categories)

          (error nil)))

  (if cnblogs-category-list

      (progn

        (cnblogs-save-category-list)

        (message "获取分类成功!"))

    (message "获取分类失败")))

(defun cnblogs-get-recent-posts ()

  (interactive)

  (let* ((num (read-number "输入要获取的随笔篇数:"

                           1))

         (posts (condition-case ()

                    (cnblogs-metaweblog-get-recent-posts num)

                  (error nil))))

    (if (not posts)

        (message "获取失败!")

      (progn

        (mapc (lambda (post)

                (cnblogs-push-post-to-entry-list post))

              posts)

        (cnblogs-save-entry-list)

        (message "获取成功!")))))

(defun cnblogs-get-users-blogs ()

  (interactive)

  (setq cnblogs-blog-info

        (condition-case ()

            (prog1

                (cnblogs-metaweblog-get-users-blogs)

              (message "获取用户博客信息成功!"))

          (error cnblogs-blog-info))))

(defun cnblogs-add-props (str plist)

  "将faces属性plist赋给str,并返回这个str"

  (set-text-properties 0 (length str) plist str)

  str)

;;[c][b]

;;(defun cnblogs-category-selection-toggle (c)

;;  "根据字符c查找要触发的分类,然后触发这个分类"

;;  (let* ((begin (string-match (concat "[" c "]" [ ]*)

;;                              (buffer-substring (string-match "随笔分类" (buffer-string)) (point-max)))

;;

;;                (substring (buffer-substring (point-min) (point-max)) 23728 23731 )

;;                ))))

;;

;;(defun cnblogs-category-selection ()

;;  (interactive)

;;  (save-window-excursion

;;    (delete-other-windows)

;;    (split-window-vertically)

;;    (org-switch-to-buffer-other-window (get-buffer-create " *Cnblogs categories*"))

;;    (erase-buffer)

;;    ;; 列出当前已经选择的分类

;;    (insert "Current:    ")

;;

;;    ;; 列出随笔分类

;;    (insert " 随笔分类:    ")

;;    (let* ((idx ?0)

;;           (ctgr-list (remove-if-not (lambda (ctgr)

;;                                       (equal (substring ctgr 1 5) "随笔分类"))

;;                                     cnblogs-category-list))

;;           (maxlen (apply 'max (mapcar 'length ctgr-list))))

;;

;;      (mapc (lambda (ctgr)

;;              (insert "[" idx "]" (format "%s  " (substring ctgr 6)))

;;              (setq idx (1+ idx)))

;;            ctgr-list))

;;

;;    ;; 列出网站类分

;;    (insert " 网站分类:    ")

;;    (let* ((idx ?A)

;;           (ctgr-list (remove-if-not (lambda (ctgr)

;;                                       (equal (substring ctgr 1 5) "网站分类"))

;;                                     cnblogs-category-list))

;;           (maxlen (apply 'max (mapcar 'length ctgr-list))))

;;      (mapc (lambda (ctgr)

;;              (insert "[" idx "]" (format "%s  " (substring ctgr 6)))

;;              (setq idx (1+ idx)

;;                    ))

;;            ctgr-list))

;;    (insert " 其他分类:    ")

;;    ;; 列出其他分类

;;    (mapc (lambda (ctgr)

;;            (if (equal (substring ctgr 1 3) "发布")

;;                (insert (format "%s   " ctgr)))

;;            )

;;          cnblogs-category-list)

;;    (message "[0..9..a-z..]:Toggle [SPC]:clear [RET]:accept")

;;    ;; 处理分类选择

;;    (catch 'exit

;;      (while t

;;        (let ((c (read-char-exclusive)))

;;          (cond

;;           ((= c ? ) (throw exit t))

;;           (t (do nothing)

;;              )

;;           ))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mode设置;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; 下面是关于minor mode的内容

(defun cnblogs-init ()

  "Cnblogs的所有初始化工作,加载各种变量值."

  ;;加载博文项列表

  (cnblogs-load-entry-list)

  ;;加载博文分类

  (cnblogs-load-category-list)

  ;;将博文项列表中的项加入到相应的分类中去

  (mapc (lambda (categorie)

          (progn

            ;;先将该分类加入

            (push (cons categorie nil)

                  cnblogs-posts-in-category)

            )

          ;;将属于该分类的项加入该分类

          (mapc (lambda (entry)

                  (let* ((entry-categories (nth 3 entry))

                         (flag (member categorie entry-categories)))

                    (and flag

                         (push entry

                               (cdr (assoc categorie cnblogs-posts-in-category)))))

                  )

                cnblogs-entry-list))

        cnblogs-category-list)

  )

;; 定义菜单

(define-key cnblogs-mode-map [menu-bar menu-bar-cnblogs-menu]

  (cons "Cnblogs" cnblogs-mode-map))

(define-minor-mode cnblogs-minor-mode

;;  "cnblogs-minor-mode"

  :init-value nil

  :lighter " Cnblogs"

  :keymap cnblogs-mode-map

  :group Cnblogs)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KeyMap;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define-key cnblogs-mode-map (kbd "C-c c p") 'cnblogs-new-post)

(define-key cnblogs-mode-map (kbd "C-c c s") 'cnblogs-save-draft)

(define-key cnblogs-mode-map (kbd "C-c c d") 'cnblogs-delete-post)

(define-key cnblogs-mode-map (kbd "C-c c e") 'cnblogs-edit-post)

(define-key cnblogs-mode-map (kbd "C-c c g") 'cnblogs-get-post)

(define-key cnblogs-mode-map (kbd "C-c c c") 'cnblogs-get-categories)

(define-key cnblogs-mode-map (kbd "C-c c r") 'cnblogs-get-recent-posts)

(define-key cnblogs-mode-map (kbd "C-c c u") 'cnblogs-get-users-blogs)

;;(add-hook 'cnblogs-minor-mode-hook 'cnblogs-init) ;打开cnblogs-minor-mode时再加载数据等初始化

(cnblogs-init)

(cnblogs-minor-mode)

(setq org-export-show-temporary-export-buffer nil)

(provide 'cnblogs)

;;; cnblogs.el ends here.

经过修改后,这个世界安静了。

配置方法及修改内容说明

  • 下载文件 打开github:huwenbiao, 下载cnblogs.el和metaweblog.el 两个文件,至于另外一个文件xml-rpc.el 请到 GITHUB:hexmode 下载。
  • 如何加载 这些是针对小白的。大牛忽略。

将这三个文件放到你的.emacs.d/cnblogs 中. 然后在init.el中 添加如下代码:

;; for cnblogs.
(add-to-list 'load-path "~/.emacs.d/cnblogs/")
(require 'cnblogs)

这样,以后打开org文件时就会自动加载相关的配置。其中的cnblogs-minor-mode 就是用于发布博客的一个mode.

  • 配置个人信息

    打开cnblogs.el 文件,找到 通过defcustom定义的以下三个变量:

cnblogs-blog-id         –> cnblogs 的blog id 比如网址:https://www.cnblogs.com/halberd-lee 的blog id 就是 halberd-lee

cnblogs-user-name    –> 登录cnblogs的用户名 

cnblogs-user-passwd –> 登录 cnblogs的密码 三个变量后面的值都是Nil , 修改为自己的信息。

4. 使用说明

做好以上配置后, 编辑好org-mode buffer后,不需要保存,C-c c p 即可正常发布,如果要本地保留源文件,最好还是保存。

C-c c d 根据发布记录的(post-id)删除博客中的博文。这是两个最常用的功能。

原文地址:https://www.cnblogs.com/halberd-lee/p/10989782.html