LDR/Fastladderを高速化してみる・第2弾

この記事の続き。前とはちょっと違う方向性で。


LDR/Fastladderは起動がちょっともたつくのが難点なのだが、その理由は、フィード一覧を取得するまでに個人設定を読み込んだりと色々待たなければならないことが多いためだ。

UserJS で設定を先に読んでおく

今まではこんな UserJS を使って、あらかじめ保存しておいた個人設定を読ませることにして (さらに、最初に右部分に開くガイドページを消してしまって) 高速化をしていた。

// ==UserScript==
// @include http://fastladder.com/reader/
// @include http://reader.livedoor.com/reader/*
// ==/UserScript==

(function(){

if(location.host == 'reader.livedoor.com'){// for LDR
try{
window.myConfig = /*ほにゃらら*/}catch(e){}
}else{// for Fastladder
try{
window.myConfig = /*ほにゃらら*/}catch(e){}
}

var beforeInitFunc = function(){
  var nativePost = window.API.prototype.post;
  window.API.prototype.post = function(param,onload){
    if(this.ap.indexOf('/api/config/load')==0 && window.myConfig){
      onload(myConfig);
      delete myConfig;
      return;
    }else{
      nativePost.call(this,param,onload)
    }
  }
  //ガイドページを表示しないようにする
  window.init_custom = function(){
    var h = '<div style="font-size:700%;text-align:center;margin-top:300px;">Welcome!</div>';
    $('right_body').innerHTML = h;
    invoke_hook('AFTER_INIT_GUIDE');
  }
  window.default_right_init = init_custom;
  //ここまで
};

if(location.host == 'reader.livedoor.com') {
  window.addEventListener('DOMContentLoaded',function(){
    beforeInitFunc();
    window.removeEventListener('DOMContentLoaded',arguments.callee,false);
  },false)
}else{
  window.opera.addEventListener('BeforeScript',function(e){
    if(e.element.text!='init();')return;
    beforeInitFunc();
    opera.removeEventListener('BeforeScript',arguments.callee,false);
  },false)
}
})()

「ほにゃらら」の部分は何かというと、LDRFastladder

javascript:(function(a){a=new API('/api/config/load');a.raw_mode=true;a.post({timestamp:new Date-0},function(data){alert(data)})})();

というブックマークレットを実行して出てくる文字列をそのままコピーして貼り付ける。

↑このブックマークレットじゃ無理という人もいるみたいですね。うちでは大丈夫ですけど。

Fastladder では上のブックマークレットでも大丈夫だったけど、LDR では raw_mode が無いので無理みたい。下のやつならいけるはず。

javascript:(function(url,func){var x=new XMLHttpRequest;x.open('GET',url,true);x.onload = function(){func(x.responseText)};x.send(null);})('/api/config/load',alert)

ちなみに Opera 限定。Opera 以外でも LDR なら動くようにすることはできるのだけど、Fastladder では (たぶん) どう頑張っても無理。Fastladder は海外からの利用を想定しているので、画像その他の読み込みが終わる前に init 関数を実行しているのだけど、これだと、init 実行の直前にスクリプトを動かすのは (Greasemonkey や GreaseKit では) 無理だ。Opera ではページ読み込み開始と同時に UserJS を実行できるし、任意のスクリプト実行前に UserJS を実行できる専用の関数が用意されているので、それで Fastladder も動かしている。LDR では (Greasemonkey で拡張しやすいように?) load イベントで init 関数が走るようになっているのでこの心配はない。

書き忘れてたけど拡張子は .user.js ではなくて .js で保存。

設定をスクリプトに直接書いておくので、もちろん設定を変更することはできないのが惜しいが、そもそも設定を変更することなど稀なのでほとんど問題にならない。

それから、ガイドページを表示しないようにしたらそれだけ遅延は無くなると思う。この部分は非同期で、フィード一覧取得と同時に行っているのだけど、LDR のガイドページみたいに大量の画像などをさらに取得する場合は通信待ちによってフィード一覧表示が遅くなると思う。まあ気休め程度で。

専用プロキシを使う

上のスクリプトを使っていたのだけど、やっぱりもっと速くならないかなあということで、プロキシスクリプトを書いてみた。

favicon.ico もキャッシュするように微修正。

#!/usr/bin/ruby
require 'webrick'
require 'webrick/httpproxy'

$SAFE = 0
$cache = Hash.new
$filter = [/^\/reader\//,/^\/img\//,/^\/css\//,/^\/js\//,/^\/api\/config\/load$/,/^\/contents\//,/^\/favicon/]
$special_filter = [{:re => /^\/api\/config\/save/, :func => lambda{|p| $cache['/api/config/load'] = nil}}]

class FreaderProxyServer < WEBrick::HTTPProxyServer
  def proxy_service(req, res)
    path = req.request_uri.path

    ['reader.livedoor.com','fastladder.com'].each do |host|
      next if req.request_uri.host != host
      $special_filter.each do |item|
         item[:func].call(path) if path =~ item[:re]
      end

      $filter.each do |re|
        next if re !~ path
        cached = $cache[path]
        if cached != nil
          puts "cache found"
          cached[:header].each{|key,value| res[key]=value}
          res.body = cached[:body]
          return
        else
          super
          if 200 <= res.status && res.status < 300
            header = Hash.new
            res.header.each{|key,value| header[key]=value}
            $cache[path] = {:header => header, :body => res.body}
          end
          return
        end
      end
    end
    super
  end
end

config = {
  :BindAddress => '127.0.0.1',
  :Port => 5430,
  :Logger => WEBrick::Log.new($stderr),
  :ProxyContentHandler => nil,
  :ProxyVia => false,
}
s = FreaderProxyServer.new(config)
trap('INT') { s.shutdown }
s.start

これを走らせておいて、ブラウザには以下のような proxy.pac を読ませる。

function FindProxyForURL(url, host) {
  if ( dnsDomainIs(host, "fastladder.com") )
    return "PROXY 127.0.0.1:5430";
  else
    return "DIRECT"
}

この状態で Fastladder を一度開くと、適切なリクエストをキャッシュしてくれるので、その後はページがサクサク開く。(LDR の場合は proxy.pac の "fastladder.com" のところを "reader.livedoor.com" に変える)


このスクリプトExerbWindows 用のアプリケーションにしようと思ったのだけど、生憎自分は Windows 環境を持っていないので断念した。

このあたりを参考にすれば出来るはずなんだけど。