JavaScript

2009年01月08日

TomblooでFemoにポストする

前のエントリyoshinonさんという方から「Femoにポストできるようにしてほしい」というコメントがありましたので、実装してみました。

使い方

[2009-01-18 追記] FemoサポートがTombloo 0.3.28で追加されましたので、下記スクリプトを追加する必要がなくなりました。なお、正式版では日付タグの自動追加はありません。

下のリンクからダウンロードして、{ProfD}/tombloo/scriptにコピーしてください。

結構簡単に実装したので、何か問題があればお知らせください。

ブックマークレットでは日付がタグに入るようですが、入力していないタグを勝手に追加するのも行儀が悪いかと思ったので、自動で日付タグを付けたい場合はabout:configで真偽値「extensions.tombloo.femo.appendDateTag」を新規作成して、trueに設定してください。

まとめ

楽だったということもあり、今回はリクエストにお応えする形でスクリプト書きました。

多分あまり使わないと思うので別に構わないですが、Femoのサイトって重いですね。



2009年01月08日 01:47|PermalinkComments(4)TrackBack(1)Mozilla | JavaScript
livedoorクリップ はてなブックマーク

2008年12月28日

Tomblooでclippにポストする

友人がTomblooからclippにポストできたらいいのにとかつぶやいてたので、勉強を兼ねてスクリプトを書いてみました。半月以上使ってみましたが、特に問題なく使えているので、公開しておきます。どうもユーザが少ないみたいで(2ユーザで注目のエントリになったりw)、需要があるかどうかわかりませんが…

◆機能の紹介

clippとは、ソーシャル・スクラップブック(ブックマーク+ミニブログ)らしいです。そちらにTomblooからポストします。

○ポスト

Photo/Quote/Link/Videoに対応しています。(動画はYouTubeとニコニコ動画でしか確認してません)

○リブログ

clippのリブログ可能なエントリがあるページ(「リブログ」という表示が出る)で[Share...]→[ReBlog - Clipp]を選択するとリブログできます。

個別エントリのページではリブログ対象は自明ですが、リブログ可能なエントリを複数含むページでは、ポインタの位置でリブログ対象が決まります。

◆使い方

下のスクリプトをclipp.jsなど適当な名前で保存して、{ProfD}/tombloo/scriptにコピーすると、使えるようになります。

問題があればお知らせいただけると嬉しいです。

[2009-01-18 追記] clippサポートがTombloo 0.3.28で追加されましたので、下記スクリプトを追加する必要がなくなりました。

[2009-01-08 追記] githubに登録しました。

