Page 3/16: « 1 2 3 4 5 6 7 8 9 »

2007-04-11

livedoor Readerの自動スクロール機能

3ヶ月ぐらい前に実装したんだけど、誰も言及してないので書いておきます。livedoor Readerの自動スクロール機能はここにあります。



- ダブルクリックして押しっぱなしにすると自動スクロールになります。
- ダブルクリックの速度で、自動スクロールの速度が変化します。
- 右クリックで逆スクロールします(Opera以外)

こういう実験的な機能は試しに実装してみて、親しい人の反応を見てみたりするのだけど、「その場所どうやって表示するの?」と、ことごとく言われた。

2007-04-05

YAPC::Asia2007でしゃべります

LTでしゃべります。

資料、カーソルキーの左右で移動。
http://ma.la/files/yapcasia2007/

2007-04-03

YAPC::Asia2007のチケットを余らせてしまったので欲しい人いたらメール下さい

YAPCのチケットを1枚余らせてしまったので、
subjectを「YAPCのチケット欲しい」にして
本文にブログのURLを書いてtimpo at ma.la宛に送って下さい。

先着1名様にタダであげます。期限は本日中で。

----
決まりましたので終了しました。
短期間にたくさんのご応募ありがとうございました。

2007-04-01

株式会社ライブドアへと入社してから1年3ヶ月目にかけての正直な思い

ライブドアに入る前の年末のクリスマス商戦の頃、Amazonのアフィリエイトでエロゲ(ToHeart2とか人妻戦隊アイサイガーとか)が大量に売れていた時期があって、その月の収入だけで10万円ぐらい入った。

そのお金は、今、会社で使っているPCの購入に使った。

月10万円あれば、贅沢をしなければぎりぎり1人で生きていけるだけの金額だ。
なんとなく。ニートのままでも、負い目なく生きていけるんじゃないかという気がした。

(中略)

そういう人が足りないと思います。

そろそろdankogaiに一言いっておくか

まあ、なんか褒めてくれたり、言及してくれるのはいいんだけど、弾さんlivedoor Reader使ってないよね。

2007-03-22

livedoor Readerにdel.icio.usのブックマーク数を表示するGreasemonkeyスクリプト

画像でブックマーク数が取れるようになったっぽいので作ってみました。
JavaScriptでURLのMD5ハッシュを計算するので、多少遅くなる可能性があります。最近のCPUなら問題ないはず。
http://la.ma.la/misc/userjs/ldr_with_delicious_count.user.js

以前作ったやつ。

livedoorクリップ
http://la.ma.la/misc/userjs/ldr_with_livedoor_clip_count_images.user.js

はてなブックマーク
http://la.ma.la/misc/userjs/ldr_with_hatena_bookmark_count_images.user.js

livedoor Readerに何かくっつけるGreasemonkeyの書き方
http://la.ma.la/blog/diary_200610182325.htm

2007-03-19

アメブロのオフィシャルブログ画像保護機能を無効化するGreasemonkeyスクリプト

現在見ているページをGM_xmlhttpRequestで受信するため、amebloのPVが増えます。さすがYappoです。
http://subtech.g.hatena.ne.jp/yappo/20070319/1174293065

なのでちょっと書き直してみました。
http://la.ma.la/misc/userjs/ameblo_sucks.user.js

イベントはremoveEventListenerで外したいところですが、元の関数が参照できないと無効化できないので、onclickやoncontextmenuに直接代入してます。GreasemonkeyではDOMへの参照はラッピングされたオブジェクトが帰ってくるのでunsafeWindow経由で操作を行う必要があります。

Greasemonkey以外のuserjs実装でも動くように書いてみたつもりです。
どうぞご利用ください。

追記

JavaScriptで追加された既存のイベントを全部消したかったら、こういうブックマークレットでOK。
javascript:document.body.innerHTML=document.body.innerHTML;void(0);

ただし再描画されるのでそれなりに重い可能性があるのと、有効になってて欲しいイベントも消えてしまうことがある。
なのでYappoさんのGreasemonkeyと同等のコードはこれで出来る。
(function(){
    var w = (typeof unsafeWindow == 'undefined') ? window : unsafeWindow;
    var onload = w.onload;
    w.onload = function(){
        onload();
        document.body.innerHTML = document.body.innerHTML;
    }
})();

2007-03-07

アメブロの新着ブログのRSSを適当に読み上げるページを作った

