XuanFengEx

QQ旋风网页版离线下载增强

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name       XuanFengEx
// @namespace  https://github.com/rhyzx/xuanfeng-userscript
// @version    0.8.0
// @description  QQ旋风网页版离线下载增强
// @match      http://lixian.qq.com/main.html*
// @copyright  2016+, rhyzx
// ==/UserScript==


/**
 * export downloads
 */
injectScript(function () {
// ======

var $       = window.jQuery // v1.6.1
  , msg     = window.XF.widget.msgbox

// export / rewrite
$('#task_dl_local em').text('导出下载')
EventHandler.task_batch2local = function (e) {
    if ($(e).hasClass('disabled_btn')) return
    msg.show('获取下载地址中...', 0, 5000)

    requestDownloadLinks(function (dls) {
        msg.hide()
        g_pop_export.setDownloads(dls)
        g_pop_export.show()
    })
}



// get selected tasks' download link/cookie/filename
// callback(dowloads)
function requestDownloadLinks(callback) {
    var count = 0
      , downloads = []

    // TODO? pre-check task status by
    // $.getJSON('/handler/lixian/get_lixian_items.php')
    $.Deferred().resolve(g_task_op.last_task_info)
    .done(function (res) {
        $.each(res, function (i, task) {
            // check
            if (
                !$('#task_sel_' +task.mid).is(':checked')|| // user selected
                task.file_size !== task.comp_size        || // download finished
                task.dl_status !== TASK_STATUS['ST_UL_OK']
            ) return


            count++
            $.post('/handler/lixian/get_http_url.php', {
                hash    : task.hash
              , filename: task.file_name
              //, g_tk    : getACSRFToken(cookie.get('skey', 'qq.com'))
              //, browser : 'other'
            }, null, 'json')
            .done(function (res) {
                count--
                if (res && res.ret === 0) {
                    // break speed limit
                    // thanks @4023 https://userscripts.org/users/381599
                    var url = res.data.com_url
                        .replace('xflx.store.cd.qq.com:443', 'xfcd.ctfs.ftn.qq.com')
                        .replace('xflx.sz.ftn.qq.com:80', 'sz.disk.ftn.qq.com')
                        .replace('xflx.cd.ftn.qq.com:80', 'cd.ctfs.ftn.qq.com')
                        .replace('xflxsrc.store.qq.com:443', 'xfxa.ctfs.ftn.qq.com')

                    downloads.push({
                        url         : url
                      , cookie      : res.data.com_cookie
                      , filename    : task.file_name
                    })
                }
            })
            .fail(function () {
                msg.show('获取失败', 2, 2000)
            })
            .always(function () {
                if (count === 0) {
                    // sort according to filename
                    downloads.sort(function (a, b) {
                        return a.filename.localeCompare(b.filename)
                    })
                    callback(downloads)
                }
            })

        })
    })
    .fail(function () {
        msg.show('获取列表的接口坏了嘛?! 请联系脚本作者', 2, 2000)
    })
}
window.requestDownloadLinks = requestDownloadLinks // export to global

/// =====
})


/**
 * aria rpc
 */
