• 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)删除博客中的博文。这是两个最常用的功能。

  • 相关阅读:
    ubuntu-虚拟机跟主机资源共享的实现方法
    git- 仓库创建、修改、提交、撤销
    theme- 工作原理
    makeMtk- user 版本编译
    Button- 自定义控件添加自定义属性
    actionMode
    screen-Orientation 横竖屏设置
    worktools-mmx 添加编译模块
    eclipse- MAT安装及使用
    worktools-monkey 测试工具的使用
  • 原文地址:https://www.cnblogs.com/halberd-lee/p/10989782.html
Copyright © 2020-2023  润新知