理系学生日記

おまえはいつまで学生気分なのか

fraddict-rate を表示する UserScript

こんにちは、体調不良で会社を休んでいるぼくです!!!!!!!!
いつも元気なぼくでも、今日という日は吐き気に負けてて、なんか吐いたり吐かなかったりを繰り返してるかんじです。このように、ぼくという存在はかくも脆く儚いものですから、みなさんはガラス細工を扱うように丁寧にぼくと接しないとダメだ。そうしないと容易にこわれる!!

ところで、ぼくは今日、吐き気があるので喰ったものをなかなか消化できない。そこで、その代わりにと Feed を消化していたところ、どうも fraddict rate という値が流行っているようです。これは、twitter における「フォロワー数/被リスト数」で定義される値みたいで、はてなダイアラーの fraddict-rate は id:tt_clown さんがまとめてくれてたりします。
そして、そのページには、こんなことが書いてある。

Twitter に関しては,一部 Follower の数が指標になってしまう領域もあるそうで,(Follow と Remove を繰り返したり Bot に Follow してもらうなどして)無理やり Follower を増やそうとする人もいるそうです.まだ閾値の検討などは行っていないですが,そういった人達の判別方法の一つとしても利用できるのかもな,と思ったりもしました.

はてなダイアラーの fladdict-rate - Cube Lilac

無理やり Follower を増やしていこうみたいな人もいるようですし、即座に fraddict-rate を確認できないと米軍から爆撃される恐れもあります。そういうわけで、米軍および吐き気とたたかいながら、ぼくは必死で UserScript をこさえたのでした。

Twitter は HTML のスクレイピングを明示的に禁止していますので、DOM 操作のみで follower/list カウントを取得できる、各ユーザのホームのみで fraddict-rate を表示できるようになっています。
あと、NewTwitter のページだと動的にページを作っているみたいで、GreaseMonkey が動作するタイミングで、まだ DOM の構築が終わってないみたいなこともあるっぽい。これに対応するために、100 ms で DOM 要素のポーリングを入れたりしてます。

// ==UserScript==
// @name           fraddict-rate
// @namespace      com.kiririmode
// @include        http://twitter.com/*
// ==/UserScript==
(function () {
    // not scraping, but DOM manipulation
    function main( followerFunc, listFunc, displayNodeFunc ) {
        var fn = followerFunc();
        var ln = listFunc();

        if ( ! fn && ! ln ) {
            setTimeout( function() { main( f, l, c ); }, 100 );
            return;
        }
        // get counts
        var follower  = followerFunc().textContent.replace(/,/g, "").match(/(\d+)/)[0];
        var list      = listFunc().textContent.replace(/,/g, "").match(/(\d+)/)[0];

        // fraddict rate
        var rate = follower/list;
            rate = isNaN(rate)                      ? ""  :
                   rate >= Number.POSITIVE_INFINITY ? ""  :
                                                      "(fraddict: " + rate.toFixed(1) + ")";

        // display
        var rateBox  = document.createElement("div");
            rateBox.appendChild( document.createTextNode( rate ) );
        displayNodeFunc().appendChild(rateBox);
    }

    try {
        var f, l, c;
        // NewTwitter page?
        if ( window.location.hash.length > 0 )  {
            f = function () { return document.getElementsByClassName("user-stats-count").item(2); }
            l = function () { return document.getElementsByClassName("user-stats-count").item(3); }
            c = function () { return document.getElementsByClassName("profile-details").item(0);   }
        } else {
            f = function () { return document.getElementById("follower_count"); }
            l = function () { return document.getElementById("lists_count");    }
            c = function () { return document.getElementsByClassName("screen-name").item(0).parentNode; }
        }
        main( f, l, c);
    } catch (x) {
        GM_log(x.name + ": " + x.message);
    }
})()