injectScript(function recall() {
// ======

var $       = window.jQuery
  , msg     = window.XF.widget.msgbox


// button
var $export = $('#task_dl_local')
var $rpc = $export.clone()
            .removeAttr('onclick')
            .attr('id', 'task_dl_rpc')
            .find('em').text('RPC').end()
            .insertAfter($export)

// diable/enable botton
$(document).click(function () {
    $export.hasClass('disabled_btn')
        ? $rpc.addClass('disabled_btn')
        : $rpc.removeClass('disabled_btn')
})


$rpc.click(function (evt) {
    if ($rpc.hasClass('disabled_btn')) return

    var config = {
        url : localStorage.getItem('rpc-url')
      , token : localStorage.getItem('rpc-token')
    }
    if (config.url) {
        msg.show('获取下载地址中...', 0, 5000)
        requestDownloadLinks(function (dls) {
            msg.show('rpc请求中...', 0, 5000)

            rpc(dls, config)
            .done(function (res) {
                msg.show('成功', 1, 2000)
            })
            .fail(function ($xhr, status, error) {
                msg.show('rpc请求失败,请检查设置,Message: ' +error, 2, 2000)
                g_pop_rpc.showConfig(config)
            })
        })
    } else {
        msg.show('rpc未设置', 3, 2000)
        g_pop_rpc.showConfig() // default url
    }
})


function rpc(dls, config) {
    var data = []
    $.each(dls, function (k, dl) {
        var ret = {
            jsonrpc : '2.0'
          , id      : 'down_' +k
          , method  : 'aria2.addUri'
          , params  : [
                [dl.url]
              , {
                    out     : dl.filename
                  , header  : 'Cookie: FTN5K=' +dl.cookie
                  , continue: 'true'
                  , split   : '10'
                  , 'max-connection-per-server' : '10'
                }
            ]
        }
        if (config.token) {
          ret.params.unshift('token:' +config.token)
        }
        data.push(ret)
    })

    // return Deferred Obj
    return $.post(config.url, JSON.stringify(data))
    // filter error
    .pipe(function (res, status, $xhr) {
      if (res[0].error) {
        return $.Deferred().reject($xhr, 'error', res[0].error.message)
      }
    })
}

/// =====
})


/**
 * auto login
 */
