Migration to Org mode

Published on Aug 18, 2019

Transform Markdown Files into Org files

Using bash script and pandoc to do this transform.

for f in `ls *.md`; do 
  echo "[*] process: $f"
  pandoc -f markdown -t org -o ${f%.md}.org ${f}; 
done

however, some error happened.

➜  blog for f in `ls *.md`; do 
for>   echo "[*] process: $f"
for>   pandoc -f markdown -t org -o ${f%.md}.org ${f}; 
for> done
[*] process: 2012-02-07-vim-latexxelatex.md
[*] process: 2012-02-23-vimlisp.md
[*] process: 2012-03-06-vbox.md
[*] process: 2012-03-11-vrdp.md
[*] process: 2012-03-21-lfs.md
[*] process: 2012-03-25-archlinux3264.md
[*] process: 2012-04-13-How-I-built-this-blog.md
[*] process: 2012-04-16-half-hackerhalf-artist.md
[*] process: 2012-04-24-.md
[*] process: 2012-04-26-a-text-game-engine-written-by-lisp.md
[*] process: 2012-04-28-visualize-tree-like-data-in-lisp.md
[*] process: 2012-05-01-grand-theft-wumpus.md
[*] process: 2012-05-03-the-orc-battle-game.md
[*] process: 2012-05-06-using-loop-to-evolve.md
[*] process: 2012-05-09-attack-of-the-robots.md
[*] process: 2012-05-10-streams-in-lisp.md
[*] process: 2012-05-12-web-server-written-in-lisp.md
[*] process: 2012-05-14-.md
[*] process: 2012-05-18-.md
[*] process: 2012-05-20-.md
[*] process: 2012-05-23-dice-of-doom.md
[*] process: 2012-05-26-.md
[*] process: 2012-05-28-archlinuxpdf.md
[*] process: 2012-05-31-tail-call-optimization.md
[*] process: 2012-06-02-memoization-in-functional-style.md
[*] process: 2012-06-05-scheme.md
[*] process: 2012-06-08-first-ai-in-lisp.md
[*] process: 2012-06-09-gimp.md
[*] process: 2012-06-12-.md
[*] process: 2012-06-13-macro-in-lisp.md
[*] process: 2012-06-16-dsl.md
[*] process: 2012-06-19-.md
[*] process: 2012-06-21-linux.md
[*] process: 2012-06-22-a-mathjax-test.md
[*] process: 2012-06-23-.md
[*] process: 2012-06-26-common-lisp.md
[*] process: 2012-06-28-google-glasses.md
[*] process: 2012-06-29-dice-of-doom-v2.md
[*] process: 2012-07-02-webdice-of-doom.md
[*] process: 2012-07-05-.md
[*] process: 2012-07-07-dice-of-doom-v4.md
[*] process: 2012-07-09-land-of-lisp.md
[*] process: 2012-07-11-.md
[*] process: 2012-07-13-.md
[*] process: 2012-08-04-.md
[*] process: 2012-08-11-.md
[*] process: 2012-08-15-galgame.md
[*] process: 2012-08-17-to-be-an-epicurean.md
[*] process: 2012-08-22-numpy.md
[*] process: 2012-08-24-scipy.md
[*] process: 2012-08-30-sympy-tutorial.md
[*] process: 2012-09-07-matplotlib-tutorial.md
[*] process: 2012-09-12-.md
[*] process: 2012-09-20-.md
[*] process: 2012-10-14-always-look-on-the-bright-side-of-life.md
[*] process: 2012-10-14-scikit-learn-machine-learning-in-python.md
[pandoc warning] Could not parse YAML header: did not find expected comment 
or line break "source" (line 41, column 3)                                 
[*] process: 2012-10-19-python.md
[*] process: 2012-10-22-scipy.md
[*] process: 2012-10-30-.md
[*] process: 2012-10-31-python.md
[*] process: 2012-11-12-numpyscipy.md
[*] process: 2012-11-19-flask.md
[*] process: 2012-12-02-python.md
[*] process: 2013-01-06-summary-and-prospect-in-2012.md
[*] process: 2013-01-13-moving-to-gentoo.md
[*] process: 2013-01-26-data-analysis-with-open-source-tools.md
[*] process: 2013-01-28-visualize-your-shell-history.md
[*] process: 2013-02-05-visualize-the-friendship-of-renren.md
[pandoc warning] Could not parse YAML header: did not find expected alphabet
ic or numeric character "source" (line 15, column 2)                       
[*] process: 2013-02-19-yet-another-photomosaic-generator.md
[*] process: 2013-02-25-generate-ascii-images-like-the-matrix.md
[*] process: 2013-03-02-python.md
[*] process: 2013-03-07-image-to-css.md
[*] process: 2013-03-11-quickstart-ebuild-guide.md
[*] process: 2013-03-13-advanced-python-constructs.md
[pandoc warning] Could not parse YAML header: did not find expected alphabet
ic or numeric character "source" (line 27, column 2)                       
[*] process: 2013-03-24-.md
[*] process: 2013-04-07-2-d-phase-unwrapping-path-following.md
[*] process: 2013-04-12-hello-bupt.md
[*] process: 2013-04-16-interfacing-with-c.md
[*] process: 2013-04-27-a-beautiful-night-in-jnu.md
[*] process: 2013-05-13-graduation-season.md
[*] process: 2013-05-16-some-books.md
[*] process: 2013-06-01-recent-summary.md
[*] process: 2013-06-09-hacking-the-art-of-exploitation.md
[*] process: 2013-07-02-goodbye-jnu.md
[*] process: 2013-07-22-build-up-your-own-pt-lab.md
[*] process: 2013-07-26-shellcode-black-magic.md
[*] process: 2013-08-03-heap-unlinking.md
[*] process: 2013-08-13-notes-on-anti-virus-evasion.md
[*] process: 2013-08-21-new-travel.md
[*] process: 2013-08-26-win32-shellcode.md
[*] process: 2013-08-31-so-boring.md
[*] process: 2013-09-06-.md
[*] process: 2013-09-09-.md
[*] process: 2013-09-13-.md
[*] process: 2013-09-15-.md
[*] process: 2013-09-30-.md
[*] process: 2013-10-11-.md
[*] process: 2013-10-15-wheres-the-way.md
[*] process: 2013-10-31-feelings-up-and-down.md
[*] process: 2013-11-09-what-a-fucking-life.md
[*] process: 2013-11-25-cloud-atlas.md
[*] process: 2013-12-21-.md
[*] process: 2013-12-24-writing-drivers-in-linuxa-brief-tutorial.md
[*] process: 2013-12-31-.md
[*] process: 2014-01-11-thanks.md
[*] process: 2014-01-12-python.md
[*] process: 2014-01-29-python.md
[*] process: 2014-02-18-.md
[*] process: 2014-02-26-spoofing.md
[*] process: 2014-03-04-play-arp.md
[*] process: 2014-03-07-play-dhcp.md
[*] process: 2014-03-15-play-icmp.md
[*] process: 2014-04-03-gns3-on-gentoo-linux.md
[*] process: 2014-04-18-.md
[*] process: 2014-05-04-360-hack-game.md
[*] process: 2014-05-04-.md
[*] process: 2014-05-10-gentoolaunchpad-msp430.md
[*] process: 2014-05-18-a-glance-at-d3js.md
[*] process: 2014-05-31-mysql-learning-notes.md
[*] process: 2014-06-02-.md
[*] process: 2014-06-13-.md
[*] process: 2014-07-26-upgrade-gentoo-linux.md
[*] process: 2014-08-07-radare2-shellcode.md
[*] process: 2014-08-08-better-and-beautiful-console.md
[*] process: 2014-08-08-defeating-ioli-with-radare2.md
[*] process: 2014-08-14-fbi-tor-malware-analysis.md
[*] process: 2014-08-26-.md
[*] process: 2014-09-08-escape-plan.md
[*] process: 2014-09-21-quora.md
[*] process: 2014-10-09-lrc.md
[*] process: 2014-10-09-.md
[*] process: 2014-10-11-gcjust-for-fun.md
[*] process: 2014-10-13-on-disk-encryption.md
[*] process: 2014-10-15-dwarf-fortress.md
[*] process: 2014-10-17-acl-on-linux.md
[*] process: 2014-11-12-some-articles.md
[*] process: 2014-11-15-.md
[*] process: 2014-11-17-linux-audit.md
[*] process: 2014-11-18-file-permissions-and-masks.md
[*] process: 2014-11-20-account-and-access-control.md
[*] process: 2014-12-24-.md
[*] process: 2015-03-02-2015s-first-post.md
[*] process: 2015-03-09-.md
[*] process: 2015-03-11-shellcodeenvironment.md
[*] process: 2015-03-16-shellcodeloaders.md
[*] process: 2015-03-16-shellcode.md
[*] process: 2015-03-17-shellcodedynamic.md
[*] process: 2015-03-18-load-time-relocation-of-shared-libraries.md
[*] process: 2015-03-19-position-independent-code-pic-in-shared-libraries.md
[*] process: 2015-03-30-boot-sequence.md
[*] process: 2015-04-01-python-spider-quick-and-dirty-way.md
[*] process: 2015-04-02-baidu-music.md
[*] process: 2015-04-03-ydcx.md
[*] process: 2015-04-04-chaoxing.md
[*] process: 2015-04-05-yingxin.md
[*] process: 2015-04-07-python-spider-camera-find.md
[*] process: 2015-05-02-javascript.md
[*] process: 2015-05-10-.md
[*] process: 2015-05-17-17.md
[*] process: 2015-05-24-hacking-security.md
[*] process: 2015-06-01-security-in-browsers.md
[*] process: 2015-06-12-.md
[*] process: 2015-06-27-.md
[*] process: 2015-07-03-.md
[*] process: 2015-08-07-maybe-the-last-post-here.md
[*] process: 2015-11-12-i-am-back.md
[*] process: 2015-11-17-greasemonkey-userscript.md
[*] process: 2015-11-18-notes-on-migrating-from-jeykll-to-hexo.md
[*] process: 2015-11-21-the-es6-features-i-use-these-days.md
[*] process: 2015-11-23-linux-tex.md
[*] process: 2015-11-24-web-based-input-method.md
[*] process: 2015-11-29-using-buptgraduatethesis-on-ubuntu.md
[*] process: 2015-12-06-freedom.md
[*] process: 2015-12-14-wangyin.md
[*] process: 2015-12-20-stream-in-nodejs.md
[*] process: 2016-01-02-2015-summary-and-prospect.md
[*] process: 2016-01-15-webchat-user-bot.md
[*] process: 2016-02-09-play.md
[*] process: 2016-02-26-evolving-game-once-more.md
[*] process: 2016-02-28-say-something.md
[*] process: 2016-03-07-neural-network-101.md
[*] process: 2016-03-08-harvest-mm-pics.md
[*] process: 2016-03-09-black-hat-javascript.md
[*] process: 2016-03-22-yet-another-new-journey.md
[*] process: 2016-04-20-after-10-o-clock.md
[*] process: 2016-05-02-the-quieter-you-become-the-more-you-are-able-to-hear
.md                                                                        
[*] process: 2016-05-25-for-freedom.md
[*] process: 2016-06-11-writing-something-useful.md
[*] process: 2016-06-26-goodbye.md
[*] process: 2016-07-24-exploring-webpack.md
[*] process: 2016-09-13-half-year-full-time-front-end-developer.md
[*] process: 2016-11-02-interview.md
[*] process: 2017-01-08-spring-and-chaos.md
[*] process: 2017-05-26-memorize-bbs-byr-cn.md
[*] process: 2017-06-14-ubuntu-gnome-guide-for-mbp-users.md
[*] process: 2017-06-17-develop-a-mind-which-does-not-abide-in-anything.md
[*] process: 2018-01-06-2018.md
[*] process: 2018-11-11-dwarf-fortress-story-calendar.md
[*] process: 2019-06-24-i-am-back-again.md
[*] process: 2019-08-11-eink-experience-in-two-weeks.md
➜  blog 

