Yearly Archives: 2014

2014-09-30

タブレットで読書

最近10.1インチのAndroidタブレット(Xperia Z2 Tablet)で自炊した本を読んでます。

大きいタブレットだと色々はかどりますね。バッテリーも持ちますし。読むのに疲れたら何か他のものを見たりもできますし(Nexus5でテザリング)。何より版面が見やすいです。

ただ、本のサイズによっては両開きだと文字が小さく、片面だと逆に大きすぎるという場合もあります。今読んでいるのは元がA5サイズですが、まさにそんな感じ。少し文字が小さくなりますが両開きで読んでます。

アプリはezPDF Readerを使ってます。ちゃんとPDFの閉じ方向情報を認識してくれることが必須ですね。両開きで表示したときにページの左右が逆になってしまいますので。余白のカット(ページの切り抜き)表示もできます。

家でも外でも何冊もの本が同じように読めるの良いです。最近は未読の本も有用な本もどんどんスキャンしているのでライブラリも充実してきました。

ちなみに今読んでいるのはアナキズム・イン・ザ・UK -壊れた英国とパンク保育士奮闘記。内容はこことかこことか参照。Life Is A Piece Of Shit ―人生は一片のクソなんだよ。

2014-09-26 ,

JekyllからWordPressへ移行

JekyllからWordpressへ移行しました。

Jekyllは生成が遅すぎて耐えきれなかったというのが第一の理由です。一つ記事を書き終わってから更新をかけると、ほぼすべてのページを再生成するため、どうしても数十秒かかります。すべてのページを再生成しなくても良いように思うかもしれませんが、各ページにあるナビゲーションリンクやタグごとの記事数なんかを書き直さなければなりません。このサイトには1500くらい記事があるのですが1分くらいはかかります。関連記事や記事数といった情報はいったん全部の記事を読み込んでからで無いと求まりませんし。incrementalな再生成も検討されているようなのですが、できるのはまだ先のようなので。

さくらのレンタルサーバで簡単にWordpressを入れる方法が紹介されていたのも移行を後押ししました。

外出先からなど、もっと自由に記事を書きたかったですし。

移行手順は次のような感じでした。

記事の変換はいくつかハマったところがありました。

まずはインポートできる形式を調べたのですが、めぼしいものが見当たりません。結局WordPress間でやりとりするのに使われるであろう形式にこれまでの記事を変換することにしました。
これまでの記事はJekyllのyamlヘッダー付きhtml形式です(昔の独自マークアップ形式やorg-mode形式からhtmlへ変換されたものです)。それをWordpressでインポートできるWXR(WordPress eXtended RSS)へ変換しました。変換に使ったEmacs Lispは次の通り。

(defun jtow-parse-html (file)
  "yamlヘッダー付きhtmlファイルを解析して(記事URL slug タイトル 時刻 タグ文字列リスト 内容文字列)を返します。"
  (with-temp-buffer
    (insert-file file)
    ;; ---
    (beginning-of-buffer)
    (if (not (looking-at "^---\n")) (error "syntax error. '---'"))
    ;; yaml header
    (next-line)
    (let ((yaml-header nil))
      (while (not (looking-at "^---"))
        (if (not (looking-at "^\\([^:]+\\): *\\(.*\\)$"))
            (error "syntax error. %s %s" file (buffer-substring (point-at-bol) (point-at-eol))))
        (push (cons (match-string-no-properties 1) (match-string-no-properties 2)) yaml-header)
        (next-line))
      (next-line)

      ;; check
      (let ((title (cdr (assoc "title" yaml-header)))
            (date (cdr (assoc "date" yaml-header)))
            (tags (cdr (assoc "tags" yaml-header)))
            (content (buffer-substring-no-properties (point) (point-max))))
        (if (not title) (error "title not found. %s" file))
        (if (not date) (error "date not found. %s" file))

        ;; result
        (list
         ;; link
         (concat "http://example.jp/blog/" file)
         ;; postname
         (if (string-match "^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-\\([^.]+\\)\\.html$" file ) (match-string 1 file) nil)
         ;; title
         (substring title 1 -1)
         ;; date
         (jtow-parse-date date)
         ;; tags
         (if tags (split-string tags " " t))
         ;; content
         content))
      )))