injectScript(function recall() {
// ======

// function from http://imgcache.qq.com/ptlogin/ver/10021/js/comm.js
var hexchar2bin=function(str){var arr=[];for(var i=0;i<str.length;i=i+2){arr.push("\\x"+str.substr(i,2))}arr=arr.join("");eval("var temp = '"+arr+"'");return temp}
var md5=function(){var r=1;var n="";var t=8;var a=32;function u(r){return e(r)}function e(r){return g(v(A(r),r.length*t))}function v(r,n){r[n>>5]|=128<<n%32;r[(n+64>>>9<<4)+14]=n;var t=1732584193;var u=-271733879;var e=-1732584194;var v=271733878;for(var i=0;i<r.length;i+=16){var s=t;var A=u;var g=e;var b=v;t=f(t,u,e,v,r[i+0],7,-680876936);v=f(v,t,u,e,r[i+1],12,-389564586);e=f(e,v,t,u,r[i+2],17,606105819);u=f(u,e,v,t,r[i+3],22,-1044525330);t=f(t,u,e,v,r[i+4],7,-176418897);v=f(v,t,u,e,r[i+5],12,1200080426);e=f(e,v,t,u,r[i+6],17,-1473231341);u=f(u,e,v,t,r[i+7],22,-45705983);t=f(t,u,e,v,r[i+8],7,1770035416);v=f(v,t,u,e,r[i+9],12,-1958414417);e=f(e,v,t,u,r[i+10],17,-42063);u=f(u,e,v,t,r[i+11],22,-1990404162);t=f(t,u,e,v,r[i+12],7,1804603682);v=f(v,t,u,e,r[i+13],12,-40341101);e=f(e,v,t,u,r[i+14],17,-1502002290);u=f(u,e,v,t,r[i+15],22,1236535329);t=o(t,u,e,v,r[i+1],5,-165796510);v=o(v,t,u,e,r[i+6],9,-1069501632);e=o(e,v,t,u,r[i+11],14,643717713);u=o(u,e,v,t,r[i+0],20,-373897302);t=o(t,u,e,v,r[i+5],5,-701558691);v=o(v,t,u,e,r[i+10],9,38016083);e=o(e,v,t,u,r[i+15],14,-660478335);u=o(u,e,v,t,r[i+4],20,-405537848);t=o(t,u,e,v,r[i+9],5,568446438);v=o(v,t,u,e,r[i+14],9,-1019803690);e=o(e,v,t,u,r[i+3],14,-187363961);u=o(u,e,v,t,r[i+8],20,1163531501);t=o(t,u,e,v,r[i+13],5,-1444681467);v=o(v,t,u,e,r[i+2],9,-51403784);e=o(e,v,t,u,r[i+7],14,1735328473);u=o(u,e,v,t,r[i+12],20,-1926607734);t=c(t,u,e,v,r[i+5],4,-378558);v=c(v,t,u,e,r[i+8],11,-2022574463);e=c(e,v,t,u,r[i+11],16,1839030562);u=c(u,e,v,t,r[i+14],23,-35309556);t=c(t,u,e,v,r[i+1],4,-1530992060);v=c(v,t,u,e,r[i+4],11,1272893353);e=c(e,v,t,u,r[i+7],16,-155497632);u=c(u,e,v,t,r[i+10],23,-1094730640);t=c(t,u,e,v,r[i+13],4,681279174);v=c(v,t,u,e,r[i+0],11,-358537222);e=c(e,v,t,u,r[i+3],16,-722521979);u=c(u,e,v,t,r[i+6],23,76029189);t=c(t,u,e,v,r[i+9],4,-640364487);v=c(v,t,u,e,r[i+12],11,-421815835);e=c(e,v,t,u,r[i+15],16,530742520);u=c(u,e,v,t,r[i+2],23,-995338651);t=h(t,u,e,v,r[i+0],6,-198630844);v=h(v,t,u,e,r[i+7],10,1126891415);e=h(e,v,t,u,r[i+14],15,-1416354905);u=h(u,e,v,t,r[i+5],21,-57434055);t=h(t,u,e,v,r[i+12],6,1700485571);v=h(v,t,u,e,r[i+3],10,-1894986606);e=h(e,v,t,u,r[i+10],15,-1051523);u=h(u,e,v,t,r[i+1],21,-2054922799);t=h(t,u,e,v,r[i+8],6,1873313359);v=h(v,t,u,e,r[i+15],10,-30611744);e=h(e,v,t,u,r[i+6],15,-1560198380);u=h(u,e,v,t,r[i+13],21,1309151649);t=h(t,u,e,v,r[i+4],6,-145523070);v=h(v,t,u,e,r[i+11],10,-1120210379);e=h(e,v,t,u,r[i+2],15,718787259);u=h(u,e,v,t,r[i+9],21,-343485551);t=l(t,s);u=l(u,A);e=l(e,g);v=l(v,b)}if(a==16){return Array(u,e)}else{return Array(t,u,e,v)}}function i(r,n,t,a,u,e){return l(s(l(l(n,r),l(a,e)),u),t)}function f(r,n,t,a,u,e,v){return i(n&t|~n&a,r,n,u,e,v)}function o(r,n,t,a,u,e,v){return i(n&a|t&~a,r,n,u,e,v)}function c(r,n,t,a,u,e,v){return i(n^t^a,r,n,u,e,v)}function h(r,n,t,a,u,e,v){return i(t^(n|~a),r,n,u,e,v)}function l(r,n){var t=(r&65535)+(n&65535);var a=(r>>16)+(n>>16)+(t>>16);return a<<16|t&65535}function s(r,n){return r<<n|r>>>32-n}function A(r){var n=Array();var a=(1<<t)-1;for(var u=0;u<r.length*t;u+=t){n[u>>5]|=(r.charCodeAt(u/t)&a)<<u%32}return n}function g(n){var t=r?"0123456789ABCDEF":"0123456789abcdef";var a="";for(var u=0;u<n.length*4;u++){a+=t.charAt(n[u>>2]>>u%4*8+4&15)+t.charAt(n[u>>2]>>u%4*8&15)}return a}return u}();

var $       = window.jQuery
  , msg     = window.XF.widget.msgbox
  , cookie  = window.QZFL.cookie

// rewrite
QQXF.COMMON.backToLogin = function (time) {
    msg.hide()
    if (time === 13) return logout() // user click logout

    var uin = localStorage.getItem('uin')
      , passhex = localStorage.getItem('passhex')

    // autologin
    if (uin && passhex) {
        msg.show('自动登录中...', 0, 5000, true)
        checkVC(uin, function (code, vcode, vc) {
            if (code == '0') { // no captcha
                login(uin, passhex, vcode, vc)
            } else { // captcha
                g_pop_login.showVC(function (vcode) {
                    login(uin, passhex, vcode, vc)
                }, uin)
            }
        })
    } else {
        // self login
        g_pop_login.showLogin(function (uin, pass, vcode, vc, save) {
            var passhex = hexchar2bin( md5(pass) )

            localStorage.setItem('uin', uin)
            if (save) { // save pass
                localStorage.setItem('passhex', passhex)
            }

            login(uin, passhex, vcode, vc)
        }, uin)
    }
}

// vc
var vcallback
function checkVC(uin, callback) {
    vcallback = callback
    $.getScript('http://check.ptlogin2.qq.com/check?uin=' +uin)
}
window.checkVC = checkVC // export
// check vc callback
//ptui_checkVC('0','!JTF','\x00\x00\x00\x00\x20\x56\x38\xb0');
window.ptui_checkVC = function (code, vcode, vc) {
    vcallback.apply(null, arguments)
}

// login main
function login (uin, passhex, vcode, vc) {
    $.getScript(['http://ptlogin2.qq.com/login'
      , '?u=' +uin
      , '&p=' +md5( md5(passhex+vc) +vcode.toUpperCase() )
      , '&verifycode=' +vcode

        // useles but necessary for request
      , '&u1=http%3A%2F%2Fqq.com&aid=1&h=1&from_ui=1&g=1'
    ].join(''))
}

// login callback
// code? ? url ? info usr
//ptuiCB('4','3','','0','登录失败,请重试。*', '100000');
window.ptuiCB = function (code, x, url, x2, tip, usr) {
    if (code == '0') {
        msg.show(tip, 1, 5000)
    } else {
        msg.show(tip, 2, 5000)
        localStorage.removeItem('passhex')
    }

    setTimeout(function () {
        window.location.reload()
    }, 800)
}


// logout main
function logout() {
    cookie.del('uin', 'qq.com')
    cookie.del('skey', 'qq.com')
    localStorage.removeItem('uin')
    localStorage.removeItem('passhex')
    msg.show('已退出', 3, 2000)
    window.location.reload()
}
/// =====
})


