capture.tumblr.jsをgelato対応に2008年02月29日 23時55分54秒

とりあえずやってみました

ブラウザでキャプチャしてアップロードするJSActionsスクリプトシリーズのtumblrにアップロードするバージョンです。
という、激しく便利なJSActionスクリプトをgelatoに対応させてみた。

キャプチャサンプル
図はtumblrのダッシュボードをキャプチャしてgelatoに放り込んだものをさらにgelatoにキャプチャして、それをキャプチャしてtumblrに放り込んだもの。何いってんだかわかんなくなってきた。

どのあたりをどう変えるか

さて、一所懸命ソースを見てみましたよ。

URLの体系が違う

まず、URLの生成方法がまったく違う。capture.tumblrはTumblr write APIを使っているが、gelatoはそんな機能はないのでadmin/index.phpに直接POSTする必要がある。

このあたりを担当しているのが、269行目からの「Tumblr」オブジェクトらしい。このオブジェクトはベースURLになる「endpoint」プロパティとリクエストを実行する「post」メソッドが実装されているが、どちらも変更する必要がある。

POSTする内容が違う

そして当然POSTする内容が違うので、このあたりを扱う部分にも変更を加える必要がある。これは「ImageSaver」オブジェクト(296行目から)の「post」メソッド(451行目から)だ。

gelatoでphotoをPOSTする場合は

  • title → コンテンツのタイトル
  • description → オプションの説明文
  • type → コンテンツタイプ。photoは「2」になる
  • date → 投稿日時。UNIXタイムスタンプ形式
  • btnAdd → submitボタンなのだが、POST時にadmin/index.phpでこれをissetチェックしているのでつけてやる必要がある
と、イメージストリーム本体の「photo」を送る必要がある。

ちょっとだけ修正してやる必要もある

イメージストリームの流し込み方などはcapture.tumblr.jsそのままになるので、Tumblr.post()に渡すオブジェクトを上記のように整えてやればよいのだが、tumblrでは必要としないfilenameを与えてやる必要もある。

08.03.01付けの0.0.1bで修正されたようです。HTTP.Request.prototype.create_streamへの修正作業は不要になりました。(08.03.02追記)

この「filename」を与えてやるにあたり、もう一箇所修正が出てくる。マルチパートのストリームを生成している、HTTP.Requestクラスのcreate_streamメソッドだ。

173行目でfilenameが与えられていた場合にそれをリクエストに追加するのだが、ここでパラメータオブジェクト名を除いた変数でアクセスしているため、これを修正しないと例外になる。tumblrの場合はこのロジックを通らないので見つからなかったバグなのだろう。

そんなわけでこんなやり方

こんな感じで手を加える部分がちょっと散っているので、

  • Tumblrオブジェクトはまるまる再定義
  • ImageSaver.postメソッドもまるまる再定義
  • create_streamメソッドは173行目を修正
といった感じで実装してみた。

修正コードのみですが

こんな感じで。

Tumblrオブジェクトの再定義

Tumblr = {
  // set your gelato admin page.
  endpoint : "http://localhost/gelato/admin/index.php",
  post : function(params, opts) {
    opts.multipart = true;
    return new HTTP.Request(this.endpoint, opts).post(params);
  }
}

opts.multipartへの値の割り当ては、オリジナルではparams.typeの内容をチェックしていたのだが、どうせマルチパート確定なので直接trueをセットしている。あとはURLはendpointに何も手を加える必要がないのでこんな感じになった。

ImageSaver.postメソッドの再定義

ImageSaver.post = function(title, bstream) {
  try {
    var uri = window.content.document.location.href;
    var file_name = (function() {
      var buf = [];
      for(var i = 0; i < 3; i++) {
        var s = ( Math.random() * ( new Date().valueOf() ) ).toString().replace(".", "");
        buf.push( Number(s).toString(36) );
      }
      return "capture-" + buf.join("").slice( -10 ) + ".png";
    })();

    Tumblr.post( {
      url: "",
      title: title,
      description: "(via: " + title.link(uri) + ")",
      type: 2,
      date: parseInt( new Date().valueOf() / 1000 ),
      btnAdd : "Create post",
      photo: {contentType: 'image/png', filename: file_name, stream: bstream}
    }, {
      async: true,
      onStopRequest: function (request, context, statusCode) {
        request.QueryInterface(Components.interfaces.nsIHttpChannel);
        var text = request.responseStatusText;
        trace(this.response_body);
        if ( ImageSaver.conf.id ) {
          text = text.fontcolor("white").link(
            'http://' + ImageSaver.conf.id + '.tumblr.com/post/' +
            this.response_body
          );
        }
        ImageSaver.close_text_delayed(text);
      }
    } );
  } catch(e) {
    Firebug.Console.log(e);
  }
}

Tumblr.post()に渡しているオブジェクトの構成は前述の通り。ローカル変数「file_name」はphotoに割り当てるファイル名なのだが、gelatoはかなり何も考えてなくて、同じ名前のファイルをアップロードすると無条件に上書きするというステキ仕様なので、仕方なくランダム生成している。 あとの例外ハンドリングなどはオリジナルコードそのまま。

上記2つのコードブロックを、capture.tumblr.jsの実行コード(new function() ~から始まる部分。542行目)の直前にそのまま差し込むことで再定義ができる。

そしてHTTP.Requestのcreate_streamだが、

chunk += 'filename="' + filename + '"' +  '\r\n';
chunk += 'filename="' + stream_params.filename + '"' +  '\r\n';
と修正すればよい。

あとはこの追加・修正を適用したファイルを「capture.gelato.js」とでもしてJSAスクリプトのglobalフォルダに放り込めば使える。ハズ。動かなかったらコメント下さい。といってもgelato使ってる人なんざほとんどいないだろうけど。

あ、あと38行目のconffileの設定は別にどうでもいいです。内容を参照しないので、ファイルさえあれば大丈夫なはずなので。