(function() {

var Clipp = {
  name: 'Clipp',
  ICON: 'http://clipp.in/favicon.ico',
  CLIPP_URL: 'http://clipp.in/',

  check: function(ps) {
    return (/(photo|quote|link|video)/).test(ps.type) && !ps.file;
  },
  post: function(ps) {
    var endpoint = this.CLIPP_URL + 'bookmarklet/add';
    var self = this;

    return self.postForm(function() {
      return self.getForm(endpoint).addCallback(function(form) {
        update(form, self[ps.type.capitalize()].convertToForm(ps));

        self.appendTags(form, ps);

        if (ps.type == 'video' && !form.embed_code) {
          // embed_tagを取得してformに設定する
          var address = form.address;
          return request(address).addCallback(function(res) {
            var doc = convertToHTMLDocument(res.responseText);
            var uri = createURI(address);
            var host = uri ? uri.host : '';
            if (host.match('youtube.com')) {
              form.embed_code = $x('id("embed_code")/@value', doc) || '';
            }
            return request(endpoint, { sendContent: form });
          });
        }
        return request(endpoint, { sendContent: form });
      });
    });
  },
  getForm: function(url) {
    return request(url).addCallback(function(res) {
      var doc = convertToHTMLDocument(res.responseText);
      return formContents(doc);
    });
  },
  appendTags: function(form, ps) {
    return update(form, {
      tags: (ps.tags && ps.tags.length) ? joinText(ps.tags, ',') : ''
    });
  },
  favor: function(ps) {
    // メモをreblogフォームの適切なフィールドの末尾に追加する
    var form = ps.favorite.form;
    items(this[ps.type.capitalize()].convertToForm({
      description: ps.description
    })).forEach(function([name, value]) {
      if (!value) return;
      form[name] += value;
    });

    this.appendTags(form, ps);

    return this.postForm(function() {
      return request(ps.favorite.endpoint, { sendContent: form });
    });
  },
  postForm: function(fn) {
    var CLIPP_URL = this.CLIPP_URL;
    var d = succeed();
    d.addCallback(fn);
    d.addCallback(function(res) {
      var url = res.channel.URI.asciiSpec.replace(/\?.*/,'');
      switch (true) {
      case url == CLIPP_URL + 'bookmarklet/add':
        return;
      case url == CLIPP_URL + 'bookmarklet/account/login':
        throw new Error(getMessage('error.notLoggedin'));
      default:
        if (url.match(/edit\/\d+$/)) addTab(url);
        error(res);
        throw new Error('Error posting entry.');
      }
    });
    return d;
  }
};

Clipp.Link = {
  convertToForm: function(ps) {
    return {
      title: ps.item,
      address: ps.itemUrl,
      description: escapeHTML(ps.description)
    };
  }
};

Clipp.Quote = {
  convertToForm: function(ps) {
    return {
      title: ps.item,
      address: ps.itemUrl,
      quote: ps.body ? ps.body.replace(/\n/g, '<br>') : '',
      description: escapeHTML(ps.description)
    };
  }
};

Clipp.Photo = {
  convertToForm: function(ps) {
    return {
      title: ps.item,
      address: ps.pageUrl,
      image_address: ps.itemUrl,
      description: joinText([
        (ps.item ? ps.item.link(ps.pageUrl) : '') + (ps.author ? ' (via ' + ps.author.link(ps.authorUrl) + ')' : ''),
        '<p>' + escapeHTML(ps.description) + '</p>' ], '')
    };
  }
};

Clipp.Video = {
  convertToForm: function(ps) {
    return {
      title: ps.item,
      address: ps.pageUrl,
      embed_code: ps.body || '',
      description: joinText([
        (ps.item ? ps.item.link(ps.pageUrl) : '') + (ps.author ? ' (via ' + ps.author.link(ps.authorUrl) + ')' : ''),
        '<p>' + escapeHTML(ps.description) + '</p>' ], '')
    };
  }
};

models.register(Clipp);

Tombloo.Service.extractors.register({
  name: 'ReBlog - Clipp',
  ICON: 'http://clipp.in/favicon.ico',
  check: function(ctx) {
    return this.getLink(ctx);
  },
  extract: function(ctx) {
    var link = this.getLink(ctx);
    if (link) {
      var self = this;
      var endpoint = Clipp.CLIPP_URL + 'bookmarklet' + link;
      return Clipp.getForm(endpoint).addCallback(function(form) {
        return update({
          type: 'link',
          item: ctx.title,
          itemUrl: ctx.href,
          favorite: {
            name: 'Clipp',
            endpoint: endpoint,
            form: form
          }
        }, self.convertToParams(form));
      });
    }
    return {};
  },
  checkEntryPage: function(ctx) {
    return (/clipp.in\/entry\/(\d+)/).test(ctx.href);
  },
  getLink: function(ctx) {
    return this.checkEntryPage(ctx) ? this.getLinkByPage(currentDocument()) : this.getLinkByTarget(ctx);
  },
  getLinkByPage: function(doc) {
    return $x('//a[contains(@href, "add?reblog=")]/@href', doc);
  },
  getLinkByTarget: function(ctx) {
    return $x('./ancestor-or-self::div[contains(concat(" ", @class, " "), " item ")]//a[contains(@href, "add?reblog=")]/@href', ctx.target);
  },
  convertToParams: function(form) {
    if (form.embed_code)
      return {
        type: 'video',
        item: form.title,
        itemUrl: form.address,
        body: form.embed_code
      };
    else if (form.image_address)
      return {
        type: 'photo',
        item: form.title,
        itemUrl: form.image_address
      };
    else if (form.quote && form.quote != '<br>')
      return {
        type: 'quote',
        item: form.title,
        itemUrl: form.address,
        body: form.quote
      };
    return {
      type: 'link',
      item: form.title,
      itemUrl: form.address
    };
  }
});

})();

◆実装について

最初は20_model.jsなどを参考にしつつ、Atom APIを利用してポストするように実装したのですが、結局requestに相当する部分を自前で書いたりする必要があったので、再度20_model.jsを中心に見直し、formをpostするように書き直しました。着手から1週間くらいで何とか原型が出来上がりました。

あとは31_Tombloo_Service_extractors.jsを参考にしてreblogを追加したり、だらだら使いながら少し修正をしたりという感じです。

本格的にTomblooのソースに目を通したのは初めてだったので、いい勉強になりました。まだ完全には理解できていないですが、Deferredってすごいなとか。

機会があれば他のサービスにもチャレンジしてみたいと思います。



2008年12月28日 02:27|PermalinkComments(8)TrackBack(1)Mozilla | JavaScript
livedoorクリップ はてなブックマーク

2007年11月12日

Crazy Cool Internet Trick!のブックマークレット

クレイジーなGoogleイメージ検索 | GoogleMania - グーグルの便利な使い方」で仕入れたネタ(元ネタは「Crazy Cool Internet Trick!」です)をブックマークレット化してみました。

下のリンクを、右クリックかドラッグでブックマークに追加してください。
Crazy Cool Internet Trick!

Googleイメージ検索で「初音ミク」などの検索結果を表示している状態で、上のブックマークレットを呼び出します。繰り返し呼び出すと、動きが速くなります。単なるCPUの無駄遣いですが…

やっていることは単純なので、改良やカスタマイズもそれほど難しくないと思います。


2007年11月12日 02:36|PermalinkComments(1)TrackBack(0)JavaScript 
livedoorクリップ はてなブックマーク