アメブロの有名人ブログの新着ページからリンク抽出してRSSを取得してMSAgentを使って音読してくれるページを作った。Windows IE専用です。それ以外でも一応見れますが音は出ません。
http://la.ma.la/misc/ameblo/

MSAgentが使える必要があります。MSAgentというのはMicrosoft製の伺かみたいなやつで、WindowsMe以降なら標準で入ってます。
Plaggerで使ってたりするやつ。MSAgentで使う日本語の読み上げエンジンは無料でダウンロードできます。MSOfficeが入ってれば最初から入ってたりします。

参考: http://blog.livedoor.jp/hakin/archives/50561235.html


何か色々言いたいことがあったんだけど忘れた。

2007-03-04

coCommentの拡張機能をいれるとlivedoor Readerの動作がおかしくなるらしいので調べてみた

似たようなのを続けて見たので調査してみた。

http://d.hatena.ne.jp/ekken/20070303/1172921555
http://d.hatena.ne.jp/babie/20070227/1172547987

coCommentのFirefox用の拡張が原因っぽい。手元のFirefox2だとXULのエラーが出て上手くインストールできなかったんだけど、ソースを読んで調べてみた。

原因はこのソースが読み込まれてるからだと思われる。
http://www.cocomment.com/js/core.js

coCommentの拡張機能はページを読み込むたびにブックマークレットを実行するのと同じようなことをしてるみたい。その際に、サイト側で定義してある関数を上書きしてしまうことがある。$とString.prototype.stripが再定義されていて、これがlivedoor Readerが動かなくなる原因だろう。他にもグローバル変数使いまくり。なんというか全般的におかしい。相性とかそういう類のものではなくて、単にcoCommentのJavaScript書いてる人が素人なだけ。

こっち側ではどうしようもないのでcoCommentの方に文句を言ってください。

感想

Firefoxの拡張機能は、分かってる人であれば中身を解凍してソースを見て、その段階で安全かどうかを判断することができるけど、ウェブサイト上に置いてあるJSを動的に読み込むようなことをしてしまうと、いつでも改変することが出来るので安全性を保障できない。(インストールした時点では安全でも、後から悪意のある拡張機能にいつでも変更できるということ)

ブックマークレットで使っているソースと共通化することが出来るので、メンテナンスコストを下げることができる。そういう理由でこういった実装にするのは、ありえないことではないとは思うけど、せめて普通は拡張機能側で適用可能なサイトかどうかを判別してからやるものだと思います。

2007-03-03

Yahoo pipesを使ってid:hamster009さんのいい加減な回答を全文フィードにするチュートリアル

hamster009さんの回答履歴
http://q.hatena.ne.jp/hamster009/answerlist

が、面白いのでウォッチしてみる。URLに「?mode=rss」を付けるとRSSを取得できるのだけれど、この回答履歴のフィードには質問文しか入っておらず、リンク先をクリックしないと回答文が読めない。ネタバレとか気にしてないので全文入れて欲しいところだ。これは人力検索の回答を日記代わりに使ってるhamster009さんのような人にとっては重大な問題のはずなので、さっさと利用規約改定すべき。

そんなわけで、今回はYahoo pipesを使ってhamster009さんの回答を全文フィードにしてみることにする。
下記のような手順でプログラミングができない私にも簡単にマッシュアップすることができた。

1. 米Yahooのアカウントを取得。
2. Yahoo pipesを表示。create a new pipeで新規パイプを作成。
3. 入力ソースでfetchモジュールを追加して、回答履歴RSSのURLを入れる。
4. linkが質問のページになってるので一覧を取得してそれぞれに?mode=rssをくっつけて、全部のRSSを取得してマージしてfilterでdc:creatorがhamster009の記事だけ残すようにすれば良いんだな。
5. 30分ぐらい試行錯誤する。
6. ブラウザを閉じる。
7. Automatorを初めて起動する。終了する。
8. Plaggerでやろうとして、やっぱりやめる。
9. 自分でスクリプト書く

出来上がり
http://feeds.feedburner.com/hamster009


ところで
Q: バソキヤ2006を売っている店を探しています。
A: 来年までまちましょう。
http://q.hatena.ne.jp/1160648378

Q: バソキヤ2006を売っている店を探しています。
A: 見つかるといいですね。
http://q.hatena.ne.jp/1160729694

Q: バソキヤ2006を売っている店を探しています。
A: いいかげんにあきらめたら。
http://q.hatena.ne.jp/1160736696


