// ==SiteScript==
// @siteName    Jokeroo
// @siteUrl     http://www.jokeroo.com/video/
// @author      DarkKnight
// @authorUrl   http://darkknightlabs.com/
// @scriptUrl   http://darkknightlabs.com/site-script/
// @description 
// @date        2009/03/22
// @version     0.4
// ==/SiteScript==


function CravingSiteScript() {
    this._initialize();
}


CravingSiteScript.prototype = {
    _xhr: null,
    
    _initialize: function() {},
    
    _getXmlHttpRequest: function() {
        if ( this._xhr != null ) {
            return this._xhr;
        }
        
        var xhr = null;
        var these = [
              function() { return new XMLHttpRequest(); }
            , function() { return new ActiveXObject( "Msxml2.XMLHTTP" ); }
            , function() { return new ActiveXObject( "Microsoft.XMLHTTP" ); }
            , function() { return new ActiveXObject( "Msxml2.XMLHTTP.4.0" ); }
        ];
        
        for ( var i = 0, length = these.length; i < length; i++ ) {
            var func = these[ i ];
            try {
                xhr = func();
                break;
            }
            catch( e ) {}
        }
        this._xhr = xhr;
        
        return this._xhr;
    },
    
    _load: function( url, data, method ) {
        var req = this._getXmlHttpRequest();
        
        var mtd = ( method == null ) ? "GET" : "POST";
        
        req.open( mtd, url, false );
        
        if ( mtd == "POST" ) {
            req.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
        }
        
        req.send( data );
        
        return req.responseText;
    },
    
    getResponseText: function( url, data, method ) {
        return this._load( url, data, method );
    },
    
    getResponseJSON: function( url, data, method ) {
        var text = this._load( url, data, method );
        
        return eval( "("+text+")" );
    },
    
    /// Math
    random: function( limit ) {
        return Math.floor( Math.random() * limit );
    },
    
    /// String
    decodeHtml: function( str ) {
        return str.replace( /&(quot|#34);/ig,    "\"" )
                  .replace( /&(amp|#38);/ig,     "&"  )
                  .replace( /&(apos|#39);/ig,    "'"  )
                  .replace( /&(lt|#60);/ig,      "<"  )
                  .replace( /&(gt|#62);/ig,      ">"  )
                  .replace( /&(nbsp|#160);/ig,   " "  )
                  .replace( /&(frasl|#8260);/ig, "/"  );
    }
}


function MD5() {
    this._initialize();
}


MD5.prototype = {
    _MD5_T: null,
    _MD5_round1: null,
    _MD5_round2: null,
    _MD5_round3: null,
    _MD5_round4: null,
    _MD5_round: null,
    
    _initialize: function() {
        
        _MD5_T = new Array( 0x00000000, 0xd76aa478, 0xe8c7b756, 0x242070db,
                            0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613,
                            0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1,
                            0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e,
                            0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51,
                            0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681,
                            0xe7d3fbc8, 0x21e1cde6, 0xc33707d6, 0xf4d50d87,
                            0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9,
                            0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122,
                            0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60,
                            0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085,
                            0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8,
                            0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7,
                            0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d,
                            0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314,
                            0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb,
                            0xeb86d391
                          );
                          
        _MD5_round1 = new Array( new Array(  0,  7,  1 ), new Array(  1, 12,  2 ),
                                 new Array(  2, 17,  3 ), new Array(  3, 22,  4 ),
                                 new Array(  4,  7,  5 ), new Array(  5, 12,  6 ),
                                 new Array(  6, 17,  7 ), new Array(  7, 22,  8 ),
                                 new Array(  8,  7,  9 ), new Array(  9, 12, 10 ),
                                 new Array( 10, 17, 11 ), new Array( 11, 22, 12 ),
                                 new Array( 12,  7, 13 ), new Array( 13, 12, 14 ),
                                 new Array( 14, 17, 15 ), new Array( 15, 22, 16 )
                               );
                               
        _MD5_round2 = new Array( new Array(  1,  5, 17 ), new Array(  6,  9, 18 ),
                                 new Array( 11, 14, 19 ), new Array(  0, 20, 20 ),
                                 new Array(  5,  5, 21 ), new Array( 10,  9, 22 ),
                                 new Array( 15, 14, 23 ), new Array(  4, 20, 24 ),
                                 new Array(  9,  5, 25 ), new Array( 14,  9, 26 ),
                                 new Array(  3, 14, 27 ), new Array(  8, 20, 28 ),
                                 new Array( 13,  5, 29 ), new Array(  2,  9, 30 ),
                                 new Array(  7, 14, 31 ), new Array( 12, 20, 32 )
                               );
                               
        _MD5_round3 = new Array( new Array(  5,  4, 33 ), new Array(  8, 11, 34 ),
                                 new Array( 11, 16, 35 ), new Array( 14, 23, 36 ),
                                 new Array(  1,  4, 37 ), new Array(  4, 11, 38 ),
                                 new Array(  7, 16, 39 ), new Array( 10, 23, 40 ),
                                 new Array( 13,  4, 41 ), new Array(  0, 11, 42 ),
                                 new Array(  3, 16, 43 ), new Array(  6, 23, 44 ),
                                 new Array(  9,  4, 45 ), new Array( 12, 11, 46 ),
                                 new Array( 15, 16, 47 ), new Array(  2, 23, 48 )
                               );
                               
        _MD5_round4 = new Array( new Array(  0,  6, 49 ), new Array(  7, 10, 50 ),
                                 new Array( 14, 15, 51 ), new Array(  5, 21, 52 ),
                                 new Array( 12,  6, 53 ), new Array(  3, 10, 54 ),
                                 new Array( 10, 15, 55 ), new Array(  1, 21, 56 ),
                                 new Array(  8,  6, 57 ), new Array( 15, 10, 58 ),
                                 new Array(  6, 15, 59 ), new Array( 13, 21, 60 ),
                                 new Array(  4,  6, 61 ), new Array( 11, 10, 62 ),
                                 new Array(  2, 15, 63 ), new Array(  9, 21, 64 )
                               );
                               
        _MD5_round = new Array( new Array( this._MD5_F, _MD5_round1 ),
                                new Array( this._MD5_G, _MD5_round2 ),
                                new Array( this._MD5_H, _MD5_round3 ),
                                new Array( this._MD5_I, _MD5_round4 )
                               );
                               
    },
    
    _MD5_F: function( x, y, z ) { return (x & y) | (~x & z); },
    
    _MD5_G: function( x, y, z ) { return (x & z) | (y & ~z); },
    
    _MD5_H: function( x, y, z ) { return x ^ y ^ z;          },
    
    _MD5_I: function( x, y, z ) { return y ^ (x | ~z);       },
    
    _MD5_pack: function ( n32 ) {
        return String.fromCharCode(   n32          & 0xff ) +
               String.fromCharCode( ( n32 >>> 8  ) & 0xff ) +
               String.fromCharCode( ( n32 >>> 16 ) & 0xff ) +
               String.fromCharCode( ( n32 >>> 24 ) & 0xff );
    },
    
    _MD5_unpack: function( s4 ) {
        return  s4.charCodeAt( 0 )         |
              ( s4.charCodeAt( 1 ) <<  8 ) |
              ( s4.charCodeAt( 2 ) << 16 ) |
              ( s4.charCodeAt( 3 ) << 24 );
    },
    
    _MD5_number: function( n ) {
        while ( n < 0 ) {
            n += 4294967296;
        }
        
        while ( n > 4294967295 ) {
            n -= 4294967296;
        }
        
        return n;
    },
    
    _MD5_apply_round: function( x, s, f, abcd, r ) {
        var a, b, c, d;
        var kk, ss, ii;
        var t, u;
        
        a = abcd[ 0 ];
        b = abcd[ 1 ];
        c = abcd[ 2 ];
        d = abcd[ 3 ];
        kk = r[ 0 ];
        ss = r[ 1 ];
        ii = r[ 2 ];
        
        u = f( s[ b ], s[ c ], s[ d ] );
        t = s[ a ] + u + x[ kk ] + _MD5_T[ ii ];
        t = this._MD5_number( t );
        t = ( ( t << ss ) | ( t >>> ( 32 - ss ) ) );
        t += s[ b ];
        s[ a ] = this._MD5_number( t );
    },
    
    _MD5_hash: function( data ) {
        var abcd, x, state, s;
        var len, index, padLen, f, r;
        var i, j, k;
        var tmp;
        
        state = new Array( 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 );
        len = data.length;
        index = len & 0x3f;
        padLen = ( index < 56 ) ? ( 56 - index ) : ( 120 - index );
        
        if ( padLen > 0 ) {
            data += "\x80";
            for ( i = 0; i < padLen - 1; i++) {
                data += "\x00";
            }
        }
        
        data += this._MD5_pack( len * 8 );
        data += this._MD5_pack( 0 );
        len  += padLen + 8;
        abcd = new Array( 0, 1, 2, 3 );
        x    = new Array( 16 );
        s    = new Array( 4 );
        
        for ( k = 0; k < len; k += 64 ) {
            for( i = 0, j = k; i < 16; i++, j += 4 ) {
                x[ i ] = data.charCodeAt( j     )         |
                       ( data.charCodeAt( j + 1 ) <<  8 ) |
                       ( data.charCodeAt( j + 2 ) << 16 ) |
                       ( data.charCodeAt( j + 3 ) << 24 );
            }
            
            for ( i = 0; i < 4; i++ ) {
                s[ i ] = state[ i ];
            }
            
            for ( i = 0; i < 4; i++ ) {
                f = _MD5_round[ i ][ 0 ];
                r = _MD5_round[ i ][ 1 ];
                
                for ( j = 0; j < 16; j++ ) {
                    this._MD5_apply_round( x, s, f, abcd, r[ j ] );
                    tmp = abcd[ 0 ];
                    abcd[ 0 ] = abcd[ 3 ];
                    abcd[ 3 ] = abcd[ 2 ];
                    abcd[ 2 ] = abcd[ 1 ];
                    abcd[ 1 ] = tmp;
                }
            }
            
            for ( i = 0; i < 4; i++ ) {
                state[ i ] += s[ i ];
                state[ i ] = this._MD5_number( state[ i ] );
            }
        }
        
        return this._MD5_pack( state[ 0 ] ) +
               this._MD5_pack( state[ 1 ] ) +
               this._MD5_pack( state[ 2 ] ) +
               this._MD5_pack( state[ 3 ] );
    },
    
    getHash: function ( data ) {
        var result = "";
        var bit128 = this._MD5_hash(data);
        
        for ( var i = 0; i < 16; i++ ) {
            var c = bit128.charCodeAt( i );
            result += "0123456789abcdef".charAt( ( c >> 4 ) & 0xf );
            result += "0123456789abcdef".charAt( c & 0xf );
        }
        
        return result;
    }
}


function isSiteUrl( url ) {
    if ( url.match( /http:\/\/www\.jokeroo\.com\/.*video.*\/.*\.html/ ) ) {
        return true;
    }
}


function getVideoDetail( url ) {
    var craving = new CravingSiteScript();
    var text = craving.getResponseText( url );
    
    if ( text == null ) {
        return null;
    }
    
    text.match( /<h1 class="titlevideo">\s*(.*?)\s*<\/h1>/ );
    var title = RegExp.$1;
    
    text.match( /param value=&quot;xml=(.*?)&quot;/ );
    var xmlUrl = "http://www.jokeroo.com/api/get/file/" + RegExp.$1 + "?jokeroo";
    
    var md5 = new MD5();
    var randString = md5.getHash( new String( Math.random() ) ).substr( 0, 8 );
    xmlUrl += "&r=" + randString;
    xmlUrl += "&k=" + md5.getHash( randString + RegExp.$1 + "joke" ).substr( 2, 8 );
    
    text = craving.getResponseText( xmlUrl );
    
    if ( text == null ) {
        return null;
    }
    
    text.match( /<playlist url="(.*?)"/ );
    var realUrl = RegExp.$1;
    
    if ( text.match( /<extData a="(.*?)"/ ) != null ) {
        var extData = md5.getHash( RegExp.$1 + "jokeyJoke" ).substr( 2, 4 );
        realUrl += "&k2=" + extData;
    }
    
    return { videoTitle0: title, videoUrl0: realUrl };
}