/**
 * magnet
 */
injectScript(function () {
// ======
var $   = window.jQuery
  , msg = window.XF.widget.msgbox


// orignal code by binux
// https://gist.github.com/binux/4585941
$('#input_tips').text('请输入HTTP/eD2k/magnet链接').each(function () {
    var $tips = $(this)
    // rewrite
    var _info = EventHandler.set_hide_info

      , input = $('#dl_url_id').get(0)

    var isMagnet = /^magnet:\?/i
    EventHandler.set_hide_info = function () {
        var url = input.value//.replace(/,/g, '_')

        if ( isMagnet.test(url) ) {
            addMagnetTask(url)

            // clean up
            input.value = ''
            $tips.blur()
        } else {
            _info.apply(EventHandler, arguments)
        }

    }
})



// mock bt upload function
// extract show bt files select function
var showFileList = (function () {
    var AjaxUpload = window.AjaxUpload
    var showFileList
    window.AjaxUpload = function ($e, options) {
        showFileList = options.onComplete
    }
    window.initTorrent() // call
    window.AjaxUpload = AjaxUpload // revert

    return showFileList
})()


function addMagnetTask(url) {
    window.g_pop_task.hide()
    msg.show('解析magnet链接中...', 0, 20000, true)

    $.ajax({
      // callback name is hard coded
        url     : 'http://pew.rhyzx.im/magnet?callback=?'
      , data    : { u : url }
      , cache   : true
      , dataType: 'jsonp'
    }).done(function (res) {
        showFileList(null, JSON.stringify({
            ret : 0
          , name: res.name
          , hash: res.infoHash.toLowerCase()
          , files : res.files.map(function (item, i) {
                return {
                    file_index  : item.index
                  , file_name   : item.name
                  , file_size   : item.length_f
                  , file_size_ori : item.length
                }
            })
        }))
    }).fail(function ($xhr) {
        msg.show('解析magnet链接失败:' + $xhr.responseText, 2, 2000)
    })
}

/// =====
})


/**
 * fold bt
 * TODO update bt info when task update
 */