(defun jtow-parse-date (d)
  "2014-01-02という形式の文字列からEmacsの時刻形式へ変換します。"
  (let ((tm (parse-time-string d)))
    (encode-time 0 0 0 (nth 3 tm) (nth 4 tm) (nth 5 tm) (* 9 3600))))

(defun jtow-format-date-rfc2822 (time)
  (format-time-string "%a, %d %b %Y 00:00:00 %z" time))

(defun jtow-format-time (time &optional universal)
  (format-time-string "%Y-%m-%d %H:%M:%S" time universal))

(defun jtow-make-item (item)
  "jtow-parse-htmlが返したリストをWXRのitem要素へ変換します。"
  (let ((link (nth 0 item))
        (postname (nth 1 item))
        (title (nth 2 item))
        (date (nth 3 item))
        (tags (nth 4 item))
        (content (nth 5 item)))
    (concat
     "<item>"
     (if link (concat "<link>" link "</link>\n"))
     (if title (concat "<title>" title "</title>\n"))
     (if date (concat "<pubDate>" (jtow-format-date-rfc2822 date) "</pubDate>\n"))
     (if tags (loop for tag in tags concat (format "<category domain=\"post_tag\" nicename=\"%s\"><![CDATA[%s]]></category>\n" (downcase tag) tag)))

     (format "<wp:post_date>%s</wp:post_date>\n" (jtow-format-time date))
     (format "<wp:post_date_gmt>%s</wp:post_date_gmt>\n" (jtow-format-time date t))
     (concat "<wp:post_name>" postname "</wp:post_name>\n")
     "<wp:post_type>post</wp:post_type>\n"
     "<wp:status>publish</wp:status>\n"

     ;; content
     "<content:encoded><![CDATA[" content "]]></content:encoded>\n"
     "</item>\n")))

(defun jtow-dir-html-to-xml (dir outfile)
  "ディレクトリ内のyamlヘッダー付きhtmlファイルからWXRファイルを作成します。"
  (with-temp-file outfile
    (insert
     "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>
<rss version=\"2.0\"
	xmlns:excerpt=\"http://wordpress.org/export/1.2/excerpt/\"
	xmlns:content=\"http://purl.org/rss/1.0/modules/content/\"
	xmlns:wfw=\"http://wellformedweb.org/CommentAPI/\"
	xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
	xmlns:wp=\"http://wordpress.org/export/1.2/\"
>
<channel>
	<title>Example Blog</title>
	<link>http://example.jp/blog</link>
	<description></description>
	<pubDate>Thu, 25 Sep 2014 05:56:52 +0000</pubDate>
	<language>ja</language>
	<wp:wxr_version>1.2</wp:wxr_version>
	<wp:base_site_url>http://example.jp/blog</wp:base_site_url>
	<wp:base_blog_url>http://example.jp/blog</wp:base_blog_url>

	<wp:author>
	<wp:author_id>1</wp:author_id>
	<wp:author_login>foo</wp:author_login>
	<wp:author_email>foo@example.jp</wp:author_email>
	<wp:author_display_name><![CDATA[foo]]></wp:author_display_name>
	<wp:author_first_name><![CDATA[]]></wp:author_first_name>
	<wp:author_last_name><![CDATA[]]></wp:author_last_name>
	</wp:author>

	<generator>http://wordpress.org/?v=4.0</generator>
")

    (loop for file in (directory-files dir nil "\.html$") do (insert (jtow-make-item (jtow-parse-html file))))

    (insert "</channel></rss>")))

;; ex)カレントディレクトリにある.htmlからposts.xmlを作る。
;;(jtow-dir-html-to-xml "." "posts.xml")

私が使っていたyamlヘッダーは主にtags, date, titleだけでしたので、それだけ考慮してあります。

CDATAの障害になる]]>という文字列が使われていないことも確認しました。