思い出したら腹が立ってきた。

2007-02-28

「ニコニコ動画はYouTubeにとって脅威になったのでアクセス拒否された」みたいな論調に話を持って行きたがる人たちについて

割とどうでもいいとは思ってるんだけど書いておくことにする。ここら辺読んで思ったこと。

http://shi3z.cocolog-nifty.com/blog/2007/02/youtubeweb20_0171.html
http://blog.livedoor.jp/lalha/archives/50154713.html
http://mindclip.blog55.fc2.com/blog-entry-121.html

通常の利用頻度でAPI使ってて他は大丈夫なのに自分だけアクセス拒否された!ってことなら、敵視されてるんじゃないか
とかそういう陰謀論が起こるのも理解できるんだけど。

「アクセス拒否=敵視されている」みたいな発想が短絡的だと思う。利用方法に問題があって異常なアクセスがあれば、普通にアクセス拒否すると思うんだけど。敵視してるとかそういうのとは全く関係なしに。

YouTubeの動画を全画面表示したり字幕くっつけたりするのを作るには、動画の元ファイル(flv)のURLを知る必要がある。これはAPI使ってるだけだと出来ないので、スクレイピングというやつをする。具体的には動画の貼られているURLにアクセスして、一定期間有効らしいトークン文字列を抜き出して、get_videoにvideo_idとトークン文字列をわたすとflvのURLにリダイレクトされる、ということらしい。

少なくともニコニコ動画は通常のAPI利用じゃない、はずだ。公開されてるAPIを使ってて蹴られたっていうならケチくさいな、と文句言えばいいけど、スクレイピングしてやってるんだから、いつアクセス拒否されてもおかしくないし、それはYouTube側の当然の権利だろう。flvの直接利用ってのもデリケートな問題だ。ビデオファイルを直接保存されてしまうと、アップロードした権利者のコントロールが及ばなくなる。

この辺り参考になる。
http://saqoosha.net/2007/02/23/466/

ニコニコ動画の担当者のインタビューというのを見つけたんだけど、これは公式な発言と捉えていいのかな。
http://ascii.jp/elem/000/000/020/20245/

Q YouTube側からアナウンスはあったか?
A 特にない。こちらでアクセスが遮断されているのに気づいた。

Q YouTubeの動画をAPIで呼び出す際の約款上、何か問題はなかったか?
A それはなかったと認識している

自分たちのやり方に問題はなくて、一方的にアクセス拒否された、みたいなことを言いたいらしい。
ほんとに?スクレイピングしてないの?flvのURLを取り出す隠しAPIとかあるのかな。何コールまで許されてるの?
そんなのあったらビデオダウンロードされまくりで回線を占有されてしまってYouTubeが全く使い物にならなくなると思うんだけど。

かといって、APIがないから使っちゃダメ、とか、そういうことを言いたいわけでもなくて。

著作権とか二次利用の問題、サーバー負荷の問題とかいろいろな問題を抱えることがあって、とりあえず試しにスクレイピングで作ってみて、それが便利だったり面白かったりしたら、フィードを提供しましょう、APIを作りましょう、とか、そういう友好的で発展的な話になる場合もある。コストがかかるようなら提供先を制限したり、あるいは有料で提供したり、といった話になる。

いぬビームがgreasemonkeyを書いたらはてながAPI作りました、とかね。極端に分かりづらい例だけど。スクレイピングで大量にアクセスされるよりは、負荷の軽いAPIを作ったのでそっち使ってね、みたいなことだってあり得るわけで。

何でそんなに「敵対企業にはビデオを自由に使わせません!」みたいな事にしたがるんだろうか。実際にそういうこともあるかもしれないけど、単にニコニコ動画の側に対話能力が欠けてるだけなんじゃないかと思うんだけど。

2007-02-21

遅延評価を使ってSjaxをAjaxに変換する方法

継続を使ってSjaxをAjaxに簡単に変換する方法
http://d.hatena.ne.jp/llamerada/20070220/1171984586

を見て。こんなのはどうだろう。

ユーザーからの入力や、非同期のHTTPリクエストなんかを、具体化されてないオブジェクトとして捉えて、それらを受け取った関数側が遅延オブジェクトを具体化するためのリクエストを投げて再試行する。ネストが深くならないですむ、同期処理で書く場合との変更点が少ない、あるいは完全に差異を無くすことができる。

alert(args)のコメントを外せば、引数が具体化されていく様子が分かるはず。