injectScript(function () {
// ======

var $       = window.jQuery
  , format  = new CTaskParaFormat

// fix bt fold
var _showList = CTaskOp.prototype.showListFromCache
CTaskOp.prototype.showListFromCache = function (firstGet) {
    _showList.call(this, true) // always firstGet
}

// rewrite
// add url to new task
var _getInfo = CTaskOp.prototype.getTaskTemplateInfo
CTaskOp.prototype.getTaskTemplateInfo = function (task) {
    var info = _getInfo.apply(this, arguments)
    if (!task.task_type && !task.file_url) {
        info.task_org_url = task.bt_id
    }
    return info
}

// rewrite
var _show = QQVIP.template.show
QQVIP.template.show = function (options) {
    var taskList = options.JSON, newList = []

    var bt // last bt task
      , key = 0
    for (var i=0, task; task=taskList[i++];) {
        // show full name
        task.task_short_file_name = task.task_file_name

        // bt task url pattern: hash_index
        // eg. task_org_url: "DB7B0F2264494DAFCD20CACB410399CC65230819_0"
        var hash = (task.task_org_url || '').split('_')
        if (hash.length > 1) { // is bt
            if (!bt || bt.hash !== hash[0]) { // new bt
                bt = {
                    hash            : hash[0]
                  , count           : 0
                  , cloudplayer_status : 'player_hide'
                  //, cloudplayer_url: '###'
                  , eyun_status     : 'eyun_hide'
                  //, hash: '181674167CD5C63034A212F2BD120BE8A7D8E5E9'
                  //, not_empty: ''
                  , org_file_size   : 0
                  //, player_status: 'player_ok'
                  //, player_url: 'id=181674167CD5C63034A212F2BD120BE8A7D8E5E9&uin=542521520'
                  //, task_dl_local_class: ''
                  , task_dl_speed   : 'BT任务'
                  , task_done_percent : '0%'
                  //, task_done_percent_class: 'green'
                  , task_file_name  : '[BT]' +task.task_file_name
                  , task_file_size  : '0'
                  , task_file_type  : 'icon_bt'
                  , task_id         : 'bt_' +key++ // key for select
                  , task_left_days  : task.task_left_days
                  //, task_org_url: '8DAB9FC87D97F44B3C613C4F75D09094E3291DB6_6'
                  //, task_org_url_class: 'elem_hide'
                  , task_row_status : 'bt_row'
                  //, task_share_class: ''
                  , task_short_file_name : '[BT]' +task.task_file_name
                  , task_status     : 'icon_bt_unfold'
                }
                newList.push(bt)
            }

            // add class for toggle display
            task.task_row_status = (task.task_row_status || '') +' bt_task_row ' + bt.task_id

            // update bt summary info
            bt.count++
            bt.org_file_size += task.org_file_size
            bt.task_file_size = format.formatFilesize(bt.org_file_size)
            var percent = parseInt(bt.task_done_percent)/bt.count * (bt.count- 1)
                        + parseInt(task.task_done_percent)/bt.count

            bt.task_done_percent = percent.toFixed(2) +'%'


            bt.task_done_percent_class = bt.task_done_percent === '100%' ? 'green' : ''

        }


        newList.push(task)
    }

    options.JSON = newList
    _show.call(QQVIP.template, options)
}

// rewrite
// toggle bt tasks display
var isBt    = /^bt_/, $curr = $()
EventHandler.task_op_display = function (obj, taskid) {
    var $e = $(obj)

    // bt row, toggle it's task list
    if (taskid.match(isBt)) {
        var $items = $('#task_info_body > .' +taskid)

        var show = !!$e.data('show')
        $e.data('show', !show)
        show ? $items.hide() : $items.show()

    // normal task, show info
    // default hanlder will clear DOM class
    // so show info by self code
    } else {
        EventHandler.get_http_url(taskid) // show normal download link
        $curr.removeClass('bg_curr')
        $curr = $e.parent().parent()

        // only show visible task's info
        if ($curr.is(':visible')) $curr.addClass('bg_curr')
    }
}

// select all in bt
$(document).delegate('.bt_row .seltbox input', 'click', function () {
    var $items = $('#task_info_body > .' +this.id.slice(9)) // task_sel_bt_0
    $items.find('.seltbox input').attr('checked', this.checked)
    EventHandler.set_top_button() // enable/disable export btn
})


/// =====
})


/**
 * TODO add multi task
 */