一番困ったのが、slug(postname)が重複してはいけないということでした。昔の記事では/blog/2006-01-01-a.htmlのようなURLが多いのですが、aの部分は他の日付でも沢山使われているので重複してしまいます。重複すると自動的にa-2、a-3のように補正されてしまいます。仕方ないので/blog/2006-01-01-060101a.htmlのように確実にユニークになるようにファイル名を置換しました。以前のURLと変わってしまいますが諦めました。

外観のカスタマイズはBootpressテーマをベースにして、気に入らないところをひたすら書き換えては表示してみる繰り返しでした。
それにしてもphpは久しぶりです。しかしまぁ、見えないグローバル変数に依存するコードが多くて分かりづらいですね。WP_Queryが割と万能な模様。

一通りカスタマイズが終わったらテスト用ディレクトリから本番ディレクトリへ移し替えて完成です。

投稿は今まで事実上Emacsからしか出来ませんでしたが、これからはブラウザ、Androidアプリ、Emacsと色々なところから出来るようになりました。

AndroidのWordPressアプリは面白いですね。写真を撮ったそばから投稿できます。

Emacsからの投稿はOrg2blogを導入。el-get経由でインストールしました。bzrが実行できないと言われたのでCygwinのインストーラからbzrをインストール(xml-rpc-elのインストールに必要)。でもWindowsのEmacsを使っていて、かつ、bzrはPythonスクリプトなのでEmacsからexecutable-findで見つからず。bzr.batを作ってsh -c '/bin/bzr %*'のようにしてなんとかel-getからインストールできました。(MELPAをpackageに追加してそこからインストールした方が良かったかも)