The error occured.

process 2012-10-14-scikit-learn-machine-learning-in-python.md
[pandoc warning] Could not parse YAML header: did not find expected comment or line break "source" (line 41, column 3)

obselete old toc implement when i use jekyll, which I write as

— *目录 {:toc} —

Insert Back FrontMatters

I use a python script to migrate jekyll yml frontmatter to orgmode options

FROM = "/home/reverland/blog-next/src/posts/"
TO = "/home/reverland/tmpblog/"
for f in os.listdir(FROM):
    if f.endswith(".md"):
        fm = frontmatter.load(os.path.join(FROM, f))
        title = fm['title']
        date = f[:10]
        summary = fm['excerpt']
        tags = " ".join(fm['tags'])
        front = "#+TITLE: %s\n#+DATE: <%s>\n#+SUBTITLE: %s\n#+TAGS: %s\n\n" % (title, date, summary, tags)
        with open(os.path.join(TO, os.path.splitext(f)[0] + '.org')) as original:
            data = original.read()
        with open(os.path.join(TO, os.path.splitext(f)[0] + '.org'), 'w') as modified:
            modified.write(front + data)

Blog with Org mode

Org mode has a versatile export and publishing function.

I tweak a little from @narendraj9's org-blog.el.

(require 'org)
(require 'ox-publish)
(require 'ox-html)
(require 'org-element)
(require 'ox-rss)

(defvar org-blog-date-format "%h %d, %Y"
  "Format for displaying publish dates.")

(defun org-blog-prepare (project-plist)
  "With help from `https://github.com/howardabrams/dot-files'.
  Touch `index.org' to rebuilt it.
  Argument `PROJECT-PLIST' contains information about the current project."
  (let* ((base-directory (plist-get project-plist :base-directory))
         (buffer (find-file-noselect (expand-file-name "index.org" base-directory) t)))
    (with-current-buffer buffer
      (set-buffer-modified-p t)
      (save-buffer 0))
    (kill-buffer buffer)))

(defvar org-blog-head
  "<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css\" integrity=\"sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO\" crossorigin=\"anonymous\">
  <link rel=\"stylesheet\" type=\"text/css\" href=\"/static/blog.css\"/>
  <link rel=\"stylesheet\" type=\"text/css\" href=\"https://fonts.googleapis.com/css?family=Amaranth|Handlee|Libre+Baskerville|Bree+Serif|Ubuntu+Mono|Pacifico&subset=latin,greek\"/>
  <link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/static/favicon.ico\">")

(defun org-blog-preamble (plist)
  "Pre-amble for whole blog."
  ;; Hack! Put date for the post as the subtitle
  (when (s-starts-with-p "20" (plist-get plist :input-file))
    (plist-put plist
               :subtitle (format "Published on %s"
                                 (org-export-get-date plist
                                                      org-blog-date-format))))

  ;; Return a simple banner with navigation links
  "<div class=\"banner\">
    <a href=\"/\"> Reverland的行知阁 </a>
  </div>
  <ul class=\"banner-links\">
    <li><a href=\"/archive.html\"> Posts </a> </li>
    <li><a href=\"/archive.xml\"> RSS </a> </li>
    <li><a href=\"/index.html\"> About Me </a> </li>
    <li><a href=\"/links.html\"> Links </a> </li>
  </ul>
  <hr>")

(defun org-blog-postamble (plist)
  "Post-amble for whole blog."
  (concat
  "<footer class=\"footer\">
    <a href=\"https://reverland.org\">
    <p> Built with
      <svg id=\"i-heart\" viewBox=\"0 0 32 32\">
        <path d=\"M4 16 C1 12 2 6 7 4 12 2 15 6 16 8 17 6 21 2 26 4 31 6 31 12 28 16 25 20 16 28 16 28 16 28 7 20 4 16 Z\"/>
      </svg> in
        <img id=\"i-emacs\" src=\"https://www.gnu.org/software/emacs/images/emacs.png\"/>
        <span id=\"view-source-link\"> copyleft@2012-2019 </span>
    </p>
    </a>
  </footer>
  <script type=\"text/javascript\" src=\"/static/blog.js\"> </script>

<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-38681562-1\"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'UA-38681562-1');
</script>
"

   ;; Add Disqus if it's a post
   (when (s-contains-p "posts/" (plist-get plist :input-file))
     "<!-- Disqua JS -->
<div id=\"disqus_thread\"></div>
<div id=\"disqus_thread\"></div>
  <script type=\"text/javascript\">
   var disqus_shortname = 'reverlandblog';
   (function() {
     var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
     dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
     (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
   })();
  </script>
  <noscript>Please enable JavaScript to view the <a href=\"http://disqus.com/?ref_noscript\">comments powered by Disqus.</a></noscript>
")))

(defun org-blog-sitemap-format-entry (entry _style project)
  "Return string for each ENTRY in PROJECT."
  (when (s-starts-with-p "20" entry)
    (format "@@html:<span class=\"archive-item\"><span class=\"archive-date\">@@ %s @@html:</span>@@ [[file:%s][%s]] @@html:</span>@@"
            (format-time-string "%h %d, %Y"
                                (org-publish-find-date entry project))
            entry
            (org-publish-find-title entry project))))

(defun org-blog-sitemap-function (title list)
  "Return sitemap using TITLE and LIST returned by `org-blog-sitemap-format-entry'."
  (concat "#+TITLE: " title "\n\n"
          "\n#+begin_archive\n"
          (mapconcat (lambda (li)
                       (format "@@html:<li>@@ %s @@html:</li>@@" (car li)))
                     (seq-filter #'car (cdr list))
                     "\n")
          "\n#+end_archive\n"))

(defun org-blog-publish-to-html (plist filename pub-dir)
  "Same as `org-html-publish-to-html' but modifies html before finishing."
  (let ((file-path (org-html-publish-to-html plist filename pub-dir)))
    (with-current-buffer (find-file-noselect file-path)
      (goto-char (point-min))
      (search-forward "<body>")
      (insert (concat "\n<div class=\"content-wrapper container\">\n "
                      "  <div class=\"row\"> <div class=\"col\"> </div> "
                      "  <div class=\"col-sm-6 col-md-8\"> "))
      (goto-char (point-max))
      (search-backward "</body>")
      (insert "\n</div>\n<div class=\"col\"></div></div>\n</div>\n")
      (save-buffer 0)
      (kill-buffer))
    file-path))

(use-package ox-publish
  :requires (org ox-html ox-rss)
  :commands publish-blog
  :config
  (defun publish-blog ()
    (interactive)
    (org-publish-project "blog" t))

  (setq org-confirm-babel-evaluate nil)

  (setq org-publish-project-alist
  `(("blog-content"
     :base-directory "~/org/posts/"
     :exclude ".*~"
     :base-extension "org"

     :publishing-directory "~/org/blog/"

     :recursive t
     :preparation-function org-blog-prepare
     :publishing-function org-blog-publish-to-html

     :with-toc nil
     :with-title org-export-with-title
     :with-date org-export-with-date
     :section-numbers nil
     :html-doctype "html5"
     :html-html5-fancy t
     :html-head-include-default-style nil
     :html-head-include-scripts nil
     :htmlized-source t
     :html-head-extra ,org-blog-head
     :html-preamble org-blog-preamble
     :html-postamble org-blog-postamble

     :auto-sitemap t
     :sitemap-filename "archive.org"
     :sitemap-title "Blog Posts"

     :sitemap-sort-files anti-chronologically
     :sitemap-format-entry org-blog-sitemap-format-entry
     :sitemap-function org-blog-sitemap-function
     )
    ("blog-static"
     :base-directory "~/org/posts/"
     :base-extension "jpg\\|png\\|css\\|js\\|ico\\|gif\\|pdf\\|ogg"
     :recursive t
     :publishing-directory "~/org/blog/"
     :publishing-function org-publish-attachment
     )
    ("blog-rss"
     :base-directory "~/org/posts/"
     ;; :base-extension "org"

     :html-link-home "http://reverland.org"
     :html-link-use-abs-url t

     :rss-extension "xml"

     :publishing-directory "~/org/blog/"
     :publishing-function (org-rss-publish-to-rss)

     :exclude ".*"
     :include ("archive.org")
     :section-numbers nil
     :with-toc nil
     :title "Reverlands Playground")
    ("blog"
     :components
     ("blog-content" "blog-static" "blog-rss"))))
  )

(provide 'org-blog)

and bind a command to some hotkeys

(use-package org-blog
  :bind (("C-c b" . publish-blog))
  )

Easy New Blog Post with Capture Template

add this, and M-x org-capture RET to add new blog files.

(defun org-blog-create-posts-file ()
  "Create an org file in ~/org/posts/."
  (interactive)
  (let ((name (read-string "Filename: ")))
    (expand-file-name (format "%s.org"
                                name) "~/org/posts/")))
(setq org-capture-templates
'(
  ("b" "New Post" plain (file org-blog-create-posts-file)
   (file "templates/blog-post.tpl"))))

Migrate disqus thread

use disqus url mapping disqus migration tools.

  with open("reverlandblog-2019-11-11T03:07:50.790956-links.csv") as f:
s = f.read()
  lines = [l for l in s.split("\r\n") if l != ""]
  for l in lines:
l = l.split("?")[0]
x = l.replace('http://reverland.org/', '').split("/")
if x[0] == "about.html":
          print("%s,%s", (l, "https://reverland.org/index.html"))
          continue
elif len(x) < 5:
          continue
y = x[1]
m = x[2]
d = x[3]
t = x[4]
print("%s,%s" % (l, ("https://reverland.org/%s-%s-%s-%s.html" % (y, m, d, t)).lower()))