Function.prototype.receive_lazy = function(){
    var orig = this;
    return function(){
        var thisObj = this;
        var me = arguments.callee;
        var args = Array.prototype.slice.apply(arguments);
        // alert(args);
        function retry(i, as_force){
            return function(arg){
                if(!isLazy(args[i])) args[i] = args[i].value;
                if(as_force && typeof arg == "function"){
                    arg(me.apply(thisObj, args));
                } else {
                    return me.apply(thisObj, args)
                }
            }
        }
        for(var i=0;i<args.length;i++){
            if(isLazy(args[i])){
                args[i].force(retry(i));
                return {isLazy:true, force: retry(i, true)}
            }
        }
        return orig.apply(this, args);
    }
};
function isLazy(obj){
    return typeof obj == "object" && obj.isLazy
}

// ここからが実際に記述する部分
function fetch(path, length, offset, cont){
    var range = ["bytes=" + offset + "-" + (offset + length - 1)].join("");
    var options = {
        method: "get",
        onComplete: function(request){cont(request.responseText);},
        requestHeaders: ["Range", range]
    }
    new Ajax.Request(path, options);
}
fetch = fetch.receive_lazy();
function lazy_fetch(path, length, offset, inflate){
    var lazy_object = {
        isLazy: true,
        force: function(callback){
            fetch(path, length, offset, function(responseText){
                lazy_object.isLazy = false;
                lazy_object.value = 
                    (typeof inflate == "function")
                     ? inflate(responseText) 
                     : responseText;
                callback(lazy_object.value);
            });
        }
    };
    return lazy_object;
};
function fetch_data(){
    var path = "/data.txt";
    var offset = lazy_fetch(path, 4, 0, parseInt);
    var length = lazy_fetch(path, 4, 4, parseInt);
    return lazy_fetch(path, length, offset);
}

// ここでalertも変形させてしまえば同期処理のコードとほとんど同じになる
fetch_data().force(alert)


処理の流れは、
- lazyなオブジェクトを引数に受け取ったら
-- 引数を具体化するためのforceメソッドを呼び出す
-- オブジェクトが具体化されたら、関数を再度実行する
- 全ての引数が具体化されたらオリジナルの関数に処理を引き渡す

Function.prototypeにreceive_lazyメソッドを加えて、あらかじめ遅延評価な変数を受け取れるように関数を変形しておく必要がある。考え方としては、コードを書くときに非同期処理を完全に意識しないで済むようにしたい。非同期に合わせて書くのではなく、同期処理のつもりで書いたコードが、いつのまにやら非同期処理になってる、というのがやりたい。

2007-02-20

まるごとJavaScript売ってます

原稿落としてすいませんでした。


2007-02-17

OPML生成サービスを作りました

livedoor Reader、Bloglines、はてなRSSを公開設定で使っているユーザーのOPMLをマージして、これは読んでおいた方がいい、というフィードのリストを作るサービスを作りました。

サンプルで最初からいくつか入れてありますが、プログラマが読んでおいた方がいい、ってのが出るように適当にピックアップしてみました。
レンタルサーバーなので、あんまり沢山いれると処理時間が長くて表示できません。ソース公開してるので適当に改造して使ってください。

http://la.ma.la/opmlburner/

2007-02-16

JavaScriptの関数の結果を期限付きでキャッシュする

処理に時間がかかるけれども、一定時間は結果が変わらないような関数の結果をキャッシュしたい。

例えばgetElementsByTagName("*")なんかを頻繁に呼び出すようなコードがあったとして、結果をキャッシュしたいけれど画面描画が発生すると使えなくなってしまう。setTimeoutで0ミリ秒後にキャッシュを消す処理を入れておいて、画面描画と関係のある処理はタイマーで実行するような制約を付けてコードを書けばDOMが絡む処理の結果もキャッシュすることができる。というようなケースに使えるような気がする。
Function.prototype.timed_memoise = function(ms){
    var self = this;
    ms = ms || 0;
    var memo = {};
    var clear_q = false;
    function clear_cache(){memo={};clear_q=false}
    return function(){
        var args = Array.prototype.slice.apply(arguments);
        if(!clear_q){
            setTimeout(clear_cache, ms);
            clear_q = true;
        }
        var key = "_" + args.join(',');
        return (key in memo) ? memo[key] : (memo[key] = self.apply(this,arguments));
    }
};
some_function = some_function.timed_memoise(expire);