Org2blogもAndroidのWordPressアプリもですがslugが入力できません。URLが日本語になってしまいますが、まぁ、これも諦めるしかないでしょうか。(Org2blogでは#+PERMALINKでslugを設定できました)

2014-09-26

9月終了番組

忙しさにかまけて切りに切りまくった今期ですが、最後まで見て面白かったなと思ったのは次の三つでしょうか。

  • グラスリップ
  • 月刊少女 野崎くん
  • ベイビーステップ

グラスリップは、一話を見たときは良くあるテキトーな青春グループ恋愛もの(誰と誰がくっつくか、というだけで延々話を消費してこれといって中身がないもの)なのかなと思ってスルーしかけたのですが、意外と中身がありました。

野崎くんは、「千代ちゃんかわいい」というだけですね。ええ。……いや、コメディなので、色々と可笑しかったです。

ベイビーステップは、勉強が得意な主人公が真面目に考えながらテニスに打ち込む話です。スポーツものとしてはちょっと変わってますよね。

2014-08-29

指定したディレクトリ下にあるwavファイルの合計時間(python)

wavファイルの合計時間が欲しかったのだけどsoxとかではあんまりうまく出来ないみたいなので自分で書いてみた。バイナリファイルの処理なので、なんとなくPython。

import sys
import os
import struct
import fractions

if len(sys.argv) != 2:
    print "Usage: python %s <directory>" % sys.argv[0]
    quit()

dir = sys.argv[1]
files = [y for y in [os.path.join(dir, x) for x in os.listdir(dir)] if os.path.isfile(y) and os.path.splitext(y)[1].upper()==".WAV"]

totalSeconds = fractions.Fraction()
for file in files:
    print file
    f = open(file, 'rb')
    riff = f.read(4)
    if riff == "RIFF":
        riffSize, riffType = struct.unpack('<I4s', f.read(8))

        samplesPerSec = 0
        blockSize = 0
        while True:
            chunkType,chunkSize = struct.unpack('<4sI', f.read(8))

            if chunkType == "fmt ":
                formatId,channels,samplesPerSec,bytesPerSec,blockSize,bitsPerSample = struct.unpack('<HHIIHH', f.read(chunkSize))
            elif chunkType == "data":
                totalSeconds += fractions.Fraction(chunkSize / blockSize, samplesPerSec)
                break
            else:
                f.seek(chunkSize, os.SEEK_CUR)

    f.close()

print "totalSeconds " + str(float(totalSeconds))
print "totalMinutes " + str(float(totalSeconds / 60))

なんて書いてみたら、後からwaveライブラリなんてものがあることに気がついたorz。

import wave
w = wave.open("a.wav")
w.getframerate()
w.getnframes()

みたいな感じでサンプリングレートとサンプル数が取得できるんだって。

2014-07-20

2014-07夏の新番組

とりあえず一通り見終わりました。

  • △MX :07/02(水) 23:30~ 幕末Rock
  • ○MX :07/02(水) 24:00~ Free! - Eternal Summer
  • △MX :07/03(木) 22:30~ グラスリップ
  • △MX :07/03(木) 23:00~ 白銀の意思 アルジェヴォルン
  • △MX :07/03(木) 24:00~ 東京喰種トーキョーグール
  • △TBS:07/03(木) 25:46~ RAIL WARS!
  • △TBS:07/03(木) 26:26~ 普通の女子校生が【ろこどる】やってみた。
  • △TX :07/05(土) 10:00~ プリパラ
  • △MX :07/05(土) 24:00~ ALDNOAH ZERO
  • △MX :07/05(土) 25:00~ 少年ハリウッド
  • ○NTV:07/05(土) 26:35~ ばらかもん
  • △MX :07/06(日) 22:00~ 人生相談テレビアニメーション「人生」
  • -MX :07/06(日) 22:30~ さばげぶっ!
  • △MX :07/06(日) 23:00~ スペース☆ダンディ シーズン2
  • ○MX :07/06(日) 24:00~ アカメが斬る!
  • △TX :07/06(日) 25:10~ 月刊少女 野崎くん
  • ×TX :07/06(日) 25:40~ DRAMAtical Murder ドラマティカルマーダー
  • ×TX :07/06(日) 26:40~ 闇芝居 新シリーズ
  • ○MX :07/07(月) 24:00~ アオハライド
  • ○TX :07/07(月) 25:35~ ハナヤマタ
  • -TX :07/07(月) 26:05~ Re :␣ハマトラ
  • △MX :07/08(火) 24:30~ モモキュンソード
  • ○MX :07/09(水) 22:00~ ヤマノススメ セカンドシーズン
  • ×MX :07/09(水) 24:30~ まじもじるるも
  • ○MX :07/09(水) 25:05~ LOVE STAGE!!
  • ○CX :07/10(木) 25:10~ 残響のテロル
  • ○CX :07/10(木) 25:40~ PSYCHO-PASS サイコパス 新編集版
  • △MX :07/11(金) 25:35~ 六畳間の侵略者!?
  • △MX :07/11(金) 25:35~ 東京ESP
  • △CX :07/11(金) 26:10~ 信長協奏曲 -のぶながコンツェルト-
  • △TBS:07/11(金) 26:35~ 黒執事 Book of Circus
  • ×MX :07/14(月) 24:30~ 精霊使いの剣舞

第一話の段階で特に目を引いたものはありませんでした。

2014-06-30

伊藤園の緑茶ティーバッグ

最近、伊藤園の緑茶のティーバッグを色々試しています。これまでに次の三種類を飲みました。

どれも十分美味しいと思います。味の評価としては、

深蒸し=ぞっこん>抹茶入り

という感じですね。価格相応です。

抹茶入りは伊右衛門みたいな味がします。いかにも抹茶でごまかされたという感じがしてしまいますが、安いことを考えれば妥当かもしれません。

ぞっこんは最近ペットボトルのおまけでティーバッグが付いていたので、飲んだ方も多いと思います。とにかくまろやかさを前面に出したような味ですね。

深蒸しはちゃんと深蒸し茶っぽい香りと味がします。綺麗な緑色、強い甘みと弱めだが確かに感じる渋みのバランス。

どれを買っても後悔はしないと思います。

個人的にはやっぱり普段から飲み慣れている深蒸し茶が好きかなぁ。

深蒸しだと20袋で36gと書いてますね。お茶屋さんで1000円/100gくらいで買った方が安いのですが、いつも全部飲みきる前に悪くなってしまうので、それを考えるとそんなに高くはないのかも。