40歳からのキャリアチェンジ

20代はエンジニア・PM、30代はWeb系エンジニア向けのキャリアアドバイザー。40代の今はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連あたり

iPhotoの複数の写真を(ほぼ自動で)まとめてEvernoteに取り込むスクリプト完成

※2010年9月14日追記
MacユーザでRubyの環境が整っていない人向けにAppleScript 使って特定のフォルダ配下の写真をまとめてインポートするを書きましたのでよろしければそちらもご覧ください

このエントリでメール送信でiPhotoの写真データをまとめてEvernoteにインポートするやり方書いた時に

メール送信経由では無く、順番にenexファイルを作成してそれを順番にインポートするやり方をもう一度模索することにした。

って書いていました。

メール送信機能を利用せずに、動的にenexファイルを生成して、それをEvernoteにインポートする所はほぼ出来ていて、実際にうまくいっているように見ていたんだけどなぜか同期しようとすると
sync_error

というエラーメッセージが出てEvernoteの同期に失敗することにたぶん1週間以上悩まされていました。

何に悩んでいたのか?

インポートする時のenexファイル(というかxmlファイル)の形式については細かいところがよくわからないけどとりあえずEvernote上の画像が含まれているファイルをenex形式でエクスポートし、適当なテキストエディタでこのenexファイルを開いて、ノートのタイトルになる所や、ノート作成日、元の画像データ・・などの関連個所を別の情報に差し替えるということを考えていました。

差し替え作業自体はそんなに難しく、実際に修正した内容をインポートしたら、Evernoteの画面上では問題なく表示されていました。

ところがいざ同期しようとすると同期に失敗するとういことで、Evernote上で見えてるのに、同期だけうまくいかないということにずっと悩んでいました。

何が原因で同期に失敗していたのか?

ファイルをenex形式でエクスポートし、適当なテキストエディタで関連個所を修正していた時に、タグの部分改行されていないから、ものすごく見づらいから、適当な所で改行したりしていました。

その時につくったテンプレート的に作ったのがこんな感じ

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export.dtd">;
<en-export export-date="20100624T223326Z" application="Evernote" version="Evernote Mac 1.9.0 (83438)">
<note>
  <title><%= @evernote_note_title %></title>
  <content>
    <![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">;
<en-note style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">
<en-media type="image/jpeg" hash="<%= @evernote_hash %>"></en-media>
</en-note>]]>
  </content>
  <created><%= @evernote_created_date %></created>
  <updated><%= @evernote_created_date %></updated>
  <note-attributes/>
  <resource>
    <data encoding="base64"><%= @imgdata %>
    </data>
    <mime>image/jpeg</mime>
    <width>1280</width>
    <height>960</height>
</resource>
</note>
</en-export>

これをつかって何度やってもダメだった。。。

これでうまくいった!

Evernoteでエクスポートした時の状態は読みづらいけど、改行とかしないでそのままやってみよう」

と思いつき、下記のファイルをevernote_enex01.tmplという名前で保存。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export.dtd">;
<en-export export-date="20100624T223326Z" application="Evernote" version="Evernote Mac 1.9.0 (83438)">
<note><title><%= @evernote_note_title %></title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">;
<en-note style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><en-media type="image/jpeg" hash="<%= @evernote_hash %>"></en-media></en-note>]]]]></content><created><%= @evernote_created_date %></created><updated><%= @evernote_created_date %></updated><note-attributes/><resource><data encoding="base64"><%= @imgdata %></data><mime>image/jpeg</mime></resource></note>
</en-export>

このテンプレートを利用する下記のiphoto2evernote.rbというものを作成して実行すると、動的にenexファイルが写真分作成されます。
many-enex
あとはまとめてEvernoteにインポートして、同期したらなんと上手く出来たー

なんかえらく遠回りしたけど、無事にツールが出来て良かったなぁー

require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'base64'
require 'digest/md5'
require 'erb'

class Images2Enex
  def initialize(base_directory)
    @base_directory = base_directory
  end
  attr_accessor :evernote_created_date, :evernote_note_title,:evernote_hash, :imgdata

  def convert
    Dir::glob(@base_directory + "Pages/*.html").each{|f|
      doc = Nokogiri::HTML(open(f))
      _filename = f.split(@base_directory + 'Pages/')
      image_file_name =  _filename[1].split('.html')
      @imgdata = base64_encode(image_file_name[0])
      @evernote_note_title = doc.xpath("//title").inner_html
      @evernote_hash = make_hash(image_file_name[0])
      tds = doc.xpath("//td")
      @evernote_created_date = convert_date_format(tds[10].text)
      template = File.open("evernote_enex01.tmpl") { |f| f.read }
      @result = ERB.new(template, nil, '-')
      make_enex(image_file_name[0])
      end
    }
  end
 
  private
  # Evernote指定の日付フォーマットであるyyyymmddThhmmssZに変換
  def convert_date_format(str)
    separete_str = str.split(" ")
    each_date_element    = separete_str[0].split("/")
    each_minutes_element = separete_str[1].split(":")
    return each_date_element[0] + each_date_element[1] + each_date_element[2]  + "T" + each_minutes_element[0] + each_minutes_element[1] + each_minutes_element[2] + "Z"
  end
 
  def make_hash(filename)
    _filename = @base_directory + "Images/" + filename + ".jpg"
    return Digest::MD5.hexdigest(File.open(_filename,'rb').read)
  end

  def make_enex(filename)
    f = File.open(@base_directory + filename + ".enex","w")
    f.puts @result.result(binding)
    f.close
  end

  def base64_encode(jpeg)
    _jpegfile = @base_directory + "Images/"+ jpeg  + ".jpg"
    return Base64.encode64 File.open(_jpegfile).read
  end
 
end

#iPhotoの写真を吐き出したフォルダ指定
_dir = "/Users/xxx/Desktop/2010-photobook/"
i2e = Images2Enex.new(_dir)
i2e.convert()