injectScript(function () {
// ======
var $ = window.jQuery
/// =====
})



/**
 * others
 */
injectScript(function () {
// ======
var $ = window.jQuery

// break normal download restrict
EventHandler.httpDownload = function () {
// big size download will be blocked by default
// just clear this code
}

/// =====
})





/**
 * download dialogBox
 */
injectScript(function () {
// ======

var $       = window.jQuery
  , xfDialog= window.xfDialog

var $export = $((function () {/*
<div id="ex_pop_export_dl" class="com_win">
    <div class="com_win_head_wrap"> <h1><em>导出下载</em> <span class="close_win" title="关闭"><a href="javascript:;"></a></span></h1></div>
    <div class="com_win_cont_wrap">
        <div class="com_win_cont">
        <div class="pop">
            <p class="ex_file">
                <a class="icon_file ex_file_aria" href="javascript:;" target="_blank"
                    title="$ aria2c -i aria2.down.txt"
                    download="aria2.down.txt"
                >存为aria2文件</a>
                <a class="icon_file ex_file_idm" href="javascript:;" target="_blank"
                    title="IDM"
                    download="idm.ef2"
                >存为IDM文件</a>
                <a class="icon_file ex_file_orbit" href="javascript:;" target="_blank"
                    title="orbit"
                    download="orbit.olt"
                >存为Orbit文件</a>
            </p>
            <div class="ex_code">
                <textarea readonly wrap="off"></textarea>
            </div>
        </div>
        </div>
    </div>
    <div class="com_win_foot_wrap"><div class="com_win_foot"></div></div>
</div>
*/}).toString().slice(16, -4)).appendTo('#popup_area')


var $file = $export.find('.ex_file_aria')
  , $code = $export.find('.ex_code textarea:first')

  , $idm  = $export.find('.ex_file_idm')
  , $orbit= $export.find('.ex_file_orbit')

// setup dialog function
var pop = window.g_pop_export = new xfDialog('ex_pop_export_dl')


pop.setDownloads = function (dls) {
    var file = '', code = '', idm = '', orbit = ''

    for (var i=0, dl; dl=dls[i++];) {
        file += [
            dl.url
          , '  header=Cookie: FTN5K=' +dl.cookie
          , '  out=' +dl.filename
          , '  continue=true'
          , '  max-connection-per-server=10'
          , '  split=10'
          , '\n'
        ].join('\n')

        code += [
            'aria2c -c -s10 -x10 -o '
          , dl.filename
          , ' --header '
          , 'Cookie: FTN5K=' +dl.cookie
          , ' '
          , dl.url
          , '\n'
        ].join('\'')

        idm += [
            '<'
          , dl.url //+dl.filename?
          , 'cookie: FTN5K=' +dl.cookie
          , '>'
          , ''
        ].join('\r\n')

        orbit += dl.url
          +'|' +dl.filename.replace(/\|/g, '_')
          +'||FTN5K=' +dl.cookie
          +'\r\n'
    }

    $file.attr('href', 'data:text/plain;charset=utf-8,' +encodeURIComponent(file))
    $code.val(code)

    $idm.attr('href', 'data:text/plain;charset=utf-8,' +encodeURIComponent(idm))
    $orbit.attr('href', 'data:text/plain;charset=utf-8,' +encodeURIComponent(orbit))
}

/// =====
})


/**
 * rpc config dialogBox
 */
