« ^ »

Qiita記事をEmacsから投稿する試み

所要時間: 約 2分

コード

(require 's)
(require 'dash)


(defun ox-qmdx--get-export-setting (header-name)
  "Get export setting value.

The export settings are those described in `#+FOO: BAR`.
This function moves point internally.
However, the position is restored as soon as the function completes.
"
  (save-excursion
    (goto-char 0)
    (re-search-forward (format "^[ \t]*#\\+%s: \\(.+\\)" header-name) nil t) 
    (match-string-no-properties 1)))


(defun ox-qmdx--get-org-source ()
  "Return markdown comment style string of Org document source in the current buffer."
  (format "\n\n<!---ORG\n%s\n--->"
      (buffer-substring-no-properties (point-min) (point-max))))


(defun ox-qmdx--export-get-title ()
  (ox-qmdx--get-export-setting 'title))


(defun ox-qmdx--export-get-item-id ()
  (or (ox-qmdx--get-export-setting 'qiita_item_id) 
      nil))


(defun ox-qmdx--export-get-private ()
  (case (ox-qmdx--get-export-setting 'qiita_private)
    ("t" :json-false)
    ("nil" t)
    (otherwise t)))


(defun ox-qmdx--export-get-tweet ()
  (case (ox-qmdx--get-export-setting 'qiita_tweet)
    ("t" t)
    ("nil" :json-false)
    (otherwise :json-false)))


(defun ox-qmdx--export-get-tags ()
  (-map (lambda (name) `((:name . ,name)))
    (s-split " "
         (ox-qmdx--get-export-setting 'qiita_tags))))

org-exportで呼び出す関数

(defun org-qmdx-export-as-markdown-and-post (&optional async subtreep visible-only)
  "Export current buffer to a Qiita Markdown buffer and source."
(json-encode
 `((title . ,(ox-qmdx--export-get-title))
   (body . ,(with-current-buffer (org-qmd-export-as-markdown) (buffer-substring-no-properties (point-min) (point-max))))
   (coediting . :json-false)
   (group_url_name . nil)
   (private . ,(ox-qmdx--export-get-private))
   (tweet . ,(ox-qmdx--export-get-tweet))
   (tags . ,(ox-qmdx--export-get-tags))
   ))
  (org-qmd-export-as-markdown async subtreep visible-only)


  (let ((src-buf (current-buffer))
    (export-buf (org-qmd-export-as-markdown)))
    (with-current-buffer export-buf
      (end-of-buffer)
      (insert (with-current-buffer src-buf 
      (ox-qmdx--get-org-source)))
      export-buf)))

記事投稿のbodyの生成

(json-encode
 `((title . ,(ox-qmdx--export-get-title))
   (body . ,(with-current-buffer (org-qmd-export-as-markdown) (buffer-substring-no-properties (point-min) (point-max))))
   (coediting . :json-false)
   (group_url_name . nil)
   (private . ,(ox-qmdx--export-get-private))
   (tweet . ,(ox-qmdx--export-get-tweet))
   (tags . ,(ox-qmdx--export-get-tags))
   ))
{"title":"Qiita記事をEmacsから投稿する","body":"```el\n(require 's)\n(require 'dash)\n\n\n(defun ox-qmdx--get-export-setting (header-name)\n  \"Get export setting value.\n\nThe export settings are those described in `#+FOO: BAR`.\nThis function moves point internally.p\nHowever, the position is restored as soon as the function completes.\n\"\n  (save-excursion\n    (goto-char 0)\n    (re-search-forward (format \"^[ \\t]*#\\\\+%s: \\\\(.+\\\\)\" header-name) nil t) \n    (match-string-no-properties 1)))\n\n\n(defun ox-qmdx--get-org-source ()\n  \"Return markdown comment style string of Org document source in the current buffer.\"\n  (format \"\\n\\n<!---ORG\\n%s\\n--->\"\n\t  (buffer-substring-no-properties (point-min) (point-max))))\n\n\n(defun org-qmdx-export-as-markdown (&optional async subtreep visible-only)\n  \"Export current buffer to a Qiita Markdown buffer and source.\"\n  (let ((src-buf (current-buffer))\n\t(export-buf (org-qmd-export-as-markdown)))\n    (with-current-buffer export-buf\n      (end-of-buffer)\n      (insert (with-current-buffer src-buf \n\t\t(ox-qmdx--get-org-source)))\n      export-buf)))\n\n\n(defun ox-qmdx--export-get-title ()\n  (ox-qmdx--get-export-setting 'title))\n\n\n(defun ox-qmdx--export-get-item-id ()\n  (or (ox-qmdx--get-export-setting 'qiita_item_id) \n      nil))\n\n\n(defun ox-qmdx--export-get-private ()\n  (case (ox-qmdx--get-export-setting 'qiita_private)\n    (\"t\" :json-false)\n    (\"nil\" t)\n    (otherwise t)))\n\n\n(defun ox-qmdx--export-get-tweet ()\n  (case (ox-qmdx--get-export-setting 'qiita_tweet)\n    (\"t\" t)\n    (\"nil\" :json-false)\n    (otherwise :json-false)))\n\n\n(defun ox-qmdx--export-get-tags ()\n  (-map (lambda (name) `((:name . ,name)))\n\t(s-split \" \"\n\t\t (ox-qmdx--get-export-setting 'qiita_tags))))\n```\n\n```el\n(json-encode\n `((title . ,(ox-qmdx--export-get-title))\n   (body . ,(with-current-buffer (org-qmdx-export-as-markdown) (buffer-substring-no-properties (point-min) (point-max))))\n   (coediting . :json-false)\n   (group_url_name . nil)\n   (private . ,(ox-qmdx--export-get-private))\n   (tweet . ,(ox-qmdx--export-get-tweet))\n   (tags . ,(ox-qmdx--export-get-tags))\n   ))\n```\n\n\n\n<!---ORG\n#+TITLE: Qiita記事をEmacsから投稿する\n#+QIITA_TAGS: emacs emacs-lisp\n#+QIITA_PRIVATE: t\n#+QIITA_ITEM_ID: d4f07e962cfbf3828803\n#+QIITA_TWEET: nil\n\n#+BEGIN_SRC emacs-lisp\n(require 's)\n(require 'dash)\n\n  \n(defun ox-qmdx--get-export-setting (header-name)\n  \"Get export setting value.\n\nThe export settings are those described in `#+FOO: BAR`.\nThis function moves point internally.p\nHowever, the position is restored as soon as the function completes.\n\"\n  (save-excursion\n    (goto-char 0)\n    (re-search-forward (format \"^[ \\t]*#\\\\+%s: \\\\(.+\\\\)\" header-name) nil t) \n    (match-string-no-properties 1)))\n\n\n(defun ox-qmdx--get-org-source ()\n  \"Return markdown comment style string of Org document source in the current buffer.\"\n  (format \"\\n\\n<!---ORG\\n%s\\n--->\"\n\t  (buffer-substring-no-properties (point-min) (point-max))))\n\n\n(defun org-qmdx-export-as-markdown (&optional async subtreep visible-only)\n  \"Export current buffer to a Qiita Markdown buffer and source.\"\n  (let ((src-buf (current-buffer))\n\t(export-buf (org-qmd-export-as-markdown)))\n    (with-current-buffer export-buf\n      (end-of-buffer)\n      (insert (with-current-buffer src-buf \n\t\t(ox-qmdx--get-org-source)))\n      export-buf)))\n\n\n(defun ox-qmdx--export-get-title ()\n  (ox-qmdx--get-export-setting 'title))\n\n\n(defun ox-qmdx--export-get-item-id ()\n  (or (ox-qmdx--get-export-setting 'qiita_item_id) \n      nil))\n\n\n(defun ox-qmdx--export-get-private ()\n  (case (ox-qmdx--get-export-setting 'qiita_private)\n    (\"t\" :json-false)\n    (\"nil\" t)\n    (otherwise t)))\n\n\n(defun ox-qmdx--export-get-tweet ()\n  (case (ox-qmdx--get-export-setting 'qiita_tweet)\n    (\"t\" t)\n    (\"nil\" :json-false)\n    (otherwise :json-false)))\n\n\n(defun ox-qmdx--export-get-tags ()\n  (-map (lambda (name) `((:name . ,name)))\n\t(s-split \" \"\n\t\t (ox-qmdx--get-export-setting 'qiita_tags))))\n#+END_SRC\n\n\n#+BEGIN_SRC emacs-lisp\n(json-encode\n `((title . ,(ox-qmdx--export-get-title))\n   (body . ,(with-current-buffer (org-qmdx-export-as-markdown) (buffer-substring-no-properties (point-min) (point-max))))\n   (coediting . :json-false)\n   (group_url_name . nil)\n   (private . ,(ox-qmdx--export-get-private))\n   (tweet . ,(ox-qmdx--export-get-tweet))\n   (tags . ,(ox-qmdx--export-get-tags))\n   ))\n#+END_SRC\n\n\n--->","coediting":false,"group_url_name":null,"private":true,"tweet":false,"tags":[{"name":"emacs"},{"name":"emacs-lisp"}]}

登録手順

  1. org-exportでpublishする
  2. 現在のソースからmarkdownを生成
  3. 生成したmarkdownをqiitaに登録
  4. 登録リクエストのレスポンスからidを取得
  5. 取得したidをソースヘッダに反映
  6. ソースをソースサーバーに保存

Org-exportの設定


(org-export-define-derived-backend 'qmdx 'qmd
  :filters-alist '((:filter-paragraph . org-qmd--unfill-paragraph))
  :menu-entry
  '(?0 "Export to Qiita Markdown X"
       ((?0 "To temporary buffer"
            (lambda (a s v b) (org-qmd-export-as-markdown a s v)))
            ))
  :translate-alist '((headline . org-qmd--headline)
                     (inner-template . org-qmd--inner-template)
                     (keyword . org--qmd-keyword)
                     (strike-through . org-qmd-strike-through)
                     (src-block . org-qmd--src-block)))

APIを使って記事を登録する

(setq ox-qmdx-api-token "testing")

(request "https://qiita.com/api/v2/items"
  :type "GET"
  :headers `(("Content-Type" . "application/json")
         ("Authorization" . ,ox-qmdx-api-token))
  :parser (lambda () (buffer-string))
  :complete (cl-function
         (lambda (&key response &allow-other-keys)
           (setq testing response))))