injectScript(function () {
// ======

var $       = window.jQuery
  , xfDialog= window.xfDialog
  , msg     = window.XF.widget.msgbox

var $rpc = $((function () {/*
<div id="ex_rpc_config" class="com_win">
    <div class="com_win_head_wrap"> <h1><em>Aria RPC设置</em> <span class="close_win" title="关闭"><a href="###"></a></span></h1></div>
    <div class="com_win_cont_wrap">
        <div class="com_win_cont">
            <div class="pop">
                <div class="con">
                    <form action="#">
                        <div class="">
                            <p class="p1"><label>地址:</label><input name="url" type="text"></p>
                            <p class="p2"><label>Secret Token:</label><input name="token" type="text"></p>
                        </div>
                        <p class="discr">
                            <a href="javascript:;" class="com_opt_btn ok"><span><em>确定</em></span></a>
                        </p>
                    </form>
                    <p style="margin-top:20px"><code>&gt; aria2c --enable-rpc=true --rpc-allow-origin-all=true --rpc-secret=token</code></p>
                </div>
            </div>
        </div>
    </div>
    <div class="com_win_foot_wrap"><div class="com_win_foot"></div></div>
</div>
*/}).toString().slice(16, -4)).appendTo('#popup_area')

var pop = window.g_pop_rpc = new xfDialog('ex_rpc_config')

var elements    = $rpc.find('form:first').get(0).elements
  , url = elements.url
  , token = elements.token


pop.showConfig = function (config) {
    config = config || {}
    url.value = config.url || 'http://localhost:6800/jsonrpc'
    token.value = config.token || ''
    this.show()
}

$rpc.find('.ok:first').click(function () {
    pop.hide()
    localStorage.setItem('rpc-url', url.value)
    localStorage.setItem('rpc-token', token.value)
})

/// =====
})


/**
 * login dialogBox
 */
injectScript(function () {
// ======

var $       = window.jQuery
  , xfDialog= window.xfDialog
  , msg     = window.XF.widget.msgbox

var $login = $((function () {/*
<div id="login_win" class="com_win">
    <div class="com_win_head_wrap"> <h1><em>登录</em> <span class="close_win" title="关闭"><a href="###"></a></span></h1></div>
    <div class="com_win_cont_wrap">
        <div class="com_win_cont">
            <div class="pop">
                <div class="con">
                <form action="#">
                    <div class="ex_login_area">
                        <p class="p1"><label>QQ帐号:</label><input name="uin" type="text"></p>
                        <p class="p2"><label>QQ密码:</label><input name="pass" type="password"></p>
                    </div>
                    <div class="ex_vc_area" style="display:none">
                        <p class="p2" style="">
                            <label>验证码:</label>
                            <input class="ex_vcode" name="vcode" type="text" />
                            <img class="ex_vimg" width="130" height="53">
                        </p>
                    </div>
                    <p class="discr">
                        <a href="javascript:;" class="ex_login_btn com_opt_btn"><span><em>登录</em></span></a>
                        <span class="ex_login_area">
                            <input class="ex_check_box" name="save" type="checkbox">
                            <span>自动登录</span>
                        </span>
                    </p>
                </form>
                </div>
            </div>
        </div>
    </div>
    <div class="com_win_foot_wrap"><div class="com_win_foot"></div></div>
</div>
*/}).toString().slice(16, -4)).appendTo('#popup_area')

var pop = window.g_pop_login = new xfDialog('login_win')

var elements    = $login.find('form:first').get(0).elements

var $vcArea     = $login.find('.ex_vc_area')
  , $loginArea  = $login.find('.ex_login_area')

var $vimg       = $login.find('.ex_vimg').click(function () {
      // refresh captcha pic
    this.src = 'http://captcha.qq.com/getimage?uin='
        +this.getAttribute('data-uin')
        +'&' +Date.now()
})


var action, vc
$login.find('.ex_login_btn').click(function () {
    pop.hide()
    msg.show('登录中...', 0, 5000, true)
    action()
})

// only show vc dialog
pop.showVC = function (callback, uin) {
    action = function () {
        callback(elements.vcode.value)
    }
    $loginArea.hide()
    $vcArea.show()
    $vimg.attr('data-uin', uin).click()
    pop.show()
}


// show login dialog
pop.showLogin = function (callback, uin) {
    action = function () {
        callback(elements.uin.value, elements.pass.value, elements.vcode.value, vc, elements.save.checked)
    }
    pop.show()

    // set uin and checkVC
    if (uin) $(elements.uin).val(uin).change()
}


// check vc when qq changed
$(elements.uin).change(function () {
    var uin = this.value
    if (uin.length > 4) {
        msg.show('检测帐号中...', 0, 5000)
        checkVC(uin, function (code, vcode, _vc) {
            msg.hide()
            vc = _vc

            if (code == '0') { // no captcha
                $vcArea.hide()
                elements.vcode.value = vcode
            } else { // need captcha
                $vcArea.show()
                $vimg.attr('data-uin', uin).click() // show pic
            }
        })
    }
})

/// =====
})


/**
 * overwrite CSS
 */
injectStyle((function () {/*
.top,
.search_box,
#share_opt,
#down_box {
    display: none !important;
}
#cont_wrap, #tbl_tpl_id, .box, .filename em {
    width: auto !important;
}

.main {
    width: auto;
    margin-left: 50px;
    margin-right: 50px;
}
.tablebox .tit_h th {
    background-repeat: repeat;
}


#ex_pop_export_dl {
    position: absolute;
    top: 200px;
    left: 50%;
    width: 640px;
    margin-left: -320px;
    text-align: left;
    color: #2d5b7c;
    z-index: 102;
    background: #FFF;
    overflow: hidden;
}
.ex_file {
    margin: 8px;
}
.ex_file a {
    display: inline-block;
    margin-right: 14px;
    outline: none;
}
.ex_code {
    margin: 0 8px;
    border: 1px solid #C7E2F1;
    border-raduis: 4px;
}
.ex_code textarea {
    width: 100%;
    height: 180px;
    font: 12px/1.5 monospace;
    border: none;
}
#login_win input {
    padding: 0 5px;
    width: 220px;
    background: #FFF;
}
#login_win .ex_vcode {
    display: inline-block;
    width: 80px;
}
#login_win .ex_check_box {
    width: 16px;
}
.ex_login_btn {
    float: none;
}
.ex_vimg {
    vertical-align: middle;
}

.bt_row {
    background: #f6fef8;
}
.bt_task_row {
    display: none;
}
.bt_task_row td:first-child ,
.bt_row  td:first-child {
    border-left: 3px solid #9fe5b1;
}
.bt_task_row .seltbox input {
    margin-left: 20px;
}
.icon_bt {
    padding-left: 20px;
    height: 16px;
    line-height: 16px;
    font-style: normal;
    background-repeat: no-repeat;
    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGrSURBVDjLxZO7ihRBFIa/6u0ZW7GHBUV0UQQTZzd3QdhMQxOfwMRXEANBMNQX0MzAzFAwEzHwARbNFDdwEd31Mj3X7a6uOr9BtzNjYjKBJ6nicP7v3KqcJFaxhBVtZUAK8OHlld2st7Xl3DJPVONP+zEUV4HqL5UDYHr5xvuQAjgl/Qs7TzvOOVAjxjlC+ePSwe6DfbVegLVuT4r14eTr6zvA8xSAoBLzx6pvj4l+DZIezuVkG9fY2H7YRQIMZIBwycmzH1/s3F8AapfIPNF3kQk7+kw9PWBy+IZOdg5Ug3mkAATy/t0usovzGeCUWTjCz0B+Sj0ekfdvkZ3abBv+U4GaCtJ1iEm6ANQJ6fEzrG/engcKw/wXQvEKxSEKQxRGKE7Izt+DSiwBJMUSm71rguMYhQKrBygOIRStf4TiFFRBvbRGKiQLWP29yRSHKBTtfdBmHs0BUpgvtgF4yRFR+NUKi0XZcYjCeCG2smkzLAHkbRBmP0/Uk26O5YnUActBp1GsAI+S5nRJJJal5K1aAMrq0d6Tm9uI6zjyf75dAe6tx/SsWeD//o2/Ab6IH3/h25pOAAAAAElFTkSuQmCC)
}

.bg_curr {
    pointer: normal !important;
    background: #d2eeff !important;
}
.bg_curr .p2 {
    display: block !important;
}
#ex_rpc_config {
    width: 460px;
    margin-left: -230px;
}
*/}).toString().slice(16, -4)) // extract css in function





// execute code in the content page scope
function injectScript(source) {
    var script = document.createElement('script')
    script.setAttribute('type', 'text/javascript')
    script.textContent = ';(' + source.toString() + ')()'

    document.body.appendChild(script)
    document.body.removeChild(script)
}

// insert css
function injectStyle(css) {
    var script = document.createElement('style')
    script.setAttribute('type', 'text/css')
    script.textContent = css
    document.head.appendChild(script)
}