Greasy Fork is available in English.

1. VIP视频解析和去广告;2.音乐下载;3.获取B站封面;3.购物优惠券;4.百度文库下载;5.图虫、千图网图片下载;6.网盘助手;7.微博[图片|视频]下载;8.知乎助手;9.起点搜书

(1)在视频播放页悬浮VIP按钮,可在线播放vip视频,支持优酷,腾讯,爱奇艺等常用视频网站;(2)音乐搜索解决方案,网易云音乐,QQ音乐,酷狗音乐,酷我音乐,虾米音乐,百度音乐,蜻蜓FM,荔枝FM,喜马拉雅;(3)淘宝,京东优惠券领取功能;(4)百度文库下载功能;(5)图虫付费图片免费下载(tuchong.com)(tuchong.com)千图网图片无水印下载;(6)网盘助手插件主要功能有:[1]百度网盘、腾讯微云、蓝奏云万能钥匙[2]百度网盘生成并展示下载链接[3]百度网盘分享时自定义提取码;(7)下载微博的图片和视频:(支持LivePhoto、短视频、动/静图(9+),可以打包下载);(8)知乎助手功能介绍:[1].知乎站外链接直接跳转至目标网址,[2].自动展开问题全部信息,同时展示所有回答,[3].去除知乎网页中的广告,[4].知乎网页中短视频下载,[5].解除知乎复制限制-划词复制(鼠标左键划词自动添加到剪切板)【注:支持Tampermonke4.0以上版本】;(9)拒绝高(捆)速(绑)下载;

// ==UserScript==
// @name         1. VIP视频解析和去广告;2.音乐下载;3.获取B站封面;3.购物优惠券;4.百度文库下载;5.图虫、千图网图片下载;6.网盘助手;7.微博[图片|视频]下载;8.知乎助手;9.起点搜书
// @namespace    http://shop.haokanba.top/
// @author       阿狸
// @version      2.0.7
// @description
// (1)在视频播放页悬浮VIP按钮,可在线播放vip视频,支持优酷,腾讯,爱奇艺等常用视频网站;
// (2)音乐搜索解决方案,网易云音乐,QQ音乐,酷狗音乐,酷我音乐,虾米音乐,百度音乐,蜻蜓FM,荔枝FM,喜马拉雅;
// (3)淘宝,京东优惠券领取功能;
// (4)百度文库下载功能;
// (5)图虫付费图片免费下载(tuchong.com)(tuchong.com)千图网图片无水印下载;
// (6)网盘助手插件主要功能有:[1]百度网盘、腾讯微云、蓝奏云万能钥匙[2]百度网盘生成并展示下载链接[3]百度网盘分享时自定义提取码;
// (7)下载微博的图片和视频:(支持LivePhoto、短视频、动/静图(9+),可以打包下载);
// (8)知乎助手功能介绍:[1].知乎站外链接直接跳转至目标网址,[2].自动展开问题全部信息,同时展示所有回答,[3].去除知乎网页中的广告,[4].知乎网页中短视频下载,[5].解除知乎复制限制-划词复制(鼠标左键划词自动添加到剪切板);
// (9)拒绝高(捆)速(绑)下载;
// @icon         http://pan.newday.me/pan/favicon.ico

// @include      *://m.youku.com/v*
// @include      *://m.youku.com/a*
// @include      *://v.youku.com/v_*
// @include      *://*.iqiyi.com/v_*
// @include      *://*.iqiyi.com/w_*
// @include      *://*.iqiyi.com/a_*
// @include      *://*.iqiyi.com/adv*
// @include      *://*.le.com/ptv/vplay/*
// @include      *v.qq.com/x/cover/*
// @include      *v.qq.com/x/page/*
// @include      *v.qq.com/play*
// @include      *v.qq.com/cover*
// @include      *://*.tudou.com/listplay/*
// @include      *://*.tudou.com/albumplay/*
// @include      *://*.tudou.com/programs/view/*
// @include      *://*.tudou.com/v*
// @include      *://*.qidian.com/
// @include      *://*.mgtv.com/b/*
// @include      *://film.sohu.com/album/*
// @include      *://tv.sohu.com/v/*
// @include      *://*.acfun.cn/v/*
// @include      *://*.bilibili.com/video/*
// @include      *://*.bilibili.com/anime/*
// @include      *://*.bilibili.com/bangumi/play/*
// @include      *://*.pptv.com/show/*
// @include      *://*.wasu.cn/Play/show*
// @include      *://v.yinyuetai.com/video/*
// @include      *://v.yinyuetai.com/playlist/*
// @include      *://*.wasu.cn/Play/show/*
// @include      *://music.taihe.com/song*
// @include      *://item.taobao.com/*
// @include      *://detail.liangxinyao.com/*
// @include      *://detail.tmall.com/*
// @include      *://detail.tmall.hk/*
// @include      *://item.jd.com/*
// @include      *://music.163.com/song*
// @include      *://music.163.com/m/song*
// @include      *://y.qq.com/*
// @include      *://*.kugou.com/*
// @include      *://*.kuwo.cn/*
// @include      *://*.xiami.com/*
// @include      *://music.taihe.com/*
// @include      *://*.1ting.com/player*
// @include      *://www.qingting.fm/*
// @include      *://www.lizhi.fm/*
// @include      *://music.migu.cn/*
// @include      *://www.ximalaya.com/*

// @include      *://pan.baidu.com/disk/home*
// @include      *://yun.baidu.com/disk/home*
// @include      *://pan.baidu.com/s/*
// @include      *://yun.baidu.com/s/*
// @include      *://pan.baidu.com/share/link*
// @include      *://yun.baidu.com/share/link*

// @include      *://www.zhihu.com/*
// @include      https://video.zhihu.com/video/*

// @match        *://share.weiyun.com/*
// @match        *://*.newday.me/*
// @match        *://pan.baidu.com/*
// @match        *://yun.baidu.com/*
// @match        *://*.lanzous.com/*

// @match        https://link.zhihu.com/*
// @match        *://www.zhihu.com/*
// @match        https://v.vzuu.com/video/*
// @match        https://video.zhihu.com/video/*

// @match        *://wenku.baidu.com/view/*
// @match  	  	 *://www.bdwenku.com/wk/*

// @match        https://www.58pic.com/*
// @match        *://*.tuchong.com/*
// @match        *://tuchong.com/*

// @match        https://weibo.com/*
// @match        https://www.weibo.com/*
// @match        https://d.weibo.com/*
// @match        https://s.weibo.com/*


// @match        *://*.onlinedown.net/*
// @match        *://*.cr173.com/*
// @match        *://*.xiazaiba.com/*
// @match        *://*.mydown.com/*
// @match        *://*.pc6.com/*
// @match        *://*.zol.com.cn/*
// @match        *://*.pconline.com.cn/*
// @match        *://*.jb51.net/*
// @match        *://*.cncrk.com/*
// @match        *://pc.qq.com/*
// @match        *://*.crsky.com/*
// @match        *://*.duote.com/*
// @match        *://*.downza.cn/*
// @match        *://*.yesky.com/*
// @match        *://*.ddooo.com/*
// @match        *://*.pchome.net/*
// @match        *://*.xpgod.com/*
// @match        *://*.52z.com/*
// @match        *://*.opdown.com/*

// @charset		 UTF-8

// @require      https://code.jquery.com/jquery-1.11.0.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.0/jszip.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js
// @require      https://cdn.staticfile.org/mustache.js/3.1.0/mustache.min.js

// @require      https://cdn.staticfile.org/jquery/1.12.4/jquery.min.js
// @require      https://greasyfork.org/scripts/373336-layer-wandhi/code/layer_wandhi.js?version=637587
// @require      https://cdn.bootcss.com/sweetalert/2.1.2/sweetalert.min.js
// @require      https://cdn.staticfile.org/snap.svg/0.5.1/snap.svg-min.js
// @require      https://cdn.staticfile.org/vue/2.6.6/vue.min.js

// @require      http://libs.baidu.com/jquery/2.0.0/jquery.min.js

// @connect      api.newday.me
// @connect      ypsuperkey.meek.com.cn

// @connect      sinaimg.cn
// @connect      miaopai.com
// @connect      youku.com
// @connect      weibo.com

// @connect      zhihu.com
// @connect      vzuu.com

// @run-at       document-start

// @license      GPL License

// @grant        GM_setClipboard
// @grant        GM_xmlhttpRequest
// @grant        GM_info
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_notification
// @grant        GM_listValues
// @grant        GM_openInTab
// @grant        GM_deleteValue
// @grant        GM_registerMenuCommand
// @grant        GM_getResourceURL
// @grant        GM_unregisterMenuCommand
// @grant        GM_download
// @grant        unsafeWindow

// @exclude      *://*.haokanba.top/*

// @description (1)在视频播放页悬浮VIP按钮,可在线播放vip视频,支持优酷,腾讯,爱奇艺等常用视频网站;(2)音乐搜索解决方案,网易云音乐,QQ音乐,酷狗音乐,酷我音乐,虾米音乐,百度音乐,蜻蜓FM,荔枝FM,喜马拉雅;(3)淘宝,京东优惠券领取功能;(4)百度文库下载功能;(5)图虫付费图片免费下载(tuchong.com)(tuchong.com)千图网图片无水印下载;(6)网盘助手插件主要功能有:[1]百度网盘、腾讯微云、蓝奏云万能钥匙[2]百度网盘生成并展示下载链接[3]百度网盘分享时自定义提取码;(7)下载微博的图片和视频:(支持LivePhoto、短视频、动/静图(9+),可以打包下载);(8)知乎助手功能介绍:[1].知乎站外链接直接跳转至目标网址,[2].自动展开问题全部信息,同时展示所有回答,[3].去除知乎网页中的广告,[4].知乎网页中短视频下载,[5].解除知乎复制限制-划词复制(鼠标左键划词自动添加到剪切板)【注:支持Tampermonke4.0以上版本】;(9)拒绝高(捆)速(绑)下载;
// ==/UserScript==
var reYk = /youku/i;
var reAqy = /iqiyi/i;
var reLS = /le.com/i;
var reTX = /v.qq/i;
var reTD = /tudou/i;
var reMG = /mgtv/i;
var reSH = /sohu/i;
var rePP = /pptv/i;
var reTaoBao = /taobao.com/i;
var reAliShop = /liangxinyao.com/i;
var reTmall = /tmall/i;
var reJd = /item.jd/i;
var reWenku = /wenku.baidu/i;
var reWY = /163(.*)song/i;
var reQQ = /y.QQ(.*)song/i;
var reKG = /kugou(.*)song/i;
var reKW = /kuwo(.*)yinyue/i;
var reXM = /xiami/i;
var reBD = /taihe.com/i;
var reQT = /qingting/i;
var reQD = /qidian/i;
var reLZ = /lizhi/i;
var reMiGu = /migu/i;
var reXMLY = /ximalaya/i;
var reBili = /bilibili.com\/video\/av/i;
var reSite = /video.haokanba.top/i;

(function () {
    'use strict';
    var currentUrl = window.location.href;
    var currentHost = window.location.host;

    // 电影搜索,音乐下载,购物券,电影解析
    $(document).ready(function () {
        superTool(currentUrl, currentHost);
    });

    // 视频广告自动跳过 目前已支持爱奇艺、优酷、腾讯视频
    skipAvertise(currentUrl, currentHost);

    // 千图网无水印下载
    downloadQianTu(currentUrl, currentHost);

    // 图虫网无水印下载
    downloadTuChong(currentUrl, currentHost);

    // 微博工具
    weiboTool(currentUrl, currentHost);

    // 清除捆绑下载工具
    clearBindTool(currentUrl, currentHost);

    // 知乎工具
    zhihuTool(currentUrl, currentHost);

    // 网盘工具
    netDiskTool(currentUrl, currentHost);
})();

// 视频广告自动跳过 目前已支持爱奇艺、优酷、腾讯视频
function skipAvertise(currentUrl, currentHost) {
    let methodYk = function () {
        window._setTimeout = window.setTimeout
        window.setTimeout = function (handler, timeout, ...arg) {
            window._setTimeout(handler, timeout / 30, ...arg)
        }
    }
    let methodIqiyi = function () {
        window.rate = 0
        window.Date.now = () => {
            return new window.Date().getTime() + (window.rate += 10000)
        }
        setInterval(() => {
            window.rate = 0
        }, 600000)
    }
    let youku = function () {
        window.onload = function () {
            if (!document.querySelectorAll('video')[1]) {
                setInterval(() => {
                    document.querySelectorAll('video')[1].playbackRate = 16
                }, 100)
            } else {
                methodYk()
            }
        }
    }
    let qq = function () {
        setInterval(() => {
            if (document.querySelectorAll('video')[0].status == 'IDLE') {
                setInterval(() => {
                    document.querySelectorAll('video')[2].playbackRate = 16
                    document.querySelectorAll('video')[3].playbackRate = 16
                }, 100)
            }
        }, 100)
    }
    switch (currentHost) {
        case 'v.youku.com':
            youku();
            break;
        case 'v.qq.com' :
            qq();
            break;
        case 'www.iqiyi.com' :
            methodIqiyi();
            break;
        default :
            break
    }
}

// 千图网无水印下载
function downloadQianTu(currentUrl, currentHost) {
    if (currentHost == 'www.58pic.com') {
        var src = document.querySelector(".pic-box").firstChild.getAttribute("data-src").replace(/preview/, "pic").split("jpg")[0];
        src = '<a href=' + src + 'jpg class="alert-color" data-mark-header="d_w_l" sta-site="4" stats-point="106" rel="nofollow" target="_blank">【油猴子插件无限制下载原图】</a>';
        document.querySelector(".mainLeft-title").insertAdjacentHTML('beforeend', src);
    }
}

// 图虫网无水印下载
function downloadTuChong(currentUrl, currentHost) {
    if (currentUrl.indexOf('tuchong.com') > 0) {
        var retry = 0;
        var maxRetryTimes = 3;
        var timer;
        timer = setInterval(function () {
            if (retry < maxRetryTimes) {
                var imgsContainer = $('.scene-container-next');
                if (imgsContainer.length > 0) {
                    getOneImages(imgsContainer);
                    getAllImages(imgsContainer);
                    clearInterval(timer);
                }
                retry++;
            } else {
                clearInterval(timer);
            }
        }, 1000)

        // 下载单页按钮
        function createdownloadBtn(imgHref, imgName) {
            $('.icon-download').before('<span id="diy-downloadOneImg" style="border-radius: 4px 8px;color:#fff;background:#4CAF50;padding:10px;cursor:pointer">单页下载</span>');
            $('#diy-downloadOneImg').on('click', function () {
                GM_download(imgHref, imgName)
            })
        }

        // 下载套图按钮
        function createdownloadAllBtn(allImages) {
            $('.icon-download').before('<span id="diy-downloadAllImg" style="border-radius: 4px 8px;margin-left:15px;color:#fff;background:#008CBA;padding:10px;cursor:pointer">图集下载</span>');
            $('#diy-downloadAllImg').on('click', function () {
                for (var i = 0; i < allImages.length; i++) {
                    var imgNames = $('.aside-post-title').text() + (i + 1);
                    GM_download(allImages[i], imgNames)
                }
            })
        }

        // 获取单页地址
        function getOneImages(container) {
            var imgHref = container.find('.scene-item').not('.prev-scene').not('.next-scene').find('img').attr('src');
            var imgName = $('.aside-post-title').text() + imgHref.split('/f/')[1];
            var re = /http/;
            if (!re.test(imgHref)) {
                imgHref = 'http:' + imgHref
            }
            createdownloadBtn(imgHref, imgName);
        }

        // 获取套图地址
        function getAllImages(container) {
            var imgHrefs = container.find('.scene-item');
            var allImages = [];
            for (var i = 0; i < imgHrefs.length; i++) {
                var curHref = $(imgHrefs[i]).find('img').attr('src');
                var re = /http/;
                if (!re.test(curHref)) {
                    curHref = 'http:' + curHref
                }
                allImages.push(curHref)
            }
            createdownloadAllBtn(allImages);
        }
    }
}

// 知乎工具
function zhihuTool(currentUrl, currentHost) {
    switch (currentHost) {
        case "link.zhihu.com": //知乎直接跳转到目标网页
            var regRet = location.search.match(/target=(.+?)(&|$)/);
            if (regRet && regRet.length == 3) {
                location.href = decodeURIComponent(regRet[1]);
            }
            break;
        case "www.zhihu.com":
            if (currentUrl.indexOf("https://www.zhihu.com/question/") != -1) {
                autoExpandQuestionInfo();
            }

            //自动展开问题全部信息,同时展示所有回答
        function autoExpandQuestionInfo() {
            $('.Button.QuestionRichText-more.Button--plain').click();
            var moreAnswers = $('.QuestionMainAction');
            if (moreAnswers.length > 0) {
                moreAnswers[0].click();
            }
        }

            //去除首页广告
        function clearAdvert() {
            $(".Pc-feedAd-container").each(function () {
                if ($(this).find(".Pc-feedAd").length != 0) {
                    $(this).remove();
                }
            });
        }

            setInterval(function () {
                clearAdvert();
            }, 500);
            //划词复制
            $('body').mouseup(function () {
                GM_setClipboard(window.getSelection().toString());
            });
            break;
    }
}

// 微博工具
function weiboTool(currentUrl, currentHost) {

    if (currentHost.indexOf("weibo.com") != -1) {

        class Config {

            /********************* ↓ 用户可配置区域 ↓ *********************/

            /**
             * 媒体类型
             * 【不推荐】直接在此修改数据,应前往【储存】中修改。
             *
             * 此方法的返回值,影响资源名称中的 @mdeia_type 参数值
             */
            static get mediaType() {

                return Config.getValue("mediaType", () => {
                    return {
                        picture: "P",
                        livePhoto: "L",
                        video: "V"
                    };
                });
            }

            /**
             * 得到资源名称
             * 【不推荐】直接在此修改数据,应前往【储存】中修改。
             *
             * 此方法的返回值,影响资源名称
             *
             * 默认的:${wb_user_name}-${wb_id}-${no}
             * 会生成:小米商城-4375413591293810-01
             *
             * 若改为:微博-${media_type}-${wb_user_name}-${wb_id}-${no}
             * 会生成:微博-P-小米商城-4375413591293810-01
             *
             * @param  {字符串} wb_user_name 微博用户名(如:小米商城)
             * @param  {字符串} wb_user_id   微博用户ID(如:5578564422)
             * @param  {字符串} wb_id        微博ID(如:4375413591293810)
             * @param  {字符串} wb_url       微博地址(如:1871821935_Ilt7yCnvt)https://weibo.com/
             * @param  {字符串} resource_id  资源原始名称(如:0065x5rwly1g3c6exw0a2j30u012utyg)
             * @param  {字符串} no           序号(如:01)
             * @param  {字符串} mdeia_type   媒体类型(如:P)
             *
             * @return {字符串}              由以上字符串组合而成的名称
             */
            static getResourceName(wb_user_name, wb_user_id, wb_id, wb_url,
                                   resource_id, no, mdeia_type) {

                const template = Config.getValue("resourceName",
                    () => "{{wb_user_name}}-{{wb_id}}-{{no}}"
                );

                return Mustache.render(template, {
                    wb_user_name: wb_user_name,
                    wb_user_id: wb_user_id,
                    wb_id: wb_id,
                    wb_url: wb_url,
                    resource_id: resource_id,
                    no: no,
                    mdeia_type: mdeia_type
                });
            }

            /**
             * 得到打包名称
             * 【不推荐】直接在此修改数据,应前往【储存】中修改。
             *
             * 此方法的返回值,影响打包名称
             *
             * 默认的:${wb_user_name}-${wb_id}
             * 会生成:小米商城-4375413591293810
             *
             * 若改为:压缩包-${wb_user_name}-${wb_id}
             * 会生成:压缩包-小米商城-4375413591293810
             *
             *
             * @param  {字符串} wb_user_name 微博用户名(如:小米商城)
             * @param  {字符串} wb_user_id   微博用户ID(如:5578564422)
             * @param  {字符串} wb_id        微博ID(如:4375413591293810)
             * @param  {字符串} wb_url       微博地址(如:1871821935_Ilt7yCnvt)
             *
             * @return {字符串}              由以上字符串组合而成的名称
             */
            static getZipName(wb_user_name, wb_user_id, wb_id, wb_url) {

                const template = Config.getValue("zipName",
                    () => "{{wb_user_name}}-{{wb_id}}"
                );

                return Mustache.render(template, {
                    wb_user_name: wb_user_name,
                    wb_user_id: wb_user_id,
                    wb_id: wb_id,
                    wb_url: wb_url
                });
            }

            /**
             * 最大等待请求时间(超时时间),单位:毫秒
             *【不推荐】直接在此修改数据,应前往【储存】中修改。
             *
             * 若经常请求超时,可适当增大此值
             *
             * @type {Number}
             */
            static get maxRequestTime() {

                return Config.getValue("maxRequestTime", () => 8000);
            }

            /**
             * 每隔 space 毫秒检查一次,是否有新的微博被加载出来
             *【不推荐】直接在此修改数据,应前往【储存】中修改。
             *
             * 此值越小,检查越快;过小会造成浏览器卡顿
             * @type {Number}
             */
            static get space() {

                return Config.getValue("space", () => 5000);
            }

            /********************* ↑ 用户可配置区域 ↑ *********************/

            /**
             * 是否启用调试模式
             * 【不推荐】直接在此修改数据,应前往【储存】中修改。
             *
             * 启用后,浏览器控制台会显示此脚本运行时的调试数据
             * @type {Boolean}[true/false]
             */
            static get isDebug() {

                return JSON.parse(Config.getValue("debug", () => false));
            }

            /**
             * 已添加增强扩展的item,会追加此类
             * 【不推荐】直接在此修改数据,应前往【储存】中修改。
             *
             * @type 字符串
             */
            static get handledWeiBoCardClass() {

                return Config.getValue("handledWeiBoCardClass", () => "weibo_383402_extend");
            }

            /**
             * 得到值
             * @param  {字符串} name 键
             * @param  {方法} fun    缺省产生值的方法
             * @return {值}         值
             */
            static getValue(name, fun) {

                let value = Config.properties[name];

                // 本地map中不存在
                if (!value) {

                    value = GM_getValue(name, null);

                    // 储存中也不存在
                    if (!value) {

                        value = fun();
                        GM_setValue(name, value);
                    }

                    // 记录到本地map中
                    Config.properties[name] = value;
                }

                return value;
            }
        }

        Config.properties = new Map();

        /**
         * 接口
         */
        class Interface {

            /**
             * 构造函数
             * @param  {字符串} name    接口名
             * @param  {字符串数组} methods 该接口所包含的所有方法
             */
            constructor(name, methods) {

                //判断接口的参数个数(第一个为接口对象,第二个为参数数组)
                if (arguments.length != 2) {
                    throw new Error('创建的接口对象参数必须为两个,第二个为方法数组!');
                }

                // 判断第二个参数是否为数组
                if (!Array.isArray(methods)) {
                    throw new Error('参数2必须为字符串数组!');
                }

                //接口对象引用名
                this.name = name;

                //自己的属性
                this.methods = []; //定义一个内置的空数组对象 等待接受methods里的元素(方法名称)

                //判断数组是否中的元素是否为string的字符串
                for (var i = 0; i < methods.length; i++) {

                    //判断方法数组里面是否为string(字符串)的属性
                    if (typeof methods[i] != 'string') {
                        throw new Error('方法名必须是string类型的!');
                    }

                    //把他放在接口对象中的methods中(把接口方法名放在Interface对象的数组中)
                    this.methods.push(methods[i]);
                }
            }

            /**
             * 实现
             * @param  {对象} obj 待实现接口的对象
             * @param  {接口} I 接口对象
             * @param  {对象} proxy 接口的实现
             * @return {对象}           扩展后的当前对象
             */
            static impl(obj, I, proxy) {

                if (I.constructor != Interface) {
                    throw new Error("参数2不是一个接口!");
                }

                // 校验实现是否实现了接口的每一个方法
                for (var i = 0; i < I.methods.length; i++) {

                    // 方法名
                    var methodName = I.methods[i];

                    //判断obj中是否实现了接口的方法和methodName是方法(而不是属性)
                    if (!proxy[methodName] || typeof proxy[methodName] != 'function') {
                        throw new Error('有接口的方法没实现');
                    }

                    // 将代理中的方法渡给obj
                    obj[methodName] = proxy[methodName];
                }
            }
        }

        class Link {

            /**
             * 构造函数
             *
             * @param  {字符串} name 名称
             * @param  {字符串} src  地址
             */
            constructor(name, src) {
                this.name = name;
                this.src = src;
            }
        }

        /**
         * 微博解析器接口
         */
        const WeiBoResolver = new Interface("SearchWeiBoResolver",
            [
                "getOperationButton",// 得到操作按钮[↓]
                "getOperationList",// 根据操作按钮,得到操作列表
                "get9PhotoImgs",// 返回九宫格图片的img$控件数组(自带后缀)
                "get9PhotoOver",// 得到超过部分的图片的id数组(无后缀)
                "getLivePhotoContainer",
                "getWeiBoCard",// 这条微博(若为转发微博,则取根微博)
                "getWeiBoInfo",// 这条微博(发布者)信息
                "getWeiBoId",// 此条微博的ID
                "getWeiBoUserId",
                "getWeiBoUserName",
                "getWeiBoUrl",// 此条微博的地址
                "getProgressContainer",
                "getVideoBox",
                "geiVideoSrc"
            ]);

        /**
         * 搜索微博 - 解析器
         */
        const SearchWeiBoResolver = {};

        Interface.impl(SearchWeiBoResolver, WeiBoResolver, {
            getOperationButton: () => $(`div .menu a:not(.${Config.handledWeiBoCardClass})`),
            getOperationList: $operationButton => $operationButton.parents(".menu").find("ul"),
            get9PhotoImgs: $ul => $ul.parents(".card-wrap").find(".media.media-piclist img"),
            get9PhotoOver: $ul => new Promise((resolve, reject) => {
                resolve([]);
            }), //搜索微博不会展示9+图片
            getLivePhotoContainer: $ul => $(null),
            getWeiBoCard: $ul => {

                const $content = $ul.parents(".content");
                const $card_content = $content.find(".card-comment");
                let $content_node;
                if ($card_content.length == 0) { // 这不是转发微博
                    $content_node = $content;
                } else {
                    $content_node = $card_content;
                }
                return $content_node;
            },
            getWeiBoInfo: $ul => {
                return SearchWeiBoResolver.getWeiBoCard($ul).find("a.name").first();
            },
            getWeiBoId: $ul => {
                const action_data = $ul.parents(".card-wrap").find(".card-act li:eq(1) a").attr("action-data");
                const rootmid_regex = action_data.match(/rootmid=(\d+)&/);
                let mid;
                if (rootmid_regex) { // 这是转发微博
                    mid = rootmid_regex[1];
                } else {
                    mid = action_data.match(/mid=(\d+)&/)[1];
                }
                return mid;
            },
            getWeiBoUserId: $ul => {
                const $info = SearchWeiBoResolver.getWeiBoInfo($ul);
                const user_id = $info.attr("href").match(/weibo\.com\/[u\/]{0,2}(\d+)/)[1].trim();
                Core.log(`得到的微博ID为:${user_id}`);
                return user_id;
            },
            getWeiBoUserName: $ul => {
                const $info = SearchWeiBoResolver.getWeiBoInfo($ul);
                const name = $info.text().trim();
                Core.log(`得到的名称为:${name}`);
                return name;
            },
            getWeiBoUrl: $ul => {
                const $card = SearchWeiBoResolver.getWeiBoCard($ul);
                const url = $card.find(".from a").attr("href").match(/weibo\.com\/(\d+\/\w+)\?/)[1].trim();
                Core.log(`得到的地址为:${url}`);
                return url.replace("\/", "_");
            },
            getProgressContainer: $sub => $sub.parents(".card-wrap").find("a.name").first().parent(),
            getVideoBox: $ul => $ul.parents(".card-wrap").find(".WB_video_h5").first(),
            geiVideoSrc: $box => {
                let src = $box.attr("action-data").match(/video_src=([\w\/\.%]+)/)[1];
                src = decodeURIComponent(decodeURIComponent(src));
                if (src.indexOf("http") != 0) {
                    src = `https:${src}`;
                }
                return src;
            }
        });

        /**
         * 我的微博(含:我的微博、他人微博、我的收藏、热门微博) - 解析器
         */
        const MyWeiBoResolver = {};

        Interface.impl(MyWeiBoResolver, WeiBoResolver, {
            getOperationButton: () => $(`div .screen_box i.ficon_arrow_down:not(.${Config.handledWeiBoCardClass})`),
            getOperationList: $operationButton => $operationButton.parents(".screen_box").find("ul"),
            get9PhotoImgs: $ul => $ul.parents(".WB_feed_detail").find("li.WB_pic img"),
            get9PhotoOver: ($ul) => {

                return new Promise((resolve, reject) => {

                    const $box = $ul.parents(".WB_feed_detail").find(".WB_media_a");

                    const action_data = $box.attr("action-data");

                    const over9pic = action_data.match(/over9pic=1&/);

                    if (over9pic) { // 存在超9图

                        const ids_regex = action_data.match(/pic_ids=([\w,]+)&/);

                        if (ids_regex) { // 得到图片ids_regex

                            const ids = ids_regex[1].split(",");

                            // 已知所有图片
                            if (ids.length > 9) { // 用户已手动触发加载over

                                resolve(ids.splice(9));

                            } else { // 只知前面9张,用户未手动触发加载over

                                Core.log("未知超过部分图片!");

                                const mid_regex = action_data.match(/mid=([\d,]+)&/);

                                if (mid_regex) { // 找到mid

                                    const mid = mid_regex[1];

                                    // 请求未显示的图片id
                                    GM_xmlhttpRequest({
                                        method: 'GET',
                                        url: `https://weibo.com/aj/mblog/getover9pic?ajwvr=6&mid=${mid}&__rnd=${Date.now()}`,
                                        timeout: Config.maxRequestTime,
                                        responseType: "json",
                                        onload: function (res) {

                                            resolve(res.response.data.pids);
                                        },
                                        onerror: function (e) {
                                            console.error(e);
                                            reject("请求未展示图片发生错误");
                                        },
                                        ontimeout: function () {
                                            reject("请求未展示图片超时!");
                                        }
                                    });
                                } else { // 未找到mid
                                    reject("未能找到此条微博的mid!");
                                }
                            }
                        } else {
                            reject("获取图片ids失败!");
                        }

                    } else { // 图片数量未超9张

                        resolve([]);
                    }
                });
            },
            getLivePhotoContainer: $ul => $ul.parents(".WB_feed_detail").find(".WB_media_a"),
            getWeiBoCard: $ul => {

                const $box = $ul.parents("div.WB_feed_detail");

                const $box_expand = $box.find(".WB_feed_expand");

                let $box_node;

                // 这不是一条转发微博
                if ($box_expand.length == 0) {

                    $box_node = $box;

                } else { // 这是一条转发微博

                    $box_node = $box_expand;
                }

                return $box_node;
            },
            getWeiBoInfo: $ul => {

                return MyWeiBoResolver.getWeiBoCard($ul).find("div.WB_info a").first();
            },
            getWeiBoId: $ul => {

                const $info = MyWeiBoResolver.getWeiBoInfo($ul);

                const id_regex = $info.attr("suda-uatrack").match(/value=\w+:(\d+)/);

                let id;

                if (id_regex) { // 我的微博、他人微博(转发)、我的收藏、热门微博

                    id = id_regex[1].trim();

                } else { // 他人微博

                    id = $ul.parents(".WB_feed_detail").parents(".WB_cardwrap").attr("mid").trim();
                }

                Core.log(`得到的微博ID为:${id}`);

                return id;
            },
            getWeiBoUserId: $ul => {

                const $info = MyWeiBoResolver.getWeiBoInfo($ul);

                const user_id = $info.attr("usercard").match(/id=(\d+)/)[1].trim();

                Core.log(`得到的用户微博ID为:${user_id}`);

                return user_id;
            },
            getWeiBoUserName: $ul => {

                const $info = MyWeiBoResolver.getWeiBoInfo($ul);

                const name = $info.text().trim();

                Core.log(`得到的名称为:${name}`);

                return name;
            },
            getWeiBoUrl: $ul => {

                const $li_forward = $ul.parents(".WB_feed_detail").parents("div.WB_cardwrap")
                    .find(".WB_feed_handle .WB_row_line li:eq(1) a");

                const action_data = $li_forward.attr("action-data");

                const rooturl_regex = action_data.match(/rooturl=https:\/\/weibo\.com\/(\d+\/\w+)&/);

                let url;

                if (rooturl_regex) { // 这是转发微博

                    url = rooturl_regex[1].trim();

                } else {

                    url = action_data.match(/url=https:\/\/weibo\.com\/(\d+\/\w+)&/)[1].trim();
                }

                Core.log(`得到的此条微博地址为:${url}`);

                return url.replace("\/", "_");
            },
            getProgressContainer: $sub => $sub.parents("div.WB_feed_detail").find("div.WB_info").first(),
            getVideoBox: $ul => $ul.parents(".WB_feed_detail").find(".WB_video,.WB_video_a,.li_story"),
            geiVideoSrc: $box => {

                const video_sources = $box.attr("video-sources");

                // 多清晰度源
                const sources = video_sources.split("&");

                Core.log(sources);

                let src;

                // 逐步下调清晰度
                for (var i = sources.length - 2; i >= 0; i -= 1) {

                    if (sources[i].trim().split("=")[1].trim().length > 0) {

                        // 解码
                        var source = decodeURIComponent(decodeURIComponent(sources[i].trim()));

                        Core.log(source);

                        src = source.substring(source.indexOf("=") + 1);
                    }
                }

                return src;
            }
        });

        /**
         * 图片处理器(含:LivePhoto)
         */
        class PictureHandler {

            /**
             * 处理图片,如果需要
             */
            static async handlePictureIfNeed($ul) {

                const $button = Core.putButton($ul, "图片解析中...", null);

                try {

                    const resolver = Core.getWeiBoResolver();

                    const photo_9_ids = resolver.get9PhotoImgs($ul).map(function (i, it) {

                        const parts = $(it).attr("src").split("/");

                        return parts[parts.length - 1];
                    }).get();

                    Core.log("九宫格图片:");
                    Core.log(photo_9_ids);

                    const photo_9_over_ids = await resolver.get9PhotoOver($ul).catch(e => {

                        Tip.error(e);

                        return [];
                    });

                    Core.log("未展示图片:");
                    Core.log(photo_9_over_ids);

                    const photo_ids = photo_9_ids.concat(photo_9_over_ids);

                    Core.log("总图片:");
                    Core.log(photo_ids);

                    // 得到大图片
                    let $links = await PictureHandler.convertLargePhoto($ul, photo_ids);

                    Core.log(`此Item有图:${$links.length}`);

                    // 判断图片是否存在
                    if ($links.length > 0) {

                        // 得到LivePhoto的链接
                        const lp_links = PictureHandler.getLivePhoto($ul, $links.length);

                        // 存在LivePhoto
                        if (lp_links) {

                            $links = $($links.get().concat(lp_links));
                        }

                        Core.handleCopy($ul, $links);

                        PictureHandler.handleDownload($ul, $links);

                        PictureHandler.handleDownloadZip($ul, $links);
                    }
                } catch (e) {

                    console.error(e);

                    Tip.error(e.message);

                    Core.putButton($ul, "图片解析失败", null);

                } finally {

                    Core.removeButton($ul, $button);
                }
            }


            /**
             * 提取LivePhoto的地址
             * @param  {$标签对象} $owner ul或li
             * @return {字符串数组}       LivePhoto地址集,可能为null
             */
            static extractLivePhotoSrc($owner) {

                const action_data = $owner.attr("action-data");

                if (action_data) {

                    const urlsRegex = action_data.match(/pic_video=([\w:,]+)/);

                    if (urlsRegex) {

                        const urls = urlsRegex[1].split(",").map(function (it, i) {
                            return it.split(":")[1];
                        });

                        return urls;
                    }
                }

                return null;
            }

            /**
             * 得到LivePhoto链接集
             *
             * @param   {$标签对象} $ul     操作列表
             * @param   {整数}      start   下标开始的位置
             * @return  {Link数组}          链接集,可能为null
             */
            static getLivePhoto($ul, start) {

                const $box = Core.getWeiBoResolver().getLivePhotoContainer($ul);

                let srcs;

                // 仅有一张LivePhoto
                if ($box.hasClass('WB_media_a_m1')) {

                    srcs = PictureHandler.extractLivePhotoSrc($box.find(".WB_pic"));

                } else {

                    srcs = PictureHandler.extractLivePhotoSrc($box);
                }

                // 判断是否存在LivePhoto的链接
                if (srcs) {

                    srcs = srcs.map(function (it, i) {

                        var src = `https://video.weibo.com/media/play?livephoto=//us.sinaimg.cn/${it}.mov&KID=unistore,videomovSrc`;

                        var name = Core.getResourceName($ul, `https://weibo.com/${it}.mp4`, i + start, Config.mediaType.livePhoto);

                        return new Link(name, src);
                    });
                }

                return srcs;
            }

            // 处理下载
            static handleDownload($ul, $links) {

                Core.putButton($ul, "逐个下载图片", function () {

                    $links.each(function (i, it) {

                        // console.log("name:" + it.name + ",src=" + it.src);

                        GM_download(it.src, it.name);
                    });
                });
            }

            /**
             * 处理打包下载
             */
            static handleDownloadZip($ul, $links) {

                Core.putButton($ul, "打包下载图片", function () {

                    ZipHandler.startZip($ul, $links);
                });
            }

            /**
             * 转换为大图链接
             *
             * @param  {$控件} $ul        操作列表
             * @param  {数组}  photo_ids  图片id数组(可能无后缀)
             * @return {Link数组}       链接集,可能为null
             */
            static async convertLargePhoto($ul, photo_ids) {

                const photo_ids_fix = await Promise.all($(photo_ids).map(function (i, it) {

                    return new Promise((resolve, reject) => {

                        // 判断是否存在后缀
                        if (it.indexOf(".") != -1) { // 存在

                            resolve(it);

                        } else { // 不存在

                            // 请求,不打开流,只需要头信息
                            GM_xmlhttpRequest({
                                method: 'GET',
                                url: `http://wx2.sinaimg.cn/thumb150/${it}`,
                                timeout: Config.maxRequestTime,
                                responseType: "blob",
                                onload: function (res) {

                                    const postfix_regex = res.responseHeaders.match(/content-type: image\/(\w+)/);

                                    // 找到,且图片类型为git
                                    if (postfix_regex && postfix_regex[1] == "gif") {

                                        resolve(`${it}.gif`);

                                    } else { // 未找到,或图片类型为:jpeg

                                        resolve(`${it}.jpg`);
                                    }
                                },
                                onerror: function (e) {

                                    console.error(e);

                                    reject("请求图片格式发生错误!");
                                },
                                ontimeout: function () {

                                    reject("请求图片格式超时!");
                                }
                            });
                        }
                    }).catch(e => {

                        Tip.error(e);

                        return `${it}.jpg`;
                    });
                }).get());

                Core.log("总图片(fix):");
                Core.log(photo_ids_fix);

                return $(photo_ids_fix).map((i, it) => {

                    // 替换为大图链接
                    const src = `http://wx2.sinaimg.cn/large/${it}`;

                    Core.log(src);

                    const name = Core.getResourceName($ul, src, i, Config.mediaType.picture);

                    return new Link(name, src);
                });
            }
        }

        /**
         * 视频处理器
         */
        class VideoHandler {

            /**
             * 处理视频如果需要
             * @param  {$标签对象} $ul 操作列表
             */
            static async handleVideoIfNeed($ul) {

                const $button = Core.putButton($ul, "视频解析中...", null);

                try {

                    const $box = Core.getWeiBoResolver().getVideoBox($ul);

                    // 不存在视频
                    if ($box.length === 0) {
                        return;
                    }

                    // 得到视频类型
                    const type = VideoHandler.getVideoType($box);


                    let $link;

                    if (type === "feedvideo") { // 短视屏(秒拍、梨视频、优酷)

                        $link = VideoHandler.getBlowVideoLink($box);

                    } else if (type === "feedlive") { // 直播回放 暂不支持
                    } else if (type === "story") { // 微博故事

                        $link = VideoHandler.getWeiboStoryLink($box);

                    } else {

                        console.warn(`未知的类型:${type}`);
                    }

                    // 是否存在视频链接
                    if ($link) {

                        Core.handleCopy($ul, $([$link]));

                        const fun = () => VideoHandler.downloadVideo($box, $link);

                        Core.putButton($ul, "下载当前视频", fun);
                    }

                } catch (e) {

                    console.error(e);

                    Tip.error(e.message);

                    Core.putButton($ul, "视频解析失败", null);

                } finally {

                    Core.removeButton($ul, $button);
                }
            }

            /**
             * 得到视频类型
             * @param  {$标签对象} $box 视频容器
             * @return {字符串}         视频类型[video、live]
             */
            static getVideoType($box) {

                const typeRegex = $box.attr("action-data").match(/type=(\w+)&/);

                return typeRegex[1];
            }

            /**
             * 得到微博故事视频Link
             *
             * @param  {$标签对象} $box 视频box
             *
             * @return {Link}      链接对象
             */
            static getWeiboStoryLink($box) {

                const action_data = $box.attr("action-data");

                const urlRegex = action_data.match(/gif_url=([\w%.]+)&/);

                const url = urlRegex[1];

                let src = decodeURIComponent(decodeURIComponent(url));

                const name = Core.getResourceName($box, src.split("?")[0], 0, Config.mediaType.video);

                if (src.indexOf("//") === 0) {
                    src = "https:" + src;
                }

                return new Link(name, src);
            }

            /**
             * 得到酷燃视频Link
             *
             * @param  {$标签对象} $box 视频box
             *
             * @return {Link}      链接对象
             */
            static getBlowVideoLink($box) {

                let src, name;

                try {

                    src = Core.getWeiBoResolver().geiVideoSrc($box);

                    if (!src) { // 未找到合适的视频地址

                        throw new Error("未能找到视频地址!");
                    }

                    name = Core.getResourceName($box, src.split("?")[0], 0, Config.mediaType.video);

                    Core.log(`download:${name}=${src}`);

                } catch (e) {

                    console.error(e);

                    throw new Error("未能找到视频地址!");
                }

                return new Link(name, src);
            }

            /**
             * 下载视频
             *
             * @param  {$标签对象} $box  视频box
             * @param  {$对象}    $link  Link对象
             */
            static downloadVideo($box, $link) {

                Tip.info("即将开始下载...");

                const progress = ZipHandler.bornProgress($box);

                GM_download({
                    url: $link.src,
                    name: $link.name,
                    onprogress: function (p) {

                        const value = p.loaded / p.total;
                        progress.value = value;
                    },
                    onerror: function (e) {

                        console.error(e);

                        Tip.error("视频下载出错!");
                    }
                });
            }
        }

        class ZipHandler {

            /**
             * 生成一个进度条
             * @param  {$标签对象} $sub card的子节点
             * @param  {int}      max  最大值
             * @return {标签对象}     进度条
             */
            static bornProgress($sub) {

                const $div = Core.getWeiBoResolver().getProgressContainer($sub);

                // 尝试获取进度条
                let $progress = $div.find('progress');

                // 进度条不存在时,生成一个
                if ($progress.length === 0) {

                    $progress = $("<progress max='1' style='margin-left:10px;' />");

                    $div.append($progress);

                } else { // 已存在时,重置value

                    $progress[0].value = 0;
                }

                return $progress[0];
            }

            /**
             * 开始打包
             * @param  {$数组} $links 图片地址集
             */
            static startZip($ul, $links) {

                Tip.tip("正在提取,请稍候...", "iconExtract");

                const progress = ZipHandler.bornProgress($ul);

                const zip = new JSZip();

                const names = [];

                $links.each(function (i, it) {

                    const name = it.name;

                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: it.src,
                        timeout: Config.maxRequestTime,
                        responseType: "blob",
                        onload: function (response) {

                            zip.file(name, response.response);

                            ZipHandler.downloadZipIfComplete($ul, progress, name, zip, names, $links.length);
                        },
                        onerror: function (e) {

                            console.error(e);

                            Tip.error(`第${(i + 1)}个对象,获取失败!`);

                            ZipHandler.downloadZipIfComplete($ul, progress, name, zip, names, $links.length);
                        },
                        ontimeout: function () {

                            Tip.error(`第${(i + 1)}个对象,请求超时!`);

                            ZipHandler.downloadZipIfComplete($ul, progress, name, zip, names, $links.length);
                        }
                    });
                });
            }

            /**
             * 下载打包,如果完成
             */
            static downloadZipIfComplete($ul, progress, name, zip, names, length) {

                names.push(name);

                const value = names.length / length;

                progress.value = value;

                if (names.length === length) {

                    Tip.tip("正在打包,请稍候...", "iconZip");

                    zip.generateAsync({
                        type: "blob"
                    }, function (metadata) {

                        progress.value = metadata.percent / 100;

                    }).then(function (content) {

                        Tip.success("打包完成,即将开始下载!");

                        const zipName = Core.getZipName($ul);

                        saveAs(content, `${zipName}.zip`);
                    });
                }
            }
        }

        /**
         * 提示
         */
        class Tip {

            static tip(text, iconName) {
                GM_notification({
                    text: text,
                    image: GM_getResourceURL(iconName)
                });
            }

            static info(text) {
                Tip.tip(text, "iconInfo");
            }

            static error(text) {
                Tip.tip(text, "iconError");
            }

            static success(text) {
                Tip.tip(text, "iconSuccess");
            }
        }

        /**
         * 核心
         */
        class Core {

            /**
             * 处理微博卡片
             */
            static handleWeiBoCard() {

                // 查找未被扩展的操作按钮
                const $operationButtons = Core.getWeiBoResolver().getOperationButton();

                // 存在未被扩展的操作按钮
                if ($operationButtons.length > 0) {

                    console.info(`找到未被扩展的操作按钮:${$operationButtons.length}`);

                    $operationButtons.one("click", event =>
                        Core.resolveWeiBoCard($(event.currentTarget))
                    );

                    $operationButtons.addClass(Config.handledWeiBoCardClass);
                }
            }

            /**
             * 解析 微博卡片
             * 仅在初次点击 操作按钮[↓] 时,触发
             *
             * @param  {$标签对象} $operationButton  操作按钮
             */
            static resolveWeiBoCard($operationButton) {

                const $ul = Core.getWeiBoResolver().getOperationList($operationButton);

                PictureHandler.handlePictureIfNeed($ul);
                VideoHandler.handleVideoIfNeed($ul);
            }

            /**
             * 得到微博解析器
             */
            static getWeiBoResolver() {

                let resolver;

                // 微博搜索
                if (currentUrl.indexOf("https://s.weibo.com") === 0) {

                    resolver = SearchWeiBoResolver;

                } else { // 我的微博、他人微博、我的收藏、热门微博

                    resolver = MyWeiBoResolver;
                }

                return resolver;
            }

            /**
             * 添加按钮
             * @param  {$标签对象} $ul  操作列表
             * @param  {字符串} name 按钮名称
             * @param  {方法} op   按钮操作
             *
             * @return {$控件} 按钮
             */
            static putButton($ul, name, op) {

                const $li = $(`<li><a href='javascript:void(0)'>—> ${name} <—</a></li>`);

                $li.click(op);

                $ul.append($li);

                return $li;
            }

            /**
             * 移除按钮
             * @param  {$标签对象} $ul  操作列表
             * @param  {$控件}    $button 按钮
             */
            static removeButton($ul, $button) {

                $ul.find(`li a:contains(${$button.text()})`).remove();
            }

            /**
             * 处理拷贝
             *
             * @param  {$对象} $ul    操作列表
             * @param  {$数组} $links Link数组
             */
            static handleCopy($ul, $links) {

                Core.putButton($ul, "复制资源链接", function () {

                    const link = $links.get().map(function (it, i) {
                        return it.src;
                    }).join("\n");

                    GM_setClipboard(link, "text");

                    Tip.success("链接地址已复制到剪贴板!");
                });
            }

            /**
             * 得到打包名称
             *
             * @param  {$标签对象} $ul      操作列表
             * @return {字符串}             压缩包名称(不含后缀)
             */
            static getZipName($ul) {

                const weiBoResolver = Core.getWeiBoResolver();

                const wb_user_name = weiBoResolver.getWeiBoUserName($ul);
                const wb_user_id = weiBoResolver.getWeiBoUserId($ul);
                const wb_id = weiBoResolver.getWeiBoId($ul);
                const wb_url = weiBoResolver.getWeiBoUrl($ul);

                const name = Config.getZipName(wb_user_name, wb_user_id, wb_id, wb_url);

                return name;
            }

            /**
             * 得到资源原始名称
             * @param  {字符串} path 路径
             * @return {字符串}     名称(含后缀)
             */
            static getPathName(path) {
                const name = path.substring(path.lastIndexOf("/") + 1);
                Core.log(`截得名称为:${name}`);
                return name;
            }

            /**
             * 得到后缀
             * @param  {字符串} path 路径
             * @return {字符串}     后缀(含.)
             */
            static getPathPostfix(path) {
                const postfix = path.substring(path.lastIndexOf("."));
                Core.log(`截得后缀为:${postfix}`);
                return postfix;
            }

            /**
             * 得到资源名称
             *
             * @param  {$标签对象} $ul        操作列表
             * @param  {字符串}    src        资源地址
             * @param  {整数}      index      序号
             * @param  {字符串}    media_type 媒体类型
             *
             * @return {字符串}             资源名称(含后缀)
             */
            static getResourceName($ul, src, index, media_type) {

                const weiBoResolver = Core.getWeiBoResolver();

                const wb_user_name = weiBoResolver.getWeiBoUserName($ul);
                const wb_user_id = weiBoResolver.getWeiBoUserId($ul);
                const wb_id = weiBoResolver.getWeiBoId($ul);
                const wb_url = weiBoResolver.getWeiBoUrl($ul);
                const resource_id = Core.getPathName(src);

                // 修正,从1开始
                index++;

                // 补齐位数:01、02、03...
                if (index.toString().length === 1) {
                    index = "0" + index.toString();
                }

                const no = index;

                const postfix = Core.getPathPostfix(src);

                return Config.getResourceName(wb_user_name, wb_user_id, wb_id, wb_url,
                    resource_id, no, media_type) + postfix;
            }

            /**
             * 记录日志
             * @param  {字符串} msg 日志内容
             */
            static log(msg) {
                if (Config.isDebug) {
                    console.log(msg);
                }
            }
        }

        setInterval(Core.handleWeiBoCard, Config.space);
    }
}

// 电影搜索,音乐下载,购物券,电影解析
function superTool(currentUrl, currentHost) {
    if (reSite.test(top.window.location.href) || $("#Wandhi-nav").length > 0) {
        return;
    }
    if (reWY.test(currentUrl) || reQQ.test(currentUrl) || reKG.test(currentUrl) || reKW.test(currentUrl) ||
        reXM.test(currentUrl) || reBD.test(currentUrl) || reQT.test(currentUrl) || reLZ.test(currentUrl) ||
        reMiGu.test(currentUrl) || reXMLY.test(currentUrl)) {
        var menus = [
            {title: '音乐下载', show: '音乐<br>下载', type: 'music'},
            {title: '电影搜索', show: '电影<br>搜索', type: 'search'},
            {title: '淘宝好券', show: '淘宝<br>好券', type: 'tb'},
            {title: '京东好券', show: '京东<br>好券', type: 'jd'}
        ];
        initMenu(menus, function () {
            $('body').on('click', '[data-cat=music]', function () {
                window.open('http://video.haokanba.top/music');
            });
            $('body').on('click', '[data-cat=search]', function () {
                window.open('http://video.haokanba.top/');
            });
            $('body').on('click', '[data-cat=tb]', function () {
                window.open('https://link.zhihu.com/?target=http://shop.haokanba.top');
            });
            $('body').on('click', '[data-cat=jd]', function () {
                window.open('http://jd.haokanba.top');
            });
        });
    } else if (reAqy.test(currentUrl) || reLS.test(currentUrl) || reTX.test(currentUrl) || reTD.test(currentUrl) ||
        reMG.test(currentUrl) || reSH.test(currentUrl) || rePP.test(currentUrl) || reYk.test(currentUrl)) {
        var menus = [
            {title: '电影搜索', show: '电影<br>搜索', type: 'search'},
            {title: '视频解析', show: '视频<br>解析', type: 'process'},
            {title: '淘宝好券', show: '淘宝<br>好券', type: 'tb'},
            {title: '京东好券', show: '京东<br>好券', type: 'jd'}
        ];
        initMenu(menus, function () {
            $('body').on('click', '[data-cat=process]', function () {//视频解析
                window.open('http://movie.haokanba.top?url=' + encodeURIComponent(currentUrl));
            });
            $('body').on('click', '[data-cat=search]', function () {//电影搜索
                window.open('http://video.haokanba.top');
            });
            $('body').on('click', '[data-cat=tb]', function () {
                window.open('https://link.zhihu.com/?target=http://shop.haokanba.top/');
            });
            $('body').on('click', '[data-cat=jd]', function () {
                window.open('http://jd.haokanba.top');
            });
        })
    } else if (reTaoBao.test(currentUrl) || reTmall.test(currentUrl) || reAliShop.test(currentUrl)) {
        queryCoupon();
        appendShopping();
    } else if (reJd.test(currentUrl)) {//查询京东优惠券
        appendShopping();
    } else if (reQD.test(currentUrl)) {
        var menus = [
            {title: '免费小说', show: '免费<br>小说', type: 'book'},
            {title: '淘宝好券', show: '淘宝<br>好券', type: 'tb'},
            {title: '京东好券', show: '京东<br>好券', type: 'jd'},
            {title: '拼多多好券', show: '拼多多<br>好券', type: 'pdd'}];
        initMenu(menus, function () {
            $('body').on('click', '[data-cat=book]', function () {
                window.open('http://xs.haokanba.top');
            });
            //淘宝优惠券
            $('body').on('click', '[data-cat=tb]', function () {
                window.open('https://link.zhihu.com/?target=http://shop.haokanba.top');
            });
            //京东优惠券
            $('body').on('click', '[data-cat=jd]', function () {
                window.open('http://jd.haokanba.top');
            });
            //拼多多优惠券
            $('body').on('click', '[data-cat=pdd]', function () {
                window.open('https://youhui.pinduoduo.com/?pid=9519321_124015430&fromCustomerMall=1&cpsSign=CM_200312_9519321_124015430_7fb46e7d0e8245ac2b68b58852a1a989&duoduo_type=2');
            });
        });
    } else if (reWenku.test(currentUrl)) {
        var menus = [
            {title: '百度文库', show: '文库<br>解析', type: 'wenku'},
            {title: '淘宝好券', show: '淘宝<br>好券', type: 'tb'},
            {title: '京东好券', show: '京东<br>好券', type: 'jd'},
            {title: '拼多多好券', show: '拼多多<br>好券', type: 'pdd'}
        ];
        initMenu(menus, function () {
            //文库解析
            $('body').on('click', '[data-cat=wenku]', function () {
                window.open('http://www.html22.com/doc/?url=' + currentUrl);
            });
            //淘宝优惠券
            $('body').on('click', '[data-cat=tb]', function () {
                window.open('https://link.zhihu.com/?target=http://shop.haokanba.top');
            });
            //京东优惠券
            $('body').on('click', '[data-cat=jd]', function () {
                window.open('http://jd.haokanba.top');
            });
            //拼多多优惠券
            $('body').on('click', '[data-cat=pdd]', function () {
                window.open('https://youhui.pinduoduo.com/?pid=9519321_124015430&fromCustomerMall=1&cpsSign=CM_200312_9519321_124015430_7fb46e7d0e8245ac2b68b58852a1a989&duoduo_type=2');
            });
        });
    } else if (reBili.test(currentUrl)) {
        var menus = [
            {title: '查看封面', show: '查看<br>封面', type: 'backcover'},
            {title: '电影搜索', show: '电影<br>搜索', type: 'search'},
            {title: '淘宝好券', show: '淘宝<br>好券', type: 'tb'},
            {title: '京东好券', show: '京东<br>好券', type: 'jd'}
        ];
        initMenu(menus, function () {
            //查看封面
            $('body').on('click', '[data-cat=backcover]', function () {
                biliFrontCover();
            });
            //电影搜索
            $('body').on('click', '[data-cat=search]', function () {
                window.open('http://video.haokanba.top');
            });
            //淘宝优惠券
            $('body').on('click', '[data-cat=tb]', function () {
                window.open('https://link.zhihu.com/?target=http://shop.haokanba.top');
            });
            //京东优惠券
            $('body').on('click', '[data-cat=jd]', function () {
                window.open('http://jd.haokanba.top');
            });
        });
    }

    function appendShopping() {
        var menus = [
            {title: '淘宝好券', show: '淘宝<br>好券', type: 'tb'},
            {title: '京东好券', show: '京东<br>好券', type: 'jd'},
            {title: '拼多多好券', show: '拼多多<br>好券', type: 'pdd'}
        ];
        initMenu(menus, function () {
            $('body').on('click', '[data-cat=tb]', function () {
                var bid = getQueryString('id');
                if (bid != null) {
                    window.open(decodeURIComponent("http://shop.haokanba.top/goods?id=" + bid));
                } else {
                    window.open('https://link.zhihu.com/?target=http://shop.haokanba.top/');
                }
            });
            $('body').on('click', '[data-cat=jd]', function () {
                var bid = currentUrl.match("\\d+(?=\\.html)");
                if (bid != null) {
                    window.open("http://jd.haokanba.top/?ah=detail&id=" + bid, '_parent');
                } else {
                    window.open('http://jd.haokanba.top');
                }
            });
            $('body').on('click', '[data-cat=pdd]', function () {
                window.open('https://youhui.pinduoduo.com/?pid=9519321_124015430&fromCustomerMall=1&cpsSign=CM_200312_9519321_124015430_7fb46e7d0e8245ac2b68b58852a1a989&duoduo_type=2');
            });
        })
    }

    function queryCoupon() {
        var bid = getQueryString('id');
        var h = "https://v2.api.haodanku.com/supersearch/apikey/tukergo/keyword/" + bid + "/back/10/min_id/1/tb_p/1/sort/0/is_tmall/0/is_coupon/0/limitrate/0";
        $('head').append($('<link rel="stylesheet" href="//cdn.wandhi.com/style/extenstion/hui.style.css">'));
        var init = "<div id='wandhi_div'><table class='wandhi_tab' id='wandhi_table'><thead><tr><th>" +
            "<b style='cursor:pointer'>优惠券</b></th><th>券后</th><th>有 效 期</th><th>操作</th></tr></thead><tr><td colspan='4'>正在查询优惠信息,请稍候...</td></tr></table></div>";
        if (reTaoBao.test(currentUrl)) {
            $('.J_LinkAdd').parent().parent().prepend(init);
            $('#wandhi_table').addClass('wandhi_tab_taobao');
        } else {
            $('#J_LinkBasket').parent().parent().prepend(init);
            $('#wandhi_table').addClass('wandhi_tab_tmall');
            setInterval(function () {
                $('#J_ButtonWaitWrap').hide();
                $('#J_LinkBuy').parent().removeClass("tb-hidden");
                $('#J_LinkBasket').parent().removeClass("tb-hidden");
            }, 2000);
        }
        $.getJSON(h, function (d) {
            $("#wandhi_table tbody tr").remove();
            var row = "";
            if (d.code) {
                d.data.forEach(function (e) {
                    row += "<tr>" +
                        "<td>" + e.itemshorttitle + "</td>" +
                        "<td>" + e.itemendprice + "</td>" +
                        "<td>" + transformTime(e.couponendtime * 1000) + "</td>" +
                        "<td><a href=" + "http://shop.haokanba.top/goods?id=" + bid + ">领取</a></td>" +
                        "</tr>";
                });
            } else {
                row = "<tr><td colspan='4'>这个商品没有超值优惠券</td></tr>";
            }
            $("#wandhi_table tbody").append(row);
        });
    }

    function biliFrontCover() {
        var loading = layer.load(1, {shade: [0.8, '#393D49'], time: 10 * 1000});
        var h = 'https://api.wandhi.com';
        var api = '/api/tools/bili?url=' + currentUrl;
        $.getJSON(h + api, function (d) {
            if (d.code) {
                showContent('<img src="' + d.data + '">', '封面');
            } else {
                alertMessage("哎哟?没找到封面哦");
            }
            layer.close(loading);
        });
    }

    function initMenu(obj, init) {
        var menusclass = ['first', 'second', 'third', 'fourth', 'fifth'];
        var str = "";
        $.each(obj, function (i, o) {
            str += '<a href="javascript:void(0)" title="' + o.title + '" data-cat="' + o.type + '" class="menu-item menu-line menu-' + menusclass[i] + '">' + o.show + '</a>';
        });
        var sidenav = '<svg width="0" height="0"><defs><filter id="goo"><feGaussianBlur in="SourceGraphic" stdDeviation="10" ' +
            'result="blur"></feGaussianBlur><feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" ' +
            'result="goo"></feColorMatrix><feComposite in="SourceGraphic" in2="goo" operator="atop"></feComposite></filter>' +
            '</defs></svg><div class="aside-nav bounceInUp animated" id="Wandhi-nav">' +
            '<label for="" class="aside-menu" title="按住拖动">VIP</label>' + str + '</div>';
        $("body").append(sidenav).append($('<link rel="stylesheet" ' +
            'href="//cdn.wandhi.com/style/tv/asidenav.css">')).append($('<link rel="stylesheet" ' +
            'href="https://lib.baomitu.com/layer/3.1.1/theme/default/layer.css">'));
        var ua = navigator.userAgent;
        /Safari|iPhone/i.test(ua) && 0 == /chrome/i.test(ua) && $("#Wandhi-nav").addClass("no-filter");
        var drags = {down: !1, x: 0, y: 0, winWid: 0, winHei: 0, clientX: 0, clientY: 0},
            asideNav = $("#Wandhi-nav")[0], getCss = function (a, e) {
                return a.currentStyle ? a.currentStyle[e] : document.defaultView.getComputedStyle(a, !1)[e]
            };
        $("body").on("mousedown", "#Wandhi-nav", function (a) {
            drags.down = !0, drags.clientX = a.clientX, drags.clientY = a.clientY, drags.x = getCss(this, "left"), drags.y = getCss(this, "top"), drags.winHei = $(window).height(), drags.winWid = $(window).width(), $(document).on("mousemove", function (a) {
                var e = a.clientX - drags.clientX, t = a.clientY - drags.clientY;
                asideNav = asideNav || $("#Wandhi-nav")[0];
                asideNav.style.top = parseInt(drags.y) + t + "px";
                asideNav.style.left = parseInt(drags.x) + e + "px";
            })
        }).on("mouseup", "#Wandhi-nav", function () {
            drags.down = !1, $(document).off("mousemove")
        });
        init();
    }
}

// 网盘工具
function netDiskTool(currentUrl, currentHost) {
    if (currentHost.indexOf("pan.baidu.com") != -1 || currentHost.indexOf("yun.baidu.com") != -1
        || currentHost.indexOf("lanzous.com") != -1 || currentHost.indexOf("newday.me") != -1) {

        var injectConfig = {
            name: "wpzs",
            version: "0.3.7",
            addon: {
                options_page: "/page/wpzs/option.html"
            },
            script: {
                options_page: "http://pan.newday.me/script/option.html"
            }
        };

        var container = (function () {
            var obj = {
                module_defines: {},
                module_objects: {}
            };

            obj.define = function (name, requires, callback) {
                name = obj.processName(name);
                obj.module_defines[name] = {
                    requires: requires,
                    callback: callback
                };
            };

            obj.require = function (name, cache) {
                if (typeof cache == "undefined") {
                    cache = true;
                }

                name = obj.processName(name);
                if (cache && obj.module_objects.hasOwnProperty(name)) {
                    return obj.module_objects[name];
                } else if (obj.module_defines.hasOwnProperty(name)) {
                    var requires = obj.module_defines[name].requires;
                    var callback = obj.module_defines[name].callback;

                    var module = obj.use(requires, callback);
                    cache && obj.register(name, module);
                    return module;
                }
            };

            obj.use = function (requires, callback) {
                var module = {
                    exports: {}
                };
                var params = obj.buildParams(requires, module);
                var result = callback.apply(this, params);
                if (typeof result != "undefined") {
                    return result;
                } else {
                    return module.exports;
                }
            };

            obj.register = function (name, module) {
                name = obj.processName(name);
                obj.module_objects[name] = module;
            };

            obj.buildParams = function (requires, module) {
                var params = [];
                requires.forEach(function (name) {
                    params.push(obj.require(name));
                });
                params.push(obj.require);
                params.push(module.exports);
                params.push(module);
                return params;
            };

            obj.processName = function (name) {
                return name.toLowerCase();
            };

            return {
                define: obj.define,
                use: obj.use,
                register: obj.register,
                modules: obj.module_objects
            };
        })();

        container.define("gm", [], function () {
            var obj = {};

            obj.ready = function (callback) {
                if (typeof GM_getValue != "undefined") {
                    callback && callback();
                } else {
                    setTimeout(function () {
                        obj.ready(callback);
                    }, 100);
                }
            };

            return obj;
        });

        container.define("runtime", [], function () {
            var obj = {
                url: location.href,
                referer: document.referrer,
            };

            obj.getUrl = function () {
                return obj.url;
            };

            obj.setUrl = function (url) {
                obj.url = url;
            };

            obj.getReferer = function () {
                return obj.referer;
            };

            obj.setReferer = function (referer) {
                obj.referer = referer;
            };

            obj.getUrlParam = function (name) {
                var param = obj.parseUrlParam(obj.getUrl());
                if (name) {
                    return param.hasOwnProperty(name) ? param[name] : null;
                } else {
                    return param;
                }
            };

            obj.parseUrlParam = function (url) {
                if (url.indexOf("?")) {
                    url = url.split("?")[1];
                }
                var reg = /([^=&\s]+)[=\s]*([^=&\s]*)/g;
                var obj = {};
                while (reg.exec(url)) {
                    obj[RegExp.$1] = RegExp.$2;
                }
                return obj;
            };

            return obj;
        });

        container.define("object", [], function () {
            var obj = {};

            obj.keys = function (data) {
                var list = [];
                for (var key in data) {
                    list.push(key);
                }
                return list;
            };

            obj.values = function (data) {
                var list = [];
                for (var key in data) {
                    list.push(data[key]);
                }
                return list;
            };

            return obj;
        });

        container.define("storage", [], function () {
            var obj = {};

            obj.getValue = function (name, defaultValue) {
                return GM_getValue(name, defaultValue);
            };

            obj.setValue = function (name, value) {
                GM_setValue(name, value);
            };

            obj.getValueList = function () {
                var nameList = GM_listValues();
                var valueList = {};
                nameList.forEach(function (name) {
                    valueList[name] = obj.getValue(name);
                });
                return valueList;
            };

            return obj;
        });

        container.define("addon", ["storage", "constant"], function (storage, constant) {
            var obj = {
                name: constant.name + "_status"
            };

            obj.isEnable = function () {
                if (storage.getValue(obj.name) == "off") {
                    return false;
                } else {
                    return true;
                }
            };

            return obj;
        });

        container.define("config", ["storage", "constant"], function (storage, constant) {
            var obj = {
                name: "config_json"
            };

            obj.getConfig = function (name) {
                var configJson = storage.getValue(obj.name);
                var configObject = obj.parseJson(configJson);
                if (name) {
                    name = obj.processName(name);
                    return configObject.hasOwnProperty(name) ? configObject[name] : null;
                } else {
                    return configObject;
                }
            };

            obj.setConfig = function (name, value) {
                var configObject = obj.getConfig();
                configObject[obj.processName(name)] = value;
                storage.setValue(obj.name, JSON.stringify(configObject));
            };

            obj.parseJson = function (jsonStr) {
                var jsonObject = {};
                try {
                    if (jsonStr) {
                        jsonObject = JSON.parse(jsonStr);
                    }
                } catch (e) {
                }
                return jsonObject;
            };

            obj.processName = function (name) {
                return constant.name + "_" + name;
            };

            return obj;
        });

        container.define("option", ["config", "constant", "object"], function (config, constant, object) {
            var obj = {
                name: "option",
                constant: constant.option
            };

            obj.isOptionActive = function (item) {
                var name = item.name;
                var option = obj.getOption();
                return option.indexOf(name) >= 0;
            };

            obj.setOptionActive = function (item) {
                var name = item.name;
                var option = obj.getOption();
                if (option.indexOf(name) < 0) {
                    option.push(name);
                    obj.setOption(option);
                }
            };

            obj.setOptionUnActive = function (item) {
                var name = item.name;
                var option = obj.getOption();
                var index = option.indexOf(name);
                if (index >= 0) {
                    delete option[index];
                    obj.setOption(option);
                }
            };

            obj.getOption = function () {
                var option = [];
                var optionObject = obj.getOptionObject();
                object.values(obj.constant).forEach(function (item) {
                    var name = item.name;
                    if (optionObject.hasOwnProperty(name)) {
                        if (optionObject[name] != "no") {
                            option.push(name);
                        }
                    } else if (item.value != "no") {
                        option.push(name);
                    }
                });
                return option;
            };

            obj.setOption = function (option) {
                var optionObject = {};
                object.values(obj.constant).forEach(function (item) {
                    var name = item.name;
                    if (option.indexOf(name) >= 0) {
                        optionObject[name] = "yes";
                    } else {
                        optionObject[name] = "no";
                    }
                });
                obj.setOptionObject(optionObject);
            };

            obj.getOptionObject = function () {
                var optionObject = config.getConfig(obj.name);
                return optionObject ? optionObject : {};
            };

            obj.setOptionObject = function (optionObject) {
                config.setConfig(obj.name, optionObject);
            };

            return obj;
        });

        container.define("mode", [], function () {
            var obj = {
                constant: {
                    addon: "addon",
                    script: "script"
                }
            };

            obj.getMode = function () {
                if (GM_info.addon) {
                    return obj.constant.addon;
                } else {
                    return obj.constant.script;
                }
            };

            return obj;
        });

        container.define("user", ["storage"], function (storage) {
            var obj = {};

            obj.getUid = function () {
                var uid = storage.getValue("uid");
                if (!uid) {
                    uid = obj.randString(32);
                    storage.setValue("uid", uid);
                }
                return uid;
            };

            obj.randString = function (length) {
                var possible = "abcdefghijklmnopqrstuvwxyz0123456789";
                var text = "";
                for (var i = 0; i < length; i++) {
                    text += possible.charAt(Math.floor(Math.random() * possible.length));
                }
                return text;
            };

            return obj;
        });

        container.define("browser", [], function () {
            var obj = {
                constant: {
                    firefox: "firefox",
                    edge: "edge",
                    baidu: "baidu",
                    liebao: "liebao",
                    uc: "uc",
                    qq: "qq",
                    sogou: "sogou",
                    opera: "opera",
                    maxthon: "maxthon",
                    ie2345: "2345",
                    se360: "360",
                    chrome: "chrome",
                    safari: "safari",
                    other: "other"
                }
            };

            obj.getBrowser = function () {
                return obj.matchBrowserType(navigator.userAgent);
            };

            obj.matchBrowserType = function (userAgent) {
                var browser = obj.constant.other;
                userAgent = userAgent.toLowerCase();
                if (userAgent.match(/firefox/) != null) {
                    browser = obj.constant.firefox;
                } else if (userAgent.match(/edge/) != null) {
                    browser = obj.constant.edge;
                } else if (userAgent.match(/bidubrowser/) != null) {
                    browser = obj.constant.baidu;
                } else if (userAgent.match(/lbbrowser/) != null) {
                    browser = obj.constant.liebao;
                } else if (userAgent.match(/ubrowser/) != null) {
                    browser = obj.constant.uc;
                } else if (userAgent.match(/qqbrowse/) != null) {
                    browser = obj.constant.qq;
                } else if (userAgent.match(/metasr/) != null) {
                    browser = obj.constant.sogou;
                } else if (userAgent.match(/opr/) != null) {
                    browser = obj.constant.opera;
                } else if (userAgent.match(/maxthon/) != null) {
                    browser = obj.constant.maxthon;
                } else if (userAgent.match(/2345explorer/) != null) {
                    browser = obj.constant.ie2345;
                } else if (userAgent.match(/chrome/) != null) {
                    if (obj.existMime("type", "application/vnd.chromium.remoting-viewer")) {
                        browser = obj.constant.se360;
                    } else {
                        browser = obj.constant.chrome;
                    }
                } else if (userAgent.match(/safari/) != null) {
                    browser = obj.constant.safari;
                }
                return browser;
            };

            obj.existMime = function (option, value) {
                if (typeof navigator != "undefined") {
                    var mimeTypes = navigator.mimeTypes;
                    for (var mt in mimeTypes) {
                        if (mimeTypes[mt][option] == value) {
                            return true;
                        }
                    }
                }
                return false;
            };

            return obj;
        });

        container.define("env", ["mode", "user", "browser", "constant"], function (mode, user, browser, constant) {
            var obj = {};

            obj.isAddon = function () {
                if (mode.getMode() == mode.constant.addon) {
                    return true;
                } else {
                    return false;
                }
            };

            obj.isInject = function () {
                if (obj.isAddon()) {
                    if (GM_info.addon.name != constant.name) {
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    if (GM_info.script.alias && GM_info.script.alias != constant.name) {
                        return true;
                    } else {
                        return false;
                    }
                }
            };

            obj.getMode = function () {
                return mode.getMode();
            };

            obj.getAid = function () {
                if (GM_info.addon && GM_info.addon.id) {
                    return GM_info.addon.id;
                } else if (GM_info.scriptHandler) {
                    return GM_info.scriptHandler.toLowerCase();
                } else {
                    return "unknown";
                }
            };

            obj.getUid = function () {
                return user.getUid();
            };

            obj.getVersion = function () {
                if (obj.isInject()) {
                    return injectConfig.version;
                } else {
                    return GM_info.script.version;
                }
            };

            obj.getBrowser = function () {
                return browser.getBrowser();
            };

            obj.getInfo = function () {
                return {
                    mode: obj.getMode(),
                    aid: obj.getAid(),
                    uid: obj.getUid(),
                    version: obj.getVersion(),
                    browser: obj.getBrowser()
                };
            };

            return obj;
        });

        container.define("http", [], function () {
            var obj = {};

            obj.ajax = function (option) {
                var details = {
                    method: option.type,
                    url: option.url,
                    responseType: option.dataType,
                    onload: function (result) {
                        option.success && option.success(result.response);
                    },
                    onerror: function (result) {
                        option.error && option.error(result.error);
                    }
                };

                // 提交数据
                if (option.data) {
                    if (option.data instanceof FormData) {
                        details.data = option.data;
                    } else {
                        var formData = new FormData();
                        for (var i in option.data) {
                            formData.append(i, option.data[i]);
                        }
                        details.data = formData;
                    }
                }

                // 自定义头
                if (option.headers) {
                    details.headers = option.headers;
                }

                // 超时
                if (option.timeout) {
                    details.timeout = option.timeout;
                }

                GM_xmlhttpRequest(details);
            };

            return obj;
        });

        container.define("router", [], function () {
            var obj = {};

            obj.goUrl = function (url) {
                obj.runCode('location.href = "' + url + '";');
            };

            obj.openUrl = function (url) {
                obj.runCode('window.open("' + url + '");');
            };

            obj.openTab = function (url, active) {
                GM_openInTab(url, !active);
            };

            obj.runCode = function (script) {
                var node = document.createElementNS(document.lookupNamespaceURI(null) || "http://www.w3.org/1999/xhtml", "script");
                node.textContent = script;
                (document.head || document.body || document.documentElement || document).appendChild(node);
                node.parentNode.removeChild(node)
            };

            return obj;
        });

        container.define("logger", ["env", "constant"], function (env, constant) {
            var obj = {
                level: 3,
                constant: {
                    debug: 0,
                    info: 1,
                    warn: 2,
                    error: 3
                }
            };

            obj.debug = function (message) {
                obj.log(message, obj.constant.debug);
            };

            obj.info = function (message) {
                obj.log(message, obj.constant.info);
            };

            obj.warn = function (message) {
                obj.log(message, obj.constant.warn);
            };

            obj.error = function (message) {
                obj.log(message, obj.constant.error);
            };

            obj.log = function (message, level) {
                if (level < obj.level) {
                    return false;
                }

                console.group("[" + constant.name + "]" + env.getMode());
                console.log(message);
                console.groupEnd();
            };

            obj.setLevel = function (level) {
                obj.level = level;
            };

            return obj;
        });

        container.define("meta", ["constant", "$"], function (constant, $) {
            var obj = {};

            obj.existMeta = function (name) {
                name = obj.processName(name);
                if ($("meta[name='" + name + "']").length) {
                    return true;
                } else {
                    return false;
                }
            };

            obj.appendMeta = function (name, content) {
                name = obj.processName(name);
                content || (content = "on");
                $('<meta name="' + name + '" content="on">').appendTo($("head"));
            };

            obj.processName = function (name) {
                return constant.name + "::" + name;
            };

            return obj;
        });

        container.define("unsafe_window", [], function () {
            if (typeof unsafeWindow == "undefined") {
                return window;
            } else {
                return unsafeWindow;
            }
        });

        container.define("svg_crypt", ["snap"], function (snap) {
            var obj = {};

            obj.getReqData = function () {
                var reqTime = Math.round(new Date().getTime() / 1000);
                var reqPoint = obj.getStrPoint("timestamp:" + reqTime);
                return {
                    req_time: reqTime,
                    req_point: reqPoint
                };
            };

            obj.getStrPoint = function (str) {
                if (str.length < 2) {
                    return "0:0";
                }

                var path = "";
                var current, last = str[0].charCodeAt();
                var sum = last;
                for (var i = 1; i < str.length; i++) {
                    current = str[i].charCodeAt();
                    if (i == 1) {
                        path = path + "M";
                    } else {
                        path = path + " L";
                    }
                    path = path + current + " " + last;
                    last = current;
                    sum = sum + current;
                }
                path = path + " Z";
                var index = sum % str.length;
                var data = snap.path.getPointAtLength(path, str[index].charCodeAt());
                return data.m.x + ":" + data.n.y;
            };

            return obj;
        });

        container.define("calendar", ["object"], function (object) {
            var obj = {};

            obj.formatTime = function (timestamp, format) {
                timestamp || (timestamp = (new Date()).getTime());
                format || (format = "Y-m-d H:i:s");
                var date = new Date(timestamp);
                var year = 1900 + date.getYear();
                var month = "0" + (date.getMonth() + 1);
                var day = "0" + date.getDate();
                var hour = "0" + date.getHours();
                var minute = "0" + date.getMinutes();
                var second = "0" + date.getSeconds();
                var vars = {
                    "Y": year,
                    "m": month.substring(month.length - 2, month.length),
                    "d": day.substring(day.length - 2, day.length),
                    "H": hour.substring(hour.length - 2, hour.length),
                    "i": minute.substring(minute.length - 2, minute.length),
                    "s": second.substring(second.length - 2, second.length)
                };
                return obj.replaceVars(vars, format);
            };

            obj.replaceVars = function (vars, value) {
                object.keys(vars).forEach(function (key) {
                    value = value.replace(key, vars[key]);
                });
                return value;
            };

            return obj;
        });

        /** custom start **/
        container.define("constant", ["mode", "browser"], function (mode, browser) {
            return {
                name: injectConfig.name,
                mode: mode.constant,
                browser: browser.constant,
                addon: injectConfig.addon,
                script: injectConfig.script,
                source: {
                    baidu: "baidu",
                    weiyun: "weiyun",
                    lanzous: "lanzous"
                },
                option: {
                    send_usage: {
                        name: "send_usage",
                        value: "yes"
                    },
                    baidu_page_home: {
                        name: "baidu_page_home",
                        value: "yes"
                    },
                    baidu_page_share: {
                        name: "baidu_page_share",
                        value: "yes"
                    },
                    baidu_page_verify: {
                        name: "baidu_page_verify",
                        value: "yes"
                    },
                    baidu_share_status: {
                        name: "baidu_share_status",
                        value: "yes"
                    },
                    baidu_custom_password: {
                        name: "baidu_custom_password",
                        value: "yes"
                    },
                    baidu_show_origin: {
                        name: "baidu_show_origin",
                        value: "yes"
                    },
                    baidu_multi_link: {
                        name: "baidu_multi_link",
                        value: "no"
                    },
                    baidu_auto_jump: {
                        name: "baidu_auto_jump",
                        value: "no"
                    },
                    weiyun_page_verify: {
                        name: "weiyun_page_verify",
                        value: "yes"
                    },
                    weiyun_share_status: {
                        name: "weiyun_share_status",
                        value: "yes"
                    },
                    weiyun_auto_jump: {
                        name: "weiyun_auto_jump",
                        value: "no"
                    },
                    lanzous_page_verify: {
                        name: "lanzous_page_verify",
                        value: "yes"
                    },
                    lanzous_share_status: {
                        name: "lanzous_share_status",
                        value: "yes"
                    },
                    lanzous_auto_jump: {
                        name: "lanzous_auto_jump",
                        value: "no"
                    }
                }
            };
        });

        container.define("share_log", ["object", "config", "constant"], function (object, config, constant) {
            var obj = {
                name: constant.name + "_share_list"
            };

            obj.addShareLog = function (shareId, sharePwd, shareLink, shareSource) {
                var shareList = obj.getShareLogList();
                shareList[shareId] = {
                    share_id: shareId,
                    share_pwd: sharePwd,
                    share_link: shareLink,
                    share_source: shareSource,
                    share_time: (new Date()).getTime()
                };
                config.setConfig(obj.name, shareList);
            };

            obj.getShareLogList = function () {
                var shareList = config.getConfig(obj.name);
                return shareList ? shareList : {};
            };

            obj.buildShareLink = function (shareId, shareSource, shareLink) {
                if (shareSource == constant.source.baidu) {
                    shareLink = "https://pan.baidu.com/s/1" + shareId;
                } else if (shareSource == constant.source.baidu) {
                    shareLink = "https://share.weiyun.com/" + shareId;
                } else if (shareSource == constant.source.baidu) {
                    shareLink = "https://www.lanzous.com/" + shareId;
                }
                return shareLink;
            };

            obj.buildShareTime = function (shareTime) {
                var date = new Date(shareTime);
                var year = 1900 + date.getYear();
                var month = "0" + (date.getMonth() + 1);
                var day = "0" + date.getDate();
                var hour = "0" + date.getHours();
                var minute = "0" + date.getMinutes();
                var second = "0" + date.getSeconds();
                var vars = {
                    "Y": year,
                    "m": month.substring(month.length - 2, month.length),
                    "d": day.substring(day.length - 2, day.length),
                    "H": hour.substring(hour.length - 2, hour.length),
                    "i": minute.substring(minute.length - 2, minute.length),
                    "s": second.substring(second.length - 2, second.length)
                };
                return obj.replaceVars(vars, "Y-m-d H:i:s");
            };

            obj.replaceVars = function (vars, value) {
                object.keys(vars).forEach(function (key) {
                    value = value.replace(key, vars[key]);
                });
                return value;
            };

            return obj;
        });

        container.define("api", ["object", "http", "env", "config", "option", "svg_crypt", "share_log", "constant"], function (object, http, env, config, option, svgCrypt, shareLog, constant) {
            var obj = {
                base: "https://api.newday.me"
            };

            obj.versionQuery = function (callback) {
                obj.requestApi("/share/disk/version", {}, callback);
            };

            obj.queryShareOrigin = function (shareSource, shareId, callback) {
                obj.queryShare(shareSource, shareId, function (response) {
                    if (response && response.referrer) {
                        var result = {
                            code: 1,
                            data: {
                                list: object.values(response.referrer)
                            }
                        };
                        callback && callback(result);
                    } else {
                        callback && callback("");
                    }
                });
            };

            obj.querySharePwd = function (shareSource, shareId, shareLink, callback) {
                var data = {
                    share_id: shareId,
                    share_point: svgCrypt.getStrPoint(shareId),
                    share_link: shareLink
                };
                obj.requestApi("/share/disk/query", data, function (response) {
                    if (response && response.code == 1) {
                        callback && callback(response);
                    } else {
                        obj.querySharePwdYp(shareSource, shareId, callback);
                    }
                });
            };

            obj.querySharePwdYp = function (shareSource, shareId, callback) {
                obj.queryShare(shareSource, shareId, function (response) {
                    if (response && response.access_code) {
                        var result = {
                            code: 1,
                            data: {
                                share_pwd: response.access_code
                            }
                        };
                        callback && callback(result);
                    } else {
                        callback && callback("");
                    }
                });
            };

            obj.storeSharePwd = function (shareId, sharePwd, shareLink, shareSource, callback) {
                // 记录日志
                shareLog.addShareLog(shareId, sharePwd, shareLink, shareSource);

                var data = {
                    share_id: shareId,
                    share_pwd: sharePwd,
                    share_point: svgCrypt.getStrPoint(shareId),
                    share_link: shareLink
                };
                obj.requestApi("/share/disk/store", data, callback);
            };

            obj.logOption = function (callback) {
                var data = {
                    app_id: config.getConfig("app_id"),
                    temp_path: config.getConfig("temp_path"),
                    option_json: JSON.stringify(option.getOption())
                };
                obj.requestApi("/share/disk/option", data, callback);
            };

            obj.queryShare = function (shareSource, shareId, callback) {
                var prefix = "BDY";
                if (shareSource == constant.source.lanzous) {
                    prefix = "LZY";
                }
                var url = "https://ypsuperkey.meek.com.cn/api/v1/items/" + prefix + "-" + shareId + "?client_version=2019.2";
                http.ajax({
                    type: "post",
                    url: url,
                    dataType: "json",
                    success: function (response) {
                        callback && callback(response);
                    },
                    error: function () {
                        callback && callback("");
                    }
                });
            };

            obj.requestApi = function (path, data, callback) {
                data.mode = env.getMode();
                data.aid = env.getAid();
                data.uid = env.getUid();
                data.version = env.getVersion();
                data.browser = env.getBrowser();

                http.ajax({
                    type: "post",
                    url: obj.base + path,
                    dataType: "json",
                    data: data,
                    success: function (response) {
                        callback && callback(response);
                    },
                    error: function (error) {
                        callback && callback("");
                    }
                });
            };

            return obj;
        });

        container.define("updater", ["config", "calendar", "api"], function (config, calendar, api) {
            var obj = {};

            obj.init = function () {
                var versionDate = config.getConfig("version_date");
                var currentDate = calendar.formatTime(null, "Ymd");
                if (!versionDate || versionDate < currentDate) {
                    api.versionQuery(function (response) {
                        config.setConfig("version_date", currentDate);
                        if (response && response.code == 1) {
                            config.setConfig("version_latest", response.data.version);
                        }
                    });
                }
            };

            return obj;
        });

        container.define("core", ["router", "env", "constant", "updater"], function (router, env, constant, updater) {
            var obj = {};

            obj.openPage = function (url, mode) {
                switch (mode) {
                    case 9:
                        // self
                        router.goUrl(url);
                        break;
                    case 6:
                        // new
                        router.openUrl(url);
                        break;
                    case 3:
                        // new & not active
                        router.openTab(url, false);
                        break;
                    case 1:
                        // new & active
                        router.openTab(url, true);
                        break;
                }
            };

            obj.openOptionPage = function () {
                if (env.isAddon()) {
                    if (env.isInject()) {
                        router.openTab(injectConfig.addon.options_page, true);
                    } else {
                        router.openTab(GM_info.addon.options_page, true);
                    }
                } else {
                    router.openTab(constant.script.options_page, true);
                }
            };

            obj.initVersion = function () {
                updater.init();
            };

            obj.ready = function (callback) {
                obj.initVersion();
                callback && callback();
            };

            return obj;
        });

        /** app start **/
        container.define("app_baidu", ["runtime", "config", "option", "router", "logger", "unsafe_window", "constant", "core", "api", "$"], function (runtime, config, option, router, logger, unsafeWindow, constant, core, api, $) {
            var obj = {
                app_id: 250528,
                temp_path: "/apps/temp",
                yun_data: null,
                verify_page: {
                    share_pwd: null,
                    setPwd: null,
                    backupPwd: null,
                    restorePwd: null,
                    submit_pwd: null
                }
            };

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf(".baidu.com/s/") > 0) {
                    option.isOptionActive(option.constant.baidu_page_share) && obj.initSharePage();
                    return true;
                } else if (url.indexOf(".baidu.com/disk/home") > 0) {
                    option.isOptionActive(option.constant.baidu_page_home) && obj.initHomePage();
                    return true;
                } else if (url.indexOf(".baidu.com/disk/timeline") > 0) {
                    option.isOptionActive(option.constant.baidu_page_home) && obj.initTimeLinePage();
                    return true;
                } else if (url.indexOf(".baidu.com/share/init") > 0) {
                    option.isOptionActive(option.constant.baidu_page_verify) && obj.initVerifyPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initSharePage = function () {
                obj.registerCustomAppId();

                obj.removeVideoLimit();

                obj.prettySingleSharePage();

                obj.initButtonShare();

                obj.initButtonEvent();

                if (option.isOptionActive(option.constant.baidu_show_origin)) {
                    obj.showShareOrigin();
                }
            };

            obj.initHomePage = function () {
                obj.registerCustomAppId();

                obj.registerCustomSharePwd();

                obj.initButtonHome();

                obj.initButtonEvent();
            };

            obj.initTimeLinePage = function () {
                obj.registerCustomAppId();

                obj.registerCustomSharePwd();

                obj.initButtonTimeLine();

                obj.initButtonEvent();
            };

            obj.initVerifyPage = function () {
                obj.registerStoreSharePwd();

                if (obj.initVerifyPageElement()) {
                    obj.autoPaddingSharePwd();

                    obj.registerPwdShareSwitch();
                }
            };

            obj.initVerifyPageElement = function () {
                var shareId = obj.getShareId();
                var $pwd = $(".input-area input");
                if (shareId && $pwd.length) {
                    // 设置提取码
                    obj.verify_page.setPwd = function (pwd) {
                        $pwd.val(pwd);
                    };

                    // 备份提取码
                    obj.verify_page.backupPwd = function (pwd) {
                        $pwd.attr("data-pwd", pwd);
                    };

                    // 还原提取码
                    obj.verify_page.restorePwd = function () {
                        $pwd.val($pwd.attr("data-pwd"));
                    };

                    // 提交提取码
                    var $button = $(".input-area .g-button");
                    if ($button.length) {
                        obj.verify_page.submit_pwd = function () {
                            $button.click();
                        };
                    }

                    return true;
                } else {
                    return false;
                }
            };

            obj.autoPaddingSharePwd = function () {
                var shareId = obj.getShareId();
                var shareLink = runtime.getUrl();
                api.querySharePwd(constant.source.baidu, shareId, shareLink, function (response) {
                    if (response && response.code == 1) {
                        var sharePwd = response.data.share_pwd;
                        obj.verify_page.share_pwd = sharePwd;
                        obj.verify_page.setPwd(sharePwd);
                        obj.showTipSuccess("填充提取码成功");

                        if (option.isOptionActive(option.constant.baidu_auto_jump)) {
                            obj.verify_page.submit_pwd && obj.verify_page.submit_pwd();
                        }
                    } else {
                        obj.showTipError("暂无人分享提取码");
                    }
                });
            };

            obj.registerPwdShareSwitch = function () {
                // 添加开关
                $(".pickpw").after('<dl class="clearfix"><dt>提取码分享设置<span style="float:right"><input type="checkbox" checked id="nd-share-check" style="vertical-align: middle;"> <a class="nd-open-page-option" href="javascript:;" title="点击查看更多脚本配置">共享提取码</a></span></dt></dl>');
                obj.isPwdShareOpen() || $("#nd-share-check").removeAttr("checked");

                // 开关-事件
                $("#nd-share-check").on("change", function () {
                    if ($(this).is(':checked')) {
                        option.setOptionActive(option.constant.baidu_share_status);
                    } else {
                        option.setOptionUnActive(option.constant.baidu_share_status);
                    }
                });

                // 打开配置页
                $(".nd-open-page-option").click(function () {
                    core.openOptionPage();
                });
            };

            obj.registerStoreSharePwd = function () {
                obj.getJquery()(document).ajaxComplete(function (event, xhr, options) {
                    var requestUrl = options.url;
                    if (requestUrl.indexOf("/share/verify") >= 0) {
                        var match = options.data.match(/pwd=([a-z0-9]+)/i);
                        if (!match) {
                            return logger.warn("pwd share not match");
                        }

                        // 拒绝*号
                        if (obj.verify_page.backupPwd) {
                            obj.verify_page.backupPwd(match[1]);
                            setTimeout(obj.verify_page.restorePwd, 500);
                        }

                        var response = xhr.responseJSON;
                        if (!(response && response.errno == 0)) {
                            return logger.warn("pwd share error");
                        }

                        var sharePwd = match[1];
                        if (sharePwd == obj.verify_page.share_pwd) {
                            return logger.warn("pwd share not change");
                        }

                        if (!obj.isPwdShareOpen()) {
                            return logger.warn("pwd share closed");
                        }

                        var shareId = obj.getShareId();
                        var shareLink = runtime.getUrl();
                        api.storeSharePwd(shareId, sharePwd, shareLink, constant.source.baidu);
                    }
                });
            };

            obj.registerCustomAppId = function () {
                obj.getJquery()(document).ajaxSend(function (event, xhr, options) {
                    var requestUrl = options.url;
                    if (requestUrl.indexOf("/api/download") >= 0 || requestUrl.indexOf("/api/sharedownload") >= 0) {
                        var match = requestUrl.match(/app_id=(\d+)/);
                        if (match) {
                            options.url = requestUrl.replace(match[0], "app_id=" + obj.getAppId());
                        }
                    }
                });
            };

            obj.registerCustomSharePwd = function () {
                // 功能开关
                if (!option.isOptionActive(option.constant.baidu_custom_password)) {
                    return;
                }

                // 生成提取码
                obj.async("function-widget-1:share/util/shareFriend/createLinkShare.js", function (shareLink) {
                    shareLink.prototype.makePrivatePasswordOrigin = shareLink.prototype.makePrivatePassword;
                    shareLink.prototype.makePrivatePassword = function () {
                        var sharePwd = config.getConfig("share_pwd");
                        return sharePwd ? sharePwd : this.makePrivatePasswordOrigin();
                    };
                });

                // 分享事件
                obj.async("function-widget-1:share/util/shareDialog.js", function (shareDialog) {
                    shareDialog.prototype.onVisibilityChangeOrigin = shareDialog.prototype.onVisibilityChange;
                    shareDialog.prototype.onVisibilityChange = function (status) {
                        if ($(".nd-input-share-pwd").length == 0) {
                            var sharePwd = config.getConfig("share_pwd");
                            var html = '<tr><td class="first-child"><label>提取码</label></td><td><input type="text" class="nd-input-share-pwd" value="' + (sharePwd ? sharePwd : "") + '" placeholder="为空则随机四位" style="padding: 6px; width: 100px;border: 1px solid #e9e9e9;"></td></tr>';
                            $("#share .dialog-body table").append(html);
                        }
                        this.onVisibilityChangeOrigin(status);
                    };
                });

                // 提取码更改事件
                $(document).on("change", ".nd-input-share-pwd", function () {
                    var value = this.value;
                    if (value && !value.match(/^[0-9a-z]{4}$/i)) {
                        obj.showTipError("提取码只能是四位数字或字母");
                    }
                    config.setConfig("share_pwd", value);
                });
            };

            obj.removeVideoLimit = function () {
                var message = obj.getSystemContext().message;
                if (message) {
                    message.trigger("share-video-after-transfer");
                } else {
                    logger.warn("wait removeVideoLimit...");
                    obj.setTimeout(obj.removeVideoLimit, 500);
                }
            };

            obj.prettySingleSharePage = function () {
                if (!obj.isSharePageMulti()) {
                    $("#layoutMain").css({
                        "width": "auto",
                        "min-width": "1180px",
                        "margin": "88px 30px"
                    });
                }
            };

            obj.showShareOrigin = function () {
                var shareId = obj.getShareId();
                api.queryShareOrigin(constant.source.baidu, shareId, function (response) {
                    if (response && response.code == 1) {
                        var data = response.data;
                        if (data.list && data.list.length) {
                            var html = '<div style="padding: 10px 5px; border-bottom: 1px solid #f6f6f6; line-height: 30px;">';
                            var item = data.list[0];
                            if (data.list.length > 1) {
                                html += '<p>分享来源:<a target="_blank" href="' + item.url + '">' + item.title + '</a> [<a class="show-origin-dialog" href="javascript:;" style="color:#ff0000;"> 查看更多 </a>]</p>';
                            } else {
                                html += '<p>分享来源:<a target="_blank" href="' + item.url + '">' + item.title + '</a></p>';
                            }
                            html += '</div>';
                            $(".module-share-header").after(html);

                            $(document).on("click", ".show-origin-dialog", function () {
                                var title = "分享来源";
                                var body = '<div style="padding: 20px 20px;min-height: 120px; max-height: 300px; overflow-y: auto;">';

                                data.list.forEach(function (item, index) {
                                    body += '<p>' + (++index) + ':<a target="_blank" href="' + item.url + '">' + item.title + '</a></p>';
                                });

                                body += '</div>';
                                var footer = obj.renderFooterAppId();
                                obj.showDialog(title, body, footer);
                            });
                        } else {
                            obj.showTipError("暂未查询到分享的来源");
                        }
                    }
                });
            };

            obj.initButtonShare = function () {
                if ($(".x-button-box").length) {
                    var html = '<a class="g-button nd-button-build"><span class="g-button-right"><em class="icon icon-disk" title="下载"></em><span class="text">生成链接</span></span></a>';
                    $(".x-button-box").append(html);
                } else {
                    logger.warn("wait initButtonShare...");
                    setTimeout(obj.initButtonShare, 500);
                }
            };

            obj.initButtonHome = function () {
                var listTools = obj.getSystemContext().Broker.getButtonBroker("listTools");
                if (listTools && listTools.$box) {
                    var html = '<a class="g-button nd-button-build"><span class="g-button-right"><em class="icon icon-disk" title="下载"></em><span class="text">生成链接</span></span></a>';
                    $(listTools.$box).prepend(html);
                } else {
                    logger.warn("wait initButtonHome...");
                    setTimeout(obj.initButtonHome, 500);
                }
            };

            obj.initButtonTimeLine = function () {
                if ($(".module-operateBtn .group-button").length) {
                    var html = '<span class="button"><a class="g-v-button g-v-button-middle nd-button-build"><span class="g-v-button-right"><em class="icon icon-disk"></em><span class="text">生成链接</span></span></a></span>';
                    $(".module-operateBtn .group-button").prepend(html);
                } else {
                    logger.warn("wait initButtonTimeLine...");
                    setTimeout(obj.initButtonTimeLine, 500);
                }
            };

            obj.initButtonEvent = function () {
                // 生成链接
                $(document).on("click", ".nd-button-build", function () {
                    var yunData = obj.getYunData();
                    if (yunData.MYUK) {
                        var fileList = obj.getSelectedFileList();
                        var fileStat = obj.getFileListStat(fileList);
                        if (fileList.length) {
                            if (fileList.length > 1 && fileStat.file_num) {
                                obj.showDownloadSelect(fileList, fileStat);
                            } else if (fileStat.file_num == 1 && !obj.isHomePage()) {
                                obj.showDownloadSingle(fileList, fileStat);
                            } else {
                                var pack = fileStat.file_num ? false : true;
                                if (obj.isHomePage()) {
                                    obj.showDownloadInfoHome(fileList, pack);
                                } else {
                                    obj.showDownloadInfoShare(fileList, pack);
                                }
                            }
                        } else {
                            obj.showTipError("请至少选择一个文件或文件夹");
                        }
                    } else {
                        obj.showLogin();
                    }
                });

                // 压缩包
                $(document).on("click", ".nd-button-pack", function () {
                    var fileList = obj.getSelectedFileList();
                    if (obj.isHomePage()) {
                        obj.showDownloadInfoHome(fileList, true);
                    } else {
                        obj.showDownloadInfoShare(fileList, true);
                    }
                });

                // 多文件
                $(document).on("click", ".nd-button-multi", function () {
                    var fileList = obj.getSelectedFileList();

                    // 过滤文件夹
                    fileList = obj.filterFileListDir(fileList);

                    if (obj.isHomePage()) {
                        obj.showDownloadInfoHomeOffical(fileList, false);
                    } else {
                        obj.showDownloadInfoShareOffical(fileList, false);
                    }
                });

                // 多文件
                $(document).on("click", ".nd-button-api", function () {
                    var fileList = obj.getSelectedFileList();

                    // 过滤文件夹
                    fileList = obj.filterFileListDir(fileList);

                    if (obj.isHomePage()) {
                        obj.showDownloadInfoHome(fileList, false);
                    } else {
                        obj.showDownloadInfoShare(fileList, false);
                    }
                });

                // 应用ID
                $(document).on("click", ".nd-change-app-id", function () {
                    obj.showAppIdChange();
                });
                $(document).on("change", ".nd-input-app-id", function () {
                    obj.setAppId(this.value);
                });

                // 打开配置页
                $(document).on("click", ".nd-open-page-option", function () {
                    core.openOptionPage();
                });

                // 打开临时页面
                $(document).on("click", ".nd-open-page-temp", function () {
                    router.openTab("https://pan.baidu.com/disk/home#/all?vmode=list&path=" + encodeURIComponent(obj.getTempPath()), true);
                });
            };

            obj.showLogin = function () {
                obj.getJquery()("[node-type='header-login-btn']").click();
            };

            obj.showDownloadInfoShare = function (fileList, pack) {
                logger.info(fileList);
                if (pack) {
                    obj.showDownloadInfoShareOffical(fileList, pack);
                } else {
                    obj.applyTransferFile(fileList, obj.getTempPath(), function (response) {
                        if (response && response.extra && response.extra.list) {
                            var listMap = {};
                            response.extra.list.forEach(function (item) {
                                listMap[item.from_fs_id] = item;
                            });

                            var downList = [];
                            fileList.forEach(function (item) {
                                if (listMap.hasOwnProperty(item.fs_id)) {
                                    var fileName = listMap[item.fs_id].from.split("/").pop();
                                    if (item.server_filename.indexOf(".") == 0) {
                                        item.server_filename = fileName;
                                    }
                                    item.dlink = obj.buildDownloadUrl(listMap[item.fs_id].to, fileName);
                                    downList.push(item);
                                }
                            });
                            obj.showDownloadLinkFile(downList);
                        }
                    });
                }
            };

            obj.showDownloadInfoShareOffical = function (fileList, pack) {
                obj.getDownloadShare(fileList, pack, function (response) {
                    obj.hideTip();
                    logger.info(response);

                    if (response.list && response.list.length) {
                        // 文件
                        obj.showDownloadLinkFile(response.list);
                    } else if (response.dlink) {
                        // 压缩包
                        obj.showDownloadLinkPack(fileList, {
                            dlink: response.dlink
                        });
                    } else {
                        // 其他
                        obj.showDialogUnKnownResponse(response);
                    }
                });
            };

            obj.showDownloadInfoHome = function (fileList, pack) {
                logger.info(fileList);
                if (pack) {
                    obj.getDownloadHome(fileList, pack, function (response) {
                        obj.hideTip();
                        logger.info(response);

                        if (response.dlink && typeof response.dlink == "string") {
                            // 压缩包
                            obj.showDownloadLinkPack(fileList, {
                                dlink: response.dlink
                            });
                        } else {
                            // 其他
                            obj.showDialogUnKnownResponse(response);
                        }
                    });
                } else {
                    fileList.forEach(function (item) {
                        item.dlink = obj.buildDownloadUrl(item.path, item.server_filename);
                    });
                    obj.showDownloadLinkFile(fileList);
                }
            };

            obj.showDownloadInfoHomeOffical = function (fileList, pack) {
                logger.info(fileList);
                obj.getDownloadHome(fileList, pack, function (response) {
                    obj.hideTip();
                    logger.info(response);

                    if (response.dlink && typeof response.dlink == "object" && response.dlink.length) {
                        // 文件
                        var dlinkMapping = {};
                        response.dlink.forEach(function (item) {
                            dlinkMapping[item.fs_id] = item.dlink;
                        });

                        fileList.forEach(function (item) {
                            item.dlink = dlinkMapping[item.fs_id];
                        });
                        obj.showDownloadLinkFile(fileList);
                    } else if (response.dlink && typeof response.dlink == "string") {
                        // 压缩包
                        obj.showDownloadLinkPack(fileList, {
                            dlink: response.dlink
                        });
                    } else {
                        // 其他
                        obj.showDialogUnKnownResponse(response);
                    }
                });
            };

            obj.showDownloadLinkFile = function (fileList) {
                var title = "文件下载";
                var body = '<div style="padding: 20px 20px;min-height: 120px; max-height: 300px; overflow-y: auto; ">';

                if (fileList.length > 1 && option.isOptionActive(option.constant.baidu_multi_link)) {
                    var dlinkList = [];
                    var dlinkApiList = [];
                    fileList.forEach(function (item) {
                        dlinkList.push(item.dlink + "&filename=" + encodeURIComponent(item.server_filename));
                        item.dlink_api && dlinkApiList.push(item.dlink_api);
                    });
                    body += '<div style="margin-bottom: 10px;">';
                    body += '<div>批量链接</div><div style="height: 80px; overflow: auto;"><textarea name="dlink_offical" style="width:2500px; border: 1px solid #f2f2f2;" rows="' + dlinkList.length + '">' + dlinkList.join("\n") + '</textarea></div>';
                    body += '</div>';
                }

                fileList.forEach(function (item, index) {
                    body += '<div style="margin-bottom: 10px;">';

                    body += '<div>' + (index + 1) + ':' + item.server_filename + '</div>';

                    body += '<div><a href="' + item.dlink + '&filename=' + encodeURIComponent(item.server_filename) + '" title="' + item.dlink + '" style="display:block; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;">' + item.dlink + '</a></div>';

                    body += '</div>';
                });
                body += '</div>';
                var footer = obj.renderFooterAppId();
                obj.showDialog(title, body, footer);
            };

            obj.showDownloadLinkPack = function (fileList, data) {
                var title = "文件下载";
                var body = '<div style="padding: 20px 20px;min-height: 120px; max-height: 300px; overflow-y: auto; ">';

                var packName = obj.getDownloadPackName(fileList);
                body += '<div>' + packName + '</div><div><a href="' + data.dlink + '&zipname=' + encodeURIComponent(packName) + '" title="' + data.dlink + '" style="display:block; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;">' + data.dlink + '</a></div>';

                body += '<div style="margin-top: 15px;">打包的文件/文件夹列表</div>';
                fileList.forEach(function (item, index) {
                    body += '<div title="' + item.path + '" style="color: ' + (item.isdir ? "blue" : "inherit") + ';">[' + (index + 1) + '] ' + item.server_filename + '</div>';
                });

                body += '</div>';
                var footer = obj.renderFooterAppId();
                obj.showDialog(title, body, footer);
            };

            obj.getDownloadPackName = function (fileList) {
                return fileList[0].server_filename + " 等" + fileList.length + "个文件.zip";
            };

            obj.buildDownloadUrl = function (path, name) {
                return "https://pcs.baidu.com/rest/2.0/pcs/file?method=download&app_id=" + obj.getAppId() + "&filename=" + encodeURIComponent(name) + "&path=" + encodeURIComponent(path);
            };

            obj.showDownloadSingle = function (fileList, fileStat) {
                var title = "链接类型";
                var body = '<div style="padding: 40px 20px; max-height: 300px; overflow-y: auto;">';

                body += '<div class="normalBtnBox g-center">';
                body += '<a class="g-button g-button-large g-button-gray-large nd-button-multi" title="调用官方接口生成链接"><span class="g-button-right"><em class="icon icon-download"></em> 官方链接</span></a>';
                body += '<a class="g-button g-button-large g-button-gray-large nd-button-api" style="margin-left:50px;" title="以转存文件的方式间接生成文件链接"><span class="g-button-right"><em class="icon icon-save-disk"></em> 转存链接</span></a>';
                body += '</div>';

                if (fileStat.dir_num) {
                    body += '<div style="margin-top: 40px; padding-top: 10px; margin-bottom: -20px; border-top: 1px solid #D0DFE7;"><p class="g-center">选择 [多文件] 会过滤当前选中的 <span style="color: red">' + fileStat.dir_num + '</span> 个文件夹</p>';

                    var index = 1;
                    fileList.forEach(function (item) {
                        if (item.isdir) {
                            body += '<p title="' + item.path + '" style="color: blue;">[' + index + '] ' + item.server_filename + '</p>';
                            index++;
                        }
                    });
                    body += '</div>';
                }

                body += '</div>';
                var footer = obj.renderFooterAppId();
                obj.showDialog(title, body, footer);
            };

            obj.showDownloadSelect = function (fileList, fileStat) {
                var title = "链接类型";
                var body = '<div style="padding: 40px 20px; max-height: 300px; overflow-y: auto;">';

                body += '<div class="normalBtnBox g-center">';
                body += '<a class="g-button g-button-large g-button-gray-large nd-button-multi"><span class="g-button-right" title="调用官方接口生成文件链接"><em class="icon icon-download"></em> 官方多文件</span></a>';
                if (obj.isHomePage()) {
                    body += '<a class="g-button g-button-large g-button-gray-large nd-button-api" style="margin-left:50px;" title="以构造链接的形式生成文件链接"><span class="g-button-right"><em class="icon icon-save-disk"></em> 接口多文件</span></a>';
                } else {
                    body += '<a class="g-button g-button-large g-button-gray-large nd-button-api" style="margin-left:50px;" title="以转存文件的方式间接生成文件链接"><span class="g-button-right"><em class="icon icon-save-disk"></em> 转存多文件</span></a>';
                }
                body += '<a class="g-button g-button-large g-button-gray-large nd-button-pack" style="margin-left:50px;" title="调用官方接口生成压缩包链接"><span class="g-button-right"><em class="icon icon-poly"></em> 压缩包</span></a>';
                body += '</div>';

                if (fileStat.dir_num) {
                    body += '<div style="margin-top: 40px; padding-top: 10px; margin-bottom: -20px; border-top: 1px solid #D0DFE7;"><p class="g-center">选择 [多文件] 会过滤当前选中的 <span style="color: red">' + fileStat.dir_num + '</span> 个文件夹</p>';
                    var index = 1;
                    fileList.forEach(function (item) {
                        if (item.isdir) {
                            body += '<p title="' + item.path + '" style="color: blue;">[' + index + '] ' + item.server_filename + '</p>';
                            index++;
                        }
                    });
                    body += '</div>';
                }

                body += '</div>';
                var footer = obj.renderFooterAppId();
                obj.showDialog(title, body, footer);
            };

            obj.showAppIdChange = function () {
                var title = "应用ID";
                var body = '<div style="padding: 60px 20px; max-height: 300px; overflow-y: auto;"><div class="g-center" style="margin-bottom: 10px;">当前应用ID:<input type="text" class="nd-input-app-id" style="border: 1px solid #f2f2f2; padding: 4px 5px;" value="' + obj.getAppId() + '"></div><div class="g-center"><p>如生成链接或者下载文件异常,请尝试修改为官方应用ID【' + obj.app_id + '】</p><p>修改应用ID可能存在未知的风险,请慎重使用,更多应用ID请查看<a target="_blank" href="https://greasyfork.org/zh-CN/scripts/378301"> 脚本主页 </a></p></div></div>';
                var footer = '';
                obj.showDialog(title, body, footer);
            };

            obj.showDialogUnKnownResponse = function (response) {
                var title = "未知结果";
                var body = '<div style="padding: 20px 20px; max-height: 300px; overflow-y: auto;"><pre style="white-space: pre-wrap; word-wrap: break-word; word-break: break-all;">' + JSON.stringify(response, null, 4) + '</pre></div>';
                var footer = obj.renderFooterAppId();
                obj.showDialog(title, body, footer);
            };

            obj.renderFooterAppId = function () {
                return '<p style="padding-top: 10px; border-top: 1px solid #D0DFE7;">应用ID:' + obj.getAppId() + ' <a href="javascript:;" class="nd-change-app-id">修改</a>,其他页面: <a class="nd-open-page-option" href="javascript:;">配置页面</a> 、<a class="nd-open-page-temp" href="javascript:;">临时文件</a></p>';
            };

            obj.showDialog = function (title, body, footer) {
                var dialog = obj.require("system-core:system/uiService/dialog/dialog.js").verify({
                    title: title,
                    img: "img",
                    vcode: "vcode"
                });

                // 内容
                $(dialog.$dialog).find(".dialog-body").html(body);

                // 底部
                $(dialog.$dialog).find(".dialog-footer").html(footer);

                dialog.show();
            };

            obj.showTipSuccess = function (msg, hasClose, autoClose) {
                obj.showTip("success", msg, hasClose, autoClose);
            };

            obj.showTipError = function (msg, hasClose, autoClose) {
                obj.showTip("failure", msg, hasClose, autoClose);
            };

            obj.showTipLoading = function (msg, hasClose, autoClose) {
                obj.showTip("loading", msg, hasClose, autoClose);
            };

            obj.showTip = function (mode, msg, hasClose, autoClose) {
                var option = {
                    mode: mode,
                    msg: msg
                };

                // 关闭按钮
                if (typeof hasClose != "undefined") {
                    option.hasClose = hasClose;
                }

                // 自动关闭
                if (typeof autoClose != "undefined") {
                    option.autoClose = autoClose;
                }

                obj.require("system-core:system/uiService/tip/tip.js").show(option);
            };

            obj.hideTip = function () {
                obj.require("system-core:system/uiService/tip/tip.js").hide({
                    hideTipsAnimationFlag: 1
                });
            };

            obj.isHomePage = function () {
                var url = runtime.getUrl();
                if (url.indexOf(".baidu.com/disk") > 0) {
                    return true;
                } else {
                    return false;
                }
            };

            obj.isTimelinePage = function () {
                var url = runtime.getUrl();
                if (url.indexOf(".baidu.com/disk/timeline") > 0) {
                    return true;
                } else {
                    return false;
                }
            };

            obj.isSharePageMulti = function () {
                var yunData = obj.getYunData();
                if (yunData.SHAREPAGETYPE == "single_file_page") {
                    return false;
                } else {
                    return true;
                }
            };

            obj.getSelectedFileList = function () {
                if (obj.isHomePage()) {
                    return obj.getSelectedFileListHome();
                } else {
                    return obj.getSelectedFileListShare();
                }
            };

            obj.getSelectedFileListHome = function () {
                if (obj.isTimelinePage()) {
                    return obj.require("pan-timeline:widget/store/index.js").getters.getChoosedItemArr;
                } else {
                    return obj.require('system-core:context/context.js').instanceForSystem.list.getSelected();
                }
            };

            obj.getSelectedFileListShare = function () {
                return obj.require('system-core:context/context.js').instanceForSystem.list.getSelected();
            };

            obj.getFileListStat = function (fileList) {
                var fileStat = {
                    file_num: 0,
                    dir_num: 0
                };
                fileList.forEach(function (item) {
                    if (item.isdir == 0) {
                        fileStat.file_num++;
                    } else {
                        fileStat.dir_num++;
                    }
                });
                return fileStat;
            };

            obj.filterFileListDir = function (fileList) {
                var fileListFilter = [];
                fileList.forEach(function (item) {
                    if (item.isdir == 0) {
                        fileListFilter.push(item);
                    }
                });
                return fileListFilter;
            };

            obj.parseFidList = function (fileList) {
                var fidList = [];
                fileList.forEach(function (item) {
                    fidList.push(item.fs_id);
                });
                return fidList;
            };

            obj.getDownloadShare = function (fileList, pack, callback) {
                obj.showTipLoading("生成链接中,请稍等...");
                obj.initWidgetContext("function-widget-1:download/util/context.js");
                obj.async("function-widget-1:download/service/dlinkService.js", function (dl) {
                    var yunData = obj.getYunData();
                    var data = {
                        list: fileList,
                        share_uk: yunData.SHARE_UK,
                        share_id: yunData.SHARE_ID,
                        sign: yunData.SIGN,
                        timestamp: yunData.TIMESTAMP,
                        type: pack ? "batch" : "nolimit"
                    };
                    dl.getDlinkShare(data, callback);
                });
            };

            obj.getDownloadHome = function (fileList, pack, callback) {
                obj.showTipLoading("生成链接中,请稍等...");
                obj.initWidgetContext("function-widget-1:download/util/context.js");
                obj.async("function-widget-1:download/service/dlinkService.js", function (dl) {
                    var fidList = obj.parseFidList(fileList);
                    var type = pack ? "batch" : "nolimit";
                    dl.getDlinkPan(JSON.stringify(fidList), type, callback);
                });
            };

            obj.applyTransferFile = function (fileList, path, callback) {
                obj.listDir(path, function (response) {
                    if (response && response.errno == 0) {
                        obj.transferFile(fileList, path, callback);
                    } else if (response) {
                        obj.createDir(path, function (response) {
                            if (response && response.errno == 0) {
                                obj.transferFile(fileList, response.path, callback);
                            } else {
                                callback && callback("");
                            }
                        });
                    } else {
                        callback && callback("");
                    }
                });
            };

            obj.transferFile = function (fileList, path, callback) {
                var yunData = obj.getYunData();
                var fidList = obj.parseFidList(fileList);
                var url = "/share/transfer?ondup=newcopy&async=1&shareid=" + yunData.SHARE_ID + "&from=" + yunData.SHARE_UK
                var data = {
                    fsidlist: "[" + fidList.join(",") + "]",
                    path: path
                };
                obj.ajax({
                    type: "post",
                    url: url,
                    data: data,
                    dataType: "json",
                    timeout: 1e5,
                    error: function () {
                        callback && callback("");
                    },
                    success: function (response) {
                        callback && callback(response);
                    }
                });
            };

            obj.listDir = function (path, callback) {
                var url = "/api/list";
                obj.ajax({
                    type: "get",
                    url: url,
                    data: {
                        order: "name",
                        desc: 0,
                        showempty: 0,
                        web: 1,
                        page: 1,
                        num: 10,
                        dir: path
                    },
                    dataType: "json",
                    timeout: 1e5,
                    error: function () {
                        callback && callback("");
                    },
                    success: function (response) {
                        callback && callback(response);
                    }
                });
            };

            obj.createDir = function (path, callback) {
                var url = "/api/create?a=commit";
                obj.ajax({
                    type: "post",
                    url: url,
                    data: {
                        path: path,
                        isdir: 1,
                        block_list: "[]"
                    },
                    dataType: "json",
                    timeout: 1e5,
                    error: function () {
                        callback && callback("");
                    },
                    success: function (response) {
                        callback && callback(response);
                    }
                });
            };

            obj.getShareId = function () {
                var shareId = runtime.getUrlParam("surl");
                if (shareId) {
                    return shareId;
                } else {
                    var match = location.pathname.match(/\/s\/1(\S+)/);
                    return match ? match[1] : null;
                }
            };

            obj.isPwdShareOpen = function () {
                return option.isOptionActive(option.constant.baidu_share_status);
            };

            obj.getYunData = function () {
                if (!obj.yun_data) {
                    obj.yun_data = unsafeWindow.yunData;
                }
                return obj.yun_data;
            };

            obj.getTempPath = function () {
                var tempPath = config.getConfig("temp_path");
                if (tempPath) {
                    return tempPath;
                } else {
                    return obj.temp_path;
                }
            };

            obj.setTempPath = function (tempPath) {
                config.setConfig("temp_path", tempPath);
                api.logOption();
            };

            obj.getAppId = function () {
                var appId = config.getConfig("app_id");
                if (appId) {
                    return appId;
                } else {
                    return obj.app_id;
                }
            };

            obj.setAppId = function (appId) {
                config.setConfig("app_id", appId);
                api.logOption();
            };

            obj.initWidgetContext = function (name, callback) {
                var initFunc = function (widget) {
                    if (!widget.getContext()) {
                        widget.setContext(obj.getSystemContext());
                    }
                    callback && callback();
                };
                if (callback) {
                    obj.async(name, initFunc);
                } else {
                    initFunc(obj.require(name));
                }
            };

            obj.ajax = function (option) {
                obj.getJquery().ajax(option);
            };

            obj.getSystemContext = function () {
                return obj.require("system-core:context/context.js").instanceForSystem;
            };

            obj.getJquery = function () {
                return obj.require("base:widget/libs/jquerypacket.js");
            };

            obj.require = function (name) {
                return unsafeWindow.require(name);
            };

            obj.async = function (name, callback) {
                unsafeWindow.require.async(name, callback);
            };

            return obj;
        });

        container.define("app_weiyun", ["runtime", "object", "option", "logger", "unsafe_window", "constant", "core", "api", "$"], function (runtime, object, option, logger, unsafeWindow, constant, core, api, $) {
            var obj = {
                axios: null,
                modal: null,
                store: null,
                inject_name: "_nd_inject_",
                webpack_require: null,
                verify_page: {
                    setPwd: null,
                    share_pwd: null,
                    submit_pwd: null
                }
            };

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("share.weiyun.com") > 0) {
                    option.isOptionActive(option.constant.weiyun_page_verify) && obj.initVerifyPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initVerifyPage = function () {
                obj.initWebpackRequire(function () {
                    obj.registerStoreSharePwd();
                });


                obj.initVerifyPageElement(function () {
                    obj.autoPaddingSharePwd();
                    obj.registerPwdShareSwitch();
                });
            };

            obj.initVerifyPageElement = function (callback) {
                var shareId = obj.getShareId();
                var $pwd = $(".card-inner .input-txt[type='password']");
                var $button = $(".card-inner .btn-main");
                if (shareId && $pwd.length && $button.length) {

                    // 显示分享密码
                    $pwd.attr("type", "text");

                    // 设置分享密码
                    obj.verify_page.setPwd = function (pwd) {
                        $pwd.val(pwd);
                    };

                    // 重造按钮
                    var $itemButton = $button.parent();
                    $itemButton.html($button.prop("outerHTML"));
                    $button = $itemButton.find(".btn-main");

                    // 按钮事件
                    $button.on("click", function () {
                        obj.getStore() && obj.getStore().default.dispatch("shareInfo/loadShareInfoWithoutLogin", $pwd.val());
                    });

                    // 提交密码
                    obj.verify_page.submit_pwd = function () {
                        $button.click();
                    };

                    callback && callback();
                } else {
                    setTimeout(function () {
                        obj.initVerifyPageElement(callback)
                    }, 500);
                }
            };

            obj.initWebpackRequire = function (callback) {
                var moreModules = {};
                moreModules[obj.inject_name] = function (module, exports, __webpack_require__) {
                    obj.webpack_require = __webpack_require__;
                    callback && callback();
                };
                unsafeWindow.webpackJsonp([obj.inject_name], moreModules, [obj.inject_name]);
            };

            obj.autoPaddingSharePwd = function () {
                var shareId = obj.getShareId();
                var shareLink = obj.getShareLink();
                api.querySharePwd(constant.source.weiyun, shareId, shareLink, function (response) {
                    if (response && response.code == 1) {
                        var sharePwd = response.data.share_pwd;
                        obj.verify_page.share_pwd = sharePwd;
                        obj.verify_page.setPwd(sharePwd);
                        obj.showTipSuccess("填充密码成功");

                        if (option.isOptionActive(option.constant.weiyun_auto_jump)) {
                            obj.verify_page.submit_pwd && obj.verify_page.submit_pwd();
                        }
                    } else {
                        obj.showTipError("暂无人分享密码");
                    }
                });
            };

            obj.registerPwdShareSwitch = function () {
                // 添加开关
                $(".card-inner .form-item-label .form-item-tit").html('<span class="form-item-tit">请输入分享密码<span style="margin-left: 45px;"><input type="checkbox" checked id="nd-share-check" style="vertical-align: middle;"> <a class="nd-open-page-option" href="javascript:;" title="点击查看更多脚本配置">共享密码</a></span></span>');
                obj.isPwdShareOpen() || $("#nd-share-check").removeAttr("checked");

                // 开关-事件
                $("#nd-share-check").on("change", function () {
                    if ($(this).is(':checked')) {
                        option.setOptionActive(option.constant.weiyun_share_status);
                    } else {
                        option.setOptionUnActive(option.constant.weiyun_share_status);
                    }
                });

                // 打开配置页
                $(".nd-open-page-option").click(function () {
                    core.openOptionPage();
                });
            };

            obj.registerStoreSharePwd = function () {
                obj.addResponseInterceptor(function (request, response) {
                    var requestUrl = request.responseURL;
                    if (requestUrl.indexOf("weiyunShareNoLogin/WeiyunShareView") > 0) {
                        if (response.data.data.rsp_header.retcode == 0) {
                            var match = response.config.data.match(/\\"share_pwd\\":\\"([\w]+)\\"/);
                            if (!match) {
                                return logger.warn("pwd share not match");
                            }

                            var sharePwd = match[1];
                            if (sharePwd == obj.verify_page.share_pwd) {
                                return logger.warn("pwd share not change");
                            }

                            if (!obj.isPwdShareOpen()) {
                                return logger.warn("pwd share closed");
                            }

                            var shareId = obj.getShareId();
                            var shareLink = obj.getShareLink();
                            api.storeSharePwd(shareId, sharePwd, shareLink, constant.source.weiyun);
                        } else {
                            return logger.warn("pwd share error");
                        }
                    }
                });
            };

            obj.addResponseInterceptor = function (callback) {
                var success = function (response) {
                    try {
                        callback && callback(response.request, response);
                    } catch (e) {
                        logger.warn(e);
                    }
                    return response;
                };
                var error = function () {
                    return Promise.reject(error);
                };
                obj.getAxios() && obj.getAxios().interceptors.response.use(success, error);
            };

            obj.showTipSuccess = function (msg) {
                obj.getModal() && obj.getModal().success(msg);
            };

            obj.showTipError = function (msg) {
                obj.getModal() && obj.getModal().error(msg);
            };

            obj.getShareId = function () {
                var url = runtime.getUrl();
                var match = url.match(/share.weiyun.com\/([0-9a-z]+)/i);
                return match ? match[1] : null;
            };

            obj.getShareLink = function () {
                return runtime.getUrl();
            };

            obj.isPwdShareOpen = function () {
                return option.isOptionActive(option.constant.weiyun_share_status);
            };

            obj.getAxios = function () {
                if (!obj.axios) {
                    obj.axios = obj.matchWebpackModule(function (module, name) {
                        if (module && module.Axios) {
                            return module;
                        }
                    });
                }
                return obj.axios;
            };

            obj.getModal = function () {
                if (!obj.modal) {
                    obj.modal = obj.matchWebpackModule(function (module, name) {
                        if (module && module.confirm && module.success) {
                            return module;
                        }
                    });
                }
                return obj.modal;
            };

            obj.getStore = function () {
                if (!obj.store) {
                    obj.store = obj.matchWebpackModule(function (module, name) {
                        if (module && module.default && module.default._modulesNamespaceMap) {
                            return module;
                        }
                    });
                }
                return obj.store;
            };

            obj.matchWebpackModule = function (matchFunc) {
                var names = object.keys(obj.webpack_require.c);
                for (var i in names) {
                    var name = names[i];
                    var match = matchFunc(obj.webpack_require(name), name);
                    if (match) {
                        return match;
                    }
                }
            };

            return obj;
        });

        container.define("app_lanzous", ["runtime", "option", "logger", "unsafe_window", "constant", "core", "api", "$"], function (runtime, option, logger, unsafeWindow, constant, core, api, $) {
            var obj = {
                verify_page: {
                    setPwd: null,
                    share_pwd: null,
                    submit_pwd: null
                }
            };

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("lanzous.com") > 0) {
                    option.isOptionActive(option.constant.lanzous_page_verify) && obj.initVerifyPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initVerifyPage = function () {
                obj.registerStoreSharePwd();

                obj.initVerifyPageElement(function () {
                    obj.autoPaddingSharePwd();

                    obj.registerPwdShareSwitch();
                });
            };

            obj.initVerifyPageElement = function (callback) {
                var shareId = obj.getShareId();
                var $pwd = $("#pwd");
                if (shareId && $pwd.length) {

                    // 设置分享密码
                    obj.verify_page.setPwd = function (pwd) {
                        $pwd.val(pwd);
                    };

                    // 提交密码
                    obj.verify_page.submit_pwd = function () {
                        $("#sub").click();
                    };

                    callback && callback();
                } else {
                    setTimeout(function () {
                        obj.initVerifyPageElement(callback)
                    }, 500);
                }
            };

            obj.autoPaddingSharePwd = function () {
                var shareId = obj.getShareId();
                var shareLink = obj.getShareLink();
                api.querySharePwd(constant.source.lanzous, shareId, shareLink, function (response) {
                    if (response && response.code == 1) {
                        var sharePwd = response.data.share_pwd;
                        obj.verify_page.share_pwd = sharePwd;
                        obj.verify_page.setPwd(sharePwd);
                        obj.showTip(1, "填充密码成功", 2000);

                        if (option.isOptionActive(option.constant.lanzous_auto_jump)) {
                            obj.verify_page.submit_pwd && obj.verify_page.submit_pwd();
                        }
                    } else {
                        obj.showTip(0, "暂无人分享密码", 2000);
                    }
                });
            };

            obj.registerPwdShareSwitch = function () {
                var html = '<div style="text-align: center; margin-top: 10px;">分享设置 <input type="checkbox" checked id="nd-share-check" style="vertical-align: middle;" > <a style="cursor: pointer;" class="nd-open-page-option" href="javascript:;" title="点击查看更多脚本配置">共享密码</a></div>';
                if ($(".off").length) {
                    $(".off").after(html);
                } else {
                    $(".passwddiv-user").after(html);
                }
                obj.isPwdShareOpen() || $("#nd-share-check").removeAttr("checked");

                // 开关-事件
                $("#nd-share-check").on("change", function () {
                    if ($(this).is(':checked')) {
                        option.setOptionActive(option.constant.lanzous_share_status);
                    } else {
                        option.setOptionUnActive(option.constant.lanzous_share_status);
                    }
                });

                // 打开配置页
                $(".nd-open-page-option").click(function () {
                    core.openOptionPage();
                });
            };

            obj.registerStoreSharePwd = function () {
                unsafeWindow.$(document).ajaxComplete(function (event, xhr, options) {
                    var match = options.data.match(/pwd=(\w+)/);
                    if (!match) {
                        var match = options.data.match(/p=(\w+)/);
                        if (!match) {
                            return logger.warn("pwd share not match");
                        }
                    }

                    var sharePwd = match[1];

                    if (sharePwd == obj.verify_page.share_pwd) {
                        return logger.warn("pwd share not change");
                    }

                    if (!obj.isPwdShareOpen()) {
                        return logger.warn("pwd share closed");
                    }

                    var shareId = obj.getShareId();
                    var shareLink = obj.getShareLink();
                    var response = obj.parseJson(xhr.response);
                    if (response && response.zt == 1 && sharePwd) {
                        api.storeSharePwd(shareId, sharePwd, shareLink, constant.source.lanzous);
                    } else {
                        logger.warn("pwd share error");
                    }
                });
            };

            obj.showTip = function (code, msg, timeout) {
                if (unsafeWindow.sms) {
                    unsafeWindow.sms(msg);
                } else {
                    var selector;
                    if ($(".off").length) {
                        selector = "#pwderr";
                    } else {
                        selector = "#info";
                    }
                    if (code) {
                        $(selector).html('<span style="color: green;">' + msg + '</span>');
                    } else {
                        $(selector).html('<span style="color: red;">' + msg + '</span>');
                    }
                    setTimeout(function () {
                        $(selector).html("");
                    }, timeout);
                }
            };

            obj.getShareId = function () {
                return location.pathname.split("/")[1];
            };

            obj.getShareLink = function () {
                return top.location.href;
            };

            obj.isPwdShareOpen = function () {
                return option.isOptionActive(option.constant.lanzous_share_status);
            };

            obj.parseJson = function (jsonStr) {
                var jsonObject = {};
                try {
                    if (jsonStr) {
                        jsonObject = JSON.parse(jsonStr);
                    }
                } catch (e) {
                }
                return jsonObject;
            };

            return obj;
        });

        container.define("app_newday", ["object", "meta", "config", "option", "router", "env", "constant", "api", "share_log", "core", "$", "vue"], function (object, meta, config, option, router, env, constant, api, shareLog, core, $, vue) {
            var obj = {};

            obj.run = function () {
                if (meta.existMeta("info")) {
                    obj.initInfoPage();
                    return true;
                } else if (meta.existMeta("option")) {
                    obj.initOptionPage();
                    return true;
                } else if (meta.existMeta("share")) {
                    obj.initSharePage();
                    return true;
                } else if (meta.existMeta("dev")) {
                    obj.initDevPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initInfoPage = function () {
                new vue({
                    el: "#container",
                    data: {
                        info: env.getInfo()
                    },
                    created: function () {
                        obj.initAddonReady();
                    }
                });
            };

            obj.initOptionPage = function () {
                new vue({
                    el: "#container",
                    data: {
                        app_id: config.getConfig("app_id"),
                        temp_path: config.getConfig("temp_path"),
                        info: env.getInfo(),
                        option: option.getOption()
                    },
                    created: function () {
                        obj.initAddonReady();
                    },
                    watch: {
                        option: function (value) {
                            option.setOption(value);
                            api.logOption();
                        },
                        app_id: function (value) {
                            config.setConfig("app_id", value);
                            value && api.logOption();
                        },
                        temp_path: function (value) {
                            config.setConfig("temp_path", value);
                            value && api.logOption();
                        }
                    },
                    methods: {
                        openTempPage: function () {
                            router.openTab("https://pan.baidu.com/disk/home#/all?vmode=list&path=" + encodeURIComponent(this.temp_path ? this.temp_path : "/apps/temp"), true);
                        }
                    }
                });
            };

            obj.initSharePage = function () {
                var shareLogList = shareLog.getShareLogList();
                new vue({
                    el: "#container",
                    data: {
                        info: env.getInfo(),
                        list: []
                    },
                    created: function () {
                        obj.initAddonReady();

                        this.loadShareLogList("all");
                    },
                    methods: {
                        showShareLogList: function (source) {
                            $(".am-nav-tabs .am-active").removeClass("am-active");
                            $(".source-" + source).addClass("am-active");
                            this.loadShareLogList(source);
                        },
                        loadShareLogList: function (source) {
                            this.list = this.processShareLogList(source);
                        },
                        processShareLogList: function (source) {
                            var filterShareLogList = [];
                            object.keys(shareLogList).forEach(function (shareId) {
                                var item = shareLogList[shareId];
                                if (source == "all" || source == item.share_source) {
                                    filterShareLogList.push({
                                        share_id: shareId,
                                        share_pwd: item.share_pwd,
                                        share_link: shareLog.buildShareLink(shareId, item.share_source, item.share_link),
                                        share_time: shareLog.buildShareTime(item.share_time),
                                        create_time: item.share_time
                                    });
                                }
                            });
                            return filterShareLogList.sort(function (a, b) {
                                return b.create_time - a.create_time;
                            });
                        }
                    }
                });
            };

            obj.initDevPage = function () {
                $("#dev-addon-info").val(JSON.stringify(env.getInfo()));

                $(".dev-open-page-option").addClass("nd-open-page-option").removeClass("dev-open-page-option");
                $(document).on("click", ".nd-open-page-option", function () {
                    core.openOptionPage();
                });
            };

            obj.initAddonReady = function () {
                $("body").addClass("nd-addon-ready");
            };

            return obj;
        });

        container.define("app", ["runtime", "addon", "logger", "meta", "$"], function (runtime, addon, logger, meta, $, require) {
            var obj = {};

            obj.run = function () {
                var metaName = "status";
                if (meta.existMeta(metaName)) {
                    logger.warn("setup already");
                } else if (addon.isEnable()) {
                    logger.info("setup success");

                    // 添加meta
                    meta.appendMeta(metaName);

                    // 运行应用
                    $(obj.runApp);
                } else {
                    logger.warn("addon disabled");
                }
            };

            obj.getAppList = function () {
                return [
                    {
                        name: "app_baidu",
                        matchs: [
                            "baidu.com"
                        ]
                    },
                    {
                        name: "app_weiyun",
                        matchs: [
                            "weiyun.com"
                        ]
                    },
                    {
                        name: "app_lanzous",
                        matchs: [
                            "lanzous.com"
                        ]
                    },
                    {
                        name: "app_newday",
                        matchs: [
                            "*"
                        ]
                    }
                ];
            };

            obj.runApp = function () {
                var url = runtime.getUrl();
                logger.info(url);

                var appList = obj.getAppList();
                for (var i in appList) {
                    var app = appList[i];
                    logger.debug(app);

                    var match = obj.matchApp(url, app);
                    logger.debug("match " + (match ? "yes" : "no"));

                    if (match == false) {
                        continue;
                    }

                    logger.info("run " + app.name);
                    if (require(app.name).run() == true) {
                        break;
                    }
                }
            };

            obj.matchApp = function (url, app) {
                var match = false;
                app.matchs.forEach(function (item) {
                    if (url.indexOf(item) > 0 || item == "*") {
                        match = true;
                    }
                });
                return match;
            };

            return obj;
        });

        // lib
        container.define("$", [], function () {
            return window.$;
        });
        container.define("snap", [], function () {
            if (typeof Snap != "undefined") {
                return Snap;
            } else {
                return window.Snap;
            }
        });
        container.define("vue", [], function () {
            return window.Vue;
        });

        container.use(["gm", "core", "app", "logger", "share_log"], function (gm, core, app, logger, shareLog) {
            gm.ready(function () {
                // 日志级别
                logger.setLevel(logger.constant.info);

                core.ready(app.run);
            });
        });
    }
}

// 清除捆绑下载工具
function clearBindTool(currentUrl, currentHost) {
    if (currentHost.indexOf("onlinedown.net") != -1 || currentHost.indexOf("cr173.com") != -1 || currentHost.indexOf("xiazaiba.com") != -1
        || currentHost.indexOf("mydown.com") != -1 || currentHost.indexOf("pc6.com") != -1 || currentHost.indexOf("zol.com.cn") != -1
        || currentHost.indexOf("pconline.com.cn") != -1 || currentHost.indexOf("jb51.net") != -1 || currentHost.indexOf("cncrk.com") != -1
        || currentHost.indexOf("qq.com") != -1 || currentHost.indexOf("crsky.com") != -1 || currentHost.indexOf("duote.com") != -1
        || currentHost.indexOf("downza.cn") != -1 || currentHost.indexOf("yesky.com") != -1 || currentHost.indexOf("ddooo.com") != -1
        || currentHost.indexOf("pchome.net") != -1 || currentHost.indexOf("xpgod.com") != -1 || currentHost.indexOf("52z.com") != -1
        || currentHost.indexOf("opdown.com") != -1) {

        var injectConfig = {
            name: "xzws",
            version: "0.1.5"
        };

        var container = (function () {
            var obj = {
                module_defines: {},
                module_objects: {}
            };

            obj.define = function (name, requires, callback) {
                name = obj.processName(name);
                obj.module_defines[name] = {
                    requires: requires,
                    callback: callback
                };
            };

            obj.require = function (name, cache) {
                if (typeof cache == "undefined") {
                    cache = true;
                }

                name = obj.processName(name);
                if (cache && obj.module_objects.hasOwnProperty(name)) {
                    return obj.module_objects[name];
                } else if (obj.module_defines.hasOwnProperty(name)) {
                    var requires = obj.module_defines[name].requires;
                    var callback = obj.module_defines[name].callback;

                    var module = obj.use(requires, callback);
                    cache && obj.register(name, module);
                    return module;
                }
            };

            obj.use = function (requires, callback) {
                var module = {
                    exports: {}
                };
                var params = obj.buildParams(requires, module);
                var result = callback.apply(this, params);
                if (typeof result != "undefined") {
                    return result;
                } else {
                    return module.exports;
                }
            };

            obj.register = function (name, module) {
                name = obj.processName(name);
                obj.module_objects[name] = module;
            };

            obj.buildParams = function (requires, module) {
                var params = [];
                requires.forEach(function (name) {
                    params.push(obj.require(name));
                });
                params.push(obj.require);
                params.push(module.exports);
                params.push(module);
                return params;
            };

            obj.processName = function (name) {
                return name.toLowerCase();
            };

            return {
                define: obj.define,
                use: obj.use,
                register: obj.register,
                modules: obj.module_objects
            };
        })();

        container.define("gm", [], function () {
            var obj = {};

            obj.ready = function (callback) {
                if (typeof GM_getValue != "undefined") {
                    callback && callback();
                } else {
                    setTimeout(function () {
                        obj.ready(callback);
                    }, 100);
                }
            };

            return obj;
        });

        container.define("runtime", [], function () {
            var obj = {
                url: location.href
            };

            obj.getUrl = function () {
                return obj.url;
            };

            obj.setUrl = function (url) {
                obj.url = url;
            };

            return obj;
        });

        container.define("object", [], function () {
            var obj = {};

            obj.keys = function (data) {
                var list = [];
                for (var key in data) {
                    list.push(key);
                }
                return list;
            };

            obj.values = function (data) {
                var list = [];
                for (var key in data) {
                    list.push(data[key]);
                }
                return list;
            };

            return obj;
        });

        container.define("storage", [], function () {
            var obj = {};

            obj.getValue = function (name, defaultValue) {
                return GM_getValue(name, defaultValue);
            };

            obj.setValue = function (name, value) {
                GM_setValue(name, value);
            };

            obj.getValueList = function () {
                var nameList = GM_listValues();
                var valueList = {};
                nameList.forEach(function (name) {
                    valueList[name] = obj.getValue(name);
                });
                return valueList;
            };

            return obj;
        });

        container.define("addon", ["storage", "constant"], function (storage, constant) {
            var obj = {
                name: constant.name + "_status"
            };

            obj.isEnable = function () {
                if (storage.getValue(obj.name) == "off") {
                    return false;
                } else {
                    return true;
                }
            };

            return obj;
        });

        container.define("config", ["storage", "constant"], function (storage, constant) {
            var obj = {
                name: "config_json"
            };

            obj.getConfig = function (name) {
                var configJson = storage.getValue(obj.name);
                var configObject = obj.parseJson(configJson);
                if (name) {
                    name = obj.processName(name);
                    return configObject.hasOwnProperty(name) ? configObject[name] : null;
                } else {
                    return configObject;
                }
            };

            obj.setConfig = function (name, value) {
                var configObject = obj.getConfig();
                configObject[obj.processName(name)] = value;
                storage.setValue(obj.name, JSON.stringify(configObject));
            };

            obj.parseJson = function (jsonStr) {
                var jsonObject = {};
                try {
                    if (jsonStr) {
                        jsonObject = JSON.parse(jsonStr);
                    }
                } catch (e) {
                }
                return jsonObject;
            };

            obj.processName = function (name) {
                return constant.name + "_" + name;
            };

            return obj;
        });

        container.define("option", ["config", "constant", "object"], function (config, constant, object) {
            var obj = {
                name: "option",
                constant: constant.option
            };

            obj.isOptionActive = function (item) {
                var name = item.name;
                var option = obj.getOption();
                return option.indexOf(name) >= 0;
            };

            obj.setOptionActive = function (item) {
                var name = item.name;
                var option = obj.getOption();
                if (option.indexOf(name) < 0) {
                    option.push(name);
                    obj.setOption(option);
                }
            };

            obj.setOptionUnActive = function (item) {
                var name = item.name;
                var option = obj.getOption();
                var index = option.indexOf(name);
                if (index >= 0) {
                    delete option[index];
                    obj.setOption(option);
                }
            };

            obj.getOption = function () {
                var option = [];
                var optionObject = obj.getOptionObject();
                object.values(obj.constant).forEach(function (item) {
                    var name = item.name;
                    if (optionObject.hasOwnProperty(name)) {
                        if (optionObject[name] != "no") {
                            option.push(name);
                        }
                    } else if (item.value != "no") {
                        option.push(name);
                    }
                });
                return option;
            };

            obj.setOption = function (option) {
                var optionObject = {};
                object.values(obj.constant).forEach(function (item) {
                    var name = item.name;
                    if (option.indexOf(name) >= 0) {
                        optionObject[name] = "yes";
                    } else {
                        optionObject[name] = "no";
                    }
                });
                obj.setOptionObject(optionObject);
            };

            obj.getOptionObject = function () {
                var optionObject = config.getConfig(obj.name);
                return optionObject ? optionObject : {};
            };

            obj.setOptionObject = function (optionObject) {
                config.setConfig(obj.name, optionObject);
            };

            return obj;
        });

        container.define("mode", [], function () {
            var obj = {
                constant: {
                    addon: "addon",
                    script: "script"
                }
            };

            obj.getMode = function () {
                if (typeof GM_info == "undefined") {
                    return obj.constant.addon;
                } else if (GM_info.scriptHandler) {
                    return obj.constant.script;
                } else {
                    return obj.constant.addon;
                }
            };

            return obj;
        });

        container.define("user", ["storage"], function (storage) {
            var obj = {};

            obj.getUid = function () {
                var uid = storage.getValue("uid");
                if (!uid) {
                    uid = obj.randString(32);
                    storage.setValue("uid", uid);
                }
                return uid;
            };

            obj.randString = function (length) {
                var possible = "abcdefghijklmnopqrstuvwxyz0123456789";
                var text = "";
                for (var i = 0; i < length; i++) {
                    text += possible.charAt(Math.floor(Math.random() * possible.length));
                }
                return text;
            };

            return obj;
        });

        container.define("browser", [], function () {
            var obj = {
                constant: {
                    firefox: "firefox",
                    edge: "edge",
                    baidu: "baidu",
                    liebao: "liebao",
                    uc: "uc",
                    qq: "qq",
                    sogou: "sogou",
                    opera: "opera",
                    maxthon: "maxthon",
                    ie2345: "2345",
                    se360: "360",
                    chrome: "chrome",
                    safari: "safari",
                    other: "other"
                }
            };

            obj.getBrowser = function () {
                return obj.matchBrowserType(navigator.userAgent);
            };

            obj.matchBrowserType = function (userAgent) {
                var browser = obj.constant.other;
                userAgent = userAgent.toLowerCase();
                if (userAgent.match(/firefox/) != null) {
                    browser = obj.constant.firefox;
                } else if (userAgent.match(/edge/) != null) {
                    browser = obj.constant.edge;
                } else if (userAgent.match(/bidubrowser/) != null) {
                    browser = obj.constant.baidu;
                } else if (userAgent.match(/lbbrowser/) != null) {
                    browser = obj.constant.liebao;
                } else if (userAgent.match(/ubrowser/) != null) {
                    browser = obj.constant.uc;
                } else if (userAgent.match(/qqbrowse/) != null) {
                    browser = obj.constant.qq;
                } else if (userAgent.match(/metasr/) != null) {
                    browser = obj.constant.sogou;
                } else if (userAgent.match(/opr/) != null) {
                    browser = obj.constant.opera;
                } else if (userAgent.match(/maxthon/) != null) {
                    browser = obj.constant.maxthon;
                } else if (userAgent.match(/2345explorer/) != null) {
                    browser = obj.constant.ie2345;
                } else if (userAgent.match(/chrome/) != null) {
                    if (obj.existMime("type", "application/vnd.chromium.remoting-viewer")) {
                        browser = obj.constant.se360;
                    } else {
                        browser = obj.constant.chrome;
                    }
                } else if (userAgent.match(/safari/) != null) {
                    browser = obj.constant.safari;
                }
                return browser;
            };

            obj.existMime = function (option, value) {
                if (typeof navigator != "undefined") {
                    var mimeTypes = navigator.mimeTypes;
                    for (var mt in mimeTypes) {
                        if (mimeTypes[mt][option] == value) {
                            return true;
                        }
                    }
                }
                return false;
            };

            return obj;
        });

        container.define("env", ["mode", "user", "browser", "constant"], function (mode, user, browser, constant) {
            var obj = {};

            obj.isAddon = function () {
                if (mode.getMode() == mode.constant.addon) {
                    return true;
                } else {
                    return false;
                }
            };

            obj.isInject = function () {
                if (obj.isAddon()) {
                    if (GM_info.addon.name != constant.name) {
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    if (GM_info.script.alias && GM_info.script.alias != constant.name) {
                        return true;
                    } else {
                        return false;
                    }
                }
            };

            obj.getMode = function () {
                return mode.getMode();
            };

            obj.getAid = function () {
                if (GM_info.addon && GM_info.addon.id) {
                    return GM_info.addon.id;
                } else if (GM_info.scriptHandler) {
                    return GM_info.scriptHandler.toLowerCase();
                } else {
                    return "unknown";
                }
            };

            obj.getUid = function () {
                return user.getUid();
            };

            obj.getVersion = function () {
                if (obj.isInject()) {
                    return injectConfig.version;
                } else {
                    return GM_info.script.version;
                }
            };

            obj.getBrowser = function () {
                return browser.getBrowser();
            };

            obj.getInfo = function () {
                return {
                    mode: obj.getMode(),
                    aid: obj.getAid(),
                    uid: obj.getUid(),
                    version: obj.getVersion(),
                    browser: obj.getBrowser()
                };
            };

            return obj;
        });

        container.define("http", [], function () {
            var obj = {};

            obj.ajax = function (option) {
                var details = {
                    url: option.url,
                    responseType: option.dataType,
                    onload: function (result) {
                        option.success && option.success(result.response);
                    },
                    onerror: function (result) {
                        option.error && option.error(result.error);
                    }
                };

                // 提交数据
                if (option.data) {
                    details.method = "POST";
                    if (option.data instanceof FormData) {
                        details.data = option.data;
                    } else {
                        var formData = new FormData();
                        for (var i in option.data) {
                            formData.append(i, option.data[i]);
                        }
                        details.data = formData;
                    }
                } else {
                    details.method = "GET";
                }

                // 自定义头
                if (option.headers) {
                    details.headers = option.headers;
                }

                // 超时
                if (option.timeout) {
                    details.timeout = option.timeout;
                }

                GM_xmlhttpRequest(details);
            };

            return obj;
        });

        container.define("logger", ["env", "constant"], function (env, constant) {
            var obj = {
                level: 3,
                constant: {
                    debug: 0,
                    info: 1,
                    warn: 2,
                    error: 3
                }
            };

            obj.debug = function (message) {
                obj.log(message, obj.constant.debug);
            };

            obj.info = function (message) {
                obj.log(message, obj.constant.info);
            };

            obj.warn = function (message) {
                obj.log(message, obj.constant.warn);
            };

            obj.error = function (message) {
                obj.log(message, obj.constant.error);
            };

            obj.log = function (message, level) {
                if (level < obj.level) {
                    return false;
                }

                console.group("[" + constant.name + "]" + env.getMode());
                console.log(message);
                console.groupEnd();
            };

            obj.setLevel = function (level) {
                obj.level = level;
            };

            return obj;
        });

        container.define("meta", ["constant", "$"], function (constant, $) {
            var obj = {};

            obj.existMeta = function (name) {
                name = obj.processName(name);
                if ($("meta[name='" + name + "']").length) {
                    return true;
                } else {
                    return false;
                }
            };

            obj.appendMeta = function (name, content) {
                name = obj.processName(name);
                content || (content = "on");
                $('<meta name="' + name + '" content="on">').appendTo($("head"));
            };

            obj.processName = function (name) {
                return constant.name + "::" + name;
            };

            return obj;
        });

        /** custom start **/
        container.define("constant", ["mode", "browser"], function (mode, browser) {
            return {
                name: injectConfig.name,
                mode: mode.constant,
                browser: browser.constant,
                option: {
                    site_onlinedown: {
                        name: "site_onlinedown",
                        value: "yes"
                    },
                    site_cr173: {
                        name: "site_cr173",
                        value: "yes"
                    },
                    site_xiazaiba: {
                        name: "site_xiazaiba",
                        value: "yes"
                    },
                    site_mydown: {
                        name: "site_mydown",
                        value: "yes"
                    },
                    site_pc6: {
                        name: "site_pc6",
                        value: "yes"
                    },
                    site_zol: {
                        name: "site_zol",
                        value: "yes"
                    },
                    site_pconline: {
                        name: "site_pconline",
                        value: "yes"
                    },
                    site_jb51: {
                        name: "site_jb51",
                        value: "yes"
                    },
                    site_cncrk: {
                        name: "site_cncrk",
                        value: "yes"
                    },
                    site_pc_qq: {
                        name: "site_pc_qq",
                        value: "yes"
                    },
                    site_crsky: {
                        name: "site_crsky",
                        value: "yes"
                    },
                    site_duote: {
                        name: "site_duote",
                        value: "yes"
                    },
                    site_downza: {
                        name: "site_downza",
                        value: "yes"
                    },
                    site_yesky: {
                        name: "site_yesky",
                        value: "yes"
                    },
                    site_ddooo: {
                        name: "site_ddooo",
                        value: "yes"
                    },
                    site_pchome: {
                        name: "site_pchome",
                        value: "yes"
                    },
                    site_xpgod: {
                        name: "site_xpgod",
                        value: "yes"
                    },
                    site_52z: {
                        name: "site_52z",
                        value: "yes"
                    },
                    site_opdown: {
                        name: "site_opdown",
                        value: "yes"
                    }
                }
            };
        });

        container.define("core", [], function () {
            var obj = {};

            obj.ready = function (callback) {
                callback && callback();
            };

            return obj;
        });

        // http://www.onlinedown.net/soft/5.htm
        container.define("app_onlinedown", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("onlinedown.net/soft") > 0) {
                    option.isOptionActive(option.constant.site_onlinedown) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 顶部高速下载
                $(".onedownbtn2").hide();

                // 底部高速下载
                $($(".downDz h4").get(0)).hide();
                $($(".downDz div").get(0)).hide();

                // 移除弹窗
                $(".wxWp").remove();
            };

            return obj;
        });

        // https://www.cr173.com/soft/18645.html
        container.define("app_cr173", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("cr173.com/soft") > 0 || url.indexOf("cr173.com/game") > 0) {
                    option.isOptionActive(option.constant.site_cr173) && obj.initSoftPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initSoftPage = function () {
                // 顶部高速下载
                $(".maindown_w4").hide();

                // 底部高速下载
                $(".ul_Address").each(function () {
                    if ($(this).find(".f-gsh3").length > 1) {
                        $($(this).find(".f-gsh3").get(0)).hide();
                    }
                });
                $(".ul_Address .downurl").hide();
            };

            return obj;
        });

        // https://www.xiazaiba.com/html/82.html
        container.define("app_xiazaiba", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("xiazaiba.com/html") > 0) {
                    option.isOptionActive(option.constant.site_xiazaiba) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 顶部高速下载
                $(".soft-btn").hide();

                // 底部高速下载
                $(".needfast").parent().hide();
            };

            return obj;
        });

        // http://www.mydown.com/soft/421/472030921.shtml
        container.define("app_mydown", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("mydown.com/soft") > 0) {
                    option.isOptionActive(option.constant.site_mydown) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 高速下载
                $(".downbtn").hide();
            };

            return obj;
        });

        // http://www.pc6.com/softview/SoftView_1822.html
        // http://www.pc6.com/mod/647389.html
        // http://www.pc6.com/az/254734.html
        container.define("app_pc6", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("pc6.com/softview") > 0) {
                    option.isOptionActive(option.constant.site_pc6) && obj.initDownloadPageSoft();
                    return true;
                } else if (url.indexOf("pc6.com/mod") > 0) {
                    option.isOptionActive(option.constant.site_pc6) && obj.initDownloadPageSoft();
                    return true;
                } else if (url.indexOf("pc6.com/az") > 0) {
                    option.isOptionActive(option.constant.site_pc6) && obj.initDownloadPageAndroid();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPageSoft = function () {
                // 顶部高速下载
                $("#xzbtn .downnow").hide();

                // 底部高速下载
                $(".ul_Address").each(function () {
                    if ($(this).find("h3").length > 1) {
                        $($(this).find("h3").get(0)).hide();
                    }
                });
                $(".ul_Address #gaosuxiazai").hide();
            };

            obj.initDownloadPageAndroid = function () {
                $(".ul_Address").each(function () {
                    if ($(this).find("h3").length > 1) {
                        $($(this).find("h3").get(0)).hide();
                    }
                });
                $(".ul_Address #gaosuxiazai").hide();
            };

            return obj;
        });

        // http://xiazai.zol.com.cn/detail/9/89734.shtml
        // http://xiazai.zol.com.cn/index.php?c=Detail_DetailMini&n=e4bd1f21d0c761d05&softid=89734
        container.define("app_zol", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("zol.com.cn/detail") > 0) {
                    option.isOptionActive(option.constant.site_zol) && obj.initDownloadPage();
                    return true;
                } else if (url.indexOf("zol.com.cn/index.php") > 0) {
                    option.isOptionActive(option.constant.site_zol) && obj.initDownloadPageMini();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 顶部高速下载
                $(".soft-text-l").hide();
                $(".soft-text-r").addClass("soft-text-l").removeClass("soft-text-r");

                // 底部高速下载
                $(".xiazaib-topa-box").hide();
            };

            obj.initDownloadPageMini = function () {
                $(".down-h4").parent().hide();
                $(".jisu-downa.clearfix").hide();
            };

            return obj;
        });

        // https://dl.pconline.com.cn/download/91034.html
        container.define("app_pconline", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("pconline.com.cn/download") > 0) {
                    option.isOptionActive(option.constant.site_pconline) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 顶部高速下载
                $("#JhsBtn").hide();

                // 底部高速下载
                $(".links p").not(".mb10").hide();
                $(".box.rela-ivy").hide();

                // 误导性广告
                $(".ivy").hide();
            };

            return obj;
        });

        // https://www.jb51.net/softs/40589.html
        // https://www.jb51.net/fonts/658225.html
        // https://www.jb51.net/game/649384.html
        // https://www.jb51.net/codes/575492.html
        container.define("app_jb51", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("jb51.net/softs") > 0) {
                    option.isOptionActive(option.constant.site_jb51) && obj.initDownloadPage();
                    return true;
                } else if (url.indexOf("jb51.net/fonts") > 0) {
                    option.isOptionActive(option.constant.site_jb51) && obj.initDownloadPage();
                    return true;
                } else if (url.indexOf("jb51.net/game") > 0) {
                    option.isOptionActive(option.constant.site_jb51) && obj.initDownloadPage();
                    return true;
                } else if (url.indexOf("jb51.net/codes") > 0) {
                    option.isOptionActive(option.constant.site_jb51) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 顶部高速下载
                $(".gsdw").hide();
                $(".gsdown").hide();

                // 底部高速下载
                $($(".address-wrap .gs").get(0)).hide();
                $("#gaosu").hide();
            };

            return obj;
        });

        // http://www.cncrk.com/downinfo/180262.html
        container.define("app_cncrk", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("cncrk.com/downinfo") > 0) {
                    option.isOptionActive(option.constant.site_cncrk) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 高速下载
                $(".downfile_hits").hide();
                $(".download-address").html("<p>全是捆绑下载,已作隐藏处理</p>");
            };

            return obj;
        });

        // https://pc.qq.com/detail/8/detail_11488.html
        container.define("app_qq", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("pc.qq.com/detail") > 0) {
                    option.isOptionActive(option.constant.site_pc_qq) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 高速下载
                $(".btn01.J_qq_download").hide();
                $(".detail-install-fast.J_qq_download").hide();
            };

            return obj;
        });

        // https://www.crsky.com/soft/48442.html
        container.define("app_crsky", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("crsky.com/soft") > 0) {
                    option.isOptionActive(option.constant.site_crsky) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                $($(".i_dwon a").get(1)).hide();

                $(".Adown_dli").hide();
                $(".Imdown").hide();
            };

            return obj;
        });

        // http://www.duote.com/soft/314065.html
        container.define("app_duote", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("duote.com/soft") > 0) {
                    option.isOptionActive(option.constant.site_duote) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 误导广告
                $(".dl-banner").hide();
                $(".large-soft-down-btn.fast-down-btn").hide();

                // 底部高速下载
                $(".down-lists").each(function () {
                    if ($(this).find(".download-box").length > 1) {
                        $($(this).find(".download-box").get(0)).hide();
                    }
                });
            };

            return obj;
        });

        // http://www.downza.cn/soft/193456.html
        container.define("app_downza", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("downza.cn/soft") > 0 || url.indexOf("downza.cn/android") > 0) {
                    option.isOptionActive(option.constant.site_downza) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 顶部高速下载
                $("#xzqIMG1").hide();

                // 底部高速下载
                $($(".pc-down_url_left .pull-left div").get(0)).hide();
                $(".pc-down_url_left .down_top").hide();
            };

            return obj;
        });

        // http://mydown.yesky.com/pcsoft/266126.html
        container.define("app_yesky", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("yesky.com/pcsoft") > 0) {
                    option.isOptionActive(option.constant.site_yesky) && obj.initDownloadPage();
                    return true;
                } else if (url.indexOf("yesky.com/game") > 0) {
                    option.isOptionActive(option.constant.site_yesky) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 顶部高速下载
                $(".bkdown").hide();
                $("#local_down").show();

                // 底部高速下载
                $($(".bk-soft_downurl .url h4").get(0)).hide();
                $(".bk-soft_downurl .down_referer").hide();
                $(".bk-soft_downurl hr").hide();
            };

            return obj;
        });

        // http://www.ddooo.com/softdown/65448.htm
        container.define("app_ddooo", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("ddooo.com/softdown") > 0) {
                    option.isOptionActive(option.constant.site_ddooo) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 顶部高速下载
                $(".bottom1").hide();

                // 底部高速下载
                $($(".txtfont").get(0)).hide();
                $(".c_down").hide();
            };

            return obj;
        });

        // https://download.pchome.net/mobile/games/other/download-193583.html
        container.define("app_pchome", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("download.pchome.net") > 0 && url.indexOf("/download-") > 0) {
                    option.isOptionActive(option.constant.site_pchome) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 不需提示
                $(".dl-tip").hide();

                // 混淆广告
                $(".mod_banner").hide();
            };

            return obj;
        });

        // https://www.xpgod.com/soft/121.html
        container.define("app_xpgod", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("xpgod.com/soft") > 0) {
                    option.isOptionActive(option.constant.site_xpgod) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 顶部高速下载
                $(".bzxz").hide();

                // 底部高速下载
                $(".show_xzq").hide();
            };

            return obj;
        });

        // https://www.52z.com/soft/389669.html
        container.define("app_52z", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("52z.com/soft") > 0) {
                    option.isOptionActive(option.constant.site_52z) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 高速下载
                setTimeout(function () {
                    $($(".elYxxzIn").get(0)).hide();
                }, 1000);
            };

            return obj;
        });

        // http://www.opdown.com/soft/23485.html
        container.define("app_opdown", ["runtime", "option", "$"], function (runtime, option, $) {
            var obj = {};

            obj.run = function () {
                var url = runtime.getUrl();
                if (url.indexOf("opdown.com/soft") > 0) {
                    option.isOptionActive(option.constant.site_opdown) && obj.initDownloadPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initDownloadPage = function () {
                // 高速下载
                $(".downnows").hide();
                $(".listaddr").hide();
            };

            return obj;
        });

        container.define("app_newday", ["env", "config", "option", "meta", "vue"], function (env, config, option, meta, vue) {
            var obj = {};

            obj.run = function () {
                if (meta.existMeta("option")) {
                    obj.initOptionPage();
                    return true;
                } else {
                    return false;
                }
            };

            obj.initOptionPage = function () {
                new vue({
                    el: "#container",
                    data: {
                        info: env.getInfo(),
                        option: option.getOption(),
                        check_switch: config.getConfig("check_switch") == "off" ? false : true
                    },
                    created: function () {
                        obj.initAddonReady();
                    },
                    watch: {
                        option: function (value) {
                            option.setOption(value);
                        },
                        check_switch: function (value) {
                            config.setConfig("check_switch", value ? "on" : "off");
                        }
                    }
                });
            };

            obj.initAddonReady = function () {
                $("body").addClass("nd-addon-ready");
            };

            return obj;
        });

        container.define("app", ["runtime", "addon", "config", "logger", "meta", "$"], function (runtime, addon, config, logger, meta, $, require) {
            var obj = {
                check_switch: "check_switch"
            };

            obj.run = function () {
                var metaName = "status";
                if (meta.existMeta(metaName)) {
                    logger.warn("setup already");
                } else if (addon.isEnable()) {
                    logger.info("setup success");

                    // 添加meta
                    meta.appendMeta(metaName);

                    // 运行应用
                    $(obj.runApp);
                } else {
                    logger.warn("addon disabled");
                }
            };

            obj.getAppList = function () {
                return [
                    {
                        name: "app_onlinedown",
                        matchs: [
                            "onlinedown.net"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_cr173",
                        matchs: [
                            "cr173.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_xiazaiba",
                        matchs: [
                            "xiazaiba.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_mydown",
                        matchs: [
                            "mydown.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_pc6",
                        matchs: [
                            "pc6.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_zol",
                        matchs: [
                            "zol.com.cn"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_pconline",
                        matchs: [
                            "pconline.com.cn"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_jb51",
                        matchs: [
                            "jb51.net"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_cncrk",
                        matchs: [
                            "cncrk.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_qq",
                        matchs: [
                            "pc.qq.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_crsky",
                        matchs: [
                            "www.crsky.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_duote",
                        matchs: [
                            "duote.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_downza",
                        matchs: [
                            "downza.cn"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_yesky",
                        matchs: [
                            "yesky.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_ddooo",
                        matchs: [
                            "ddooo.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_pchome",
                        matchs: [
                            "pchome.net"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_xpgod",
                        matchs: [
                            "xpgod.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_52z",
                        matchs: [
                            "52z.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_opdown",
                        matchs: [
                            "opdown.com"
                        ],
                        switch: obj.check_switch
                    },
                    {
                        name: "app_newday",
                        matchs: [
                            "*"
                        ]
                    }
                ];
            };

            obj.runApp = function () {
                var url = runtime.getUrl();
                logger.info(url);

                var appList = obj.getAppList();
                for (var i in appList) {
                    var app = appList[i];
                    logger.debug(app);

                    var match = obj.matchApp(url, app);
                    logger.debug("match " + (match ? "yes" : "no"));

                    if (match == false) {
                        continue;
                    }

                    if (app.switch && config.getConfig(app.switch) == "off") {
                        continue;
                    }

                    logger.info("run " + app.name);
                    if (require(app.name).run() == true) {
                        break;
                    }
                }
            };

            obj.matchApp = function (url, app) {
                var match = false;
                app.matchs.forEach(function (item) {
                    if (url.indexOf(item) > 0 || item == "*") {
                        match = true;
                    }
                });
                return match;
            };

            return obj;
        });

        // 注册模块
        container.define("$", [], function () {
            return window.$;
        });
        container.define("vue", [], function () {
            return window.Vue;
        });

        container.use(["gm", "core", "app", "logger"], function (gm, core, app, logger) {
            gm.ready(function () {
                // 日志级别
                logger.setLevel(logger.constant.info);

                core.ready(app.run);
            });
        });
    }
}

//===============工具类
function transformTime(timestamp) {
    if (timestamp) {
        var time = new Date(timestamp);
        var y = time.getFullYear(); //getFullYear方法以四位数字返回年份
        var M = time.getMonth() + 1; // getMonth方法从 Date 对象返回月份 (0 ~ 11),返回结果需要手动加一
        var d = time.getDate(); // getDate方法从 Date 对象返回一个月中的某一天 (1 ~ 31)
        var h = time.getHours(); // getHours方法返回 Date 对象的小时 (0 ~ 23)
        var m = time.getMinutes(); // getMinutes方法返回 Date 对象的分钟 (0 ~ 59)
        var s = time.getSeconds(); // getSeconds方法返回 Date 对象的秒数 (0 ~ 59)
        return y + '-' + M + '-' + d + ' ' + h + ':' + m + ':' + s;
    } else {
        return '';
    }
}


function getQueryString(name) {
    var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
    var reg_rewrite = new RegExp("(^|/)" + name + "/([^/]*)(/|$)", "i");
    var r = window.location.search.substr(1).match(reg);
    var q = window.location.pathname.substr(1).match(reg_rewrite);
    if (r != null) {
        return unescape(r[2]);
    } else if (q != null) {
        return unescape(q[2]);
    } else {
        return "";
    }
}

function showContent(content, title) {
    layer.closeAll();
    layer.open({type: 1, title: title, shade: 0, content: content});
}

function alertMessage(msg) {
    layer.closeAll();
    layer.msg(msg, {icon: 5});
}


//下载知乎视频
(async () => {
    const playlistBaseUrl = 'https://lens.zhihu.com/api/videos/';
    const videoId = window.location.pathname.split('/').pop(); // 视频id
    const menuStyle = 'transform:none !important; left:auto !important; right:-0.5em !important;';
    const playerId = 'player';
    const svgDownload = '<path d="M9.5,4 H14.5 V10 H17.8 L12,15.8 L6.2,10 H9.5 Z M6.2,18 H17.8 V20 H6.2 Z"></path>';
    let player = document.getElementById(playerId);
    let resolutionMap = {'标清': 'sd', '高清': 'ld', '超清': 'hd'};
    let videos = []; // 存储各分辨率的视频信息
    let downloading = false;

    function getBrowerInfo() {
        let browser = (function (window) {
            let document = window.document;
            let navigator = window.navigator;
            let agent = navigator.userAgent.toLowerCase();
            // IE8+支持.返回浏览器渲染当前文档所用的模式
            // IE6,IE7:undefined.IE8:8(兼容模式返回7).IE9:9(兼容模式返回7||8)
            // IE10:10(兼容模式7||8||9)
            let IEMode = document.documentMode;
            let chrome = window.chrome || false;
            let system = {
                // user-agent
                agent: agent,
                // 是否为IE
                isIE: /trident/.test(agent),
                // Gecko内核
                isGecko: agent.indexOf('gecko') > 0 && agent.indexOf('like gecko') < 0,
                // webkit内核
                isWebkit: agent.indexOf('webkit') > 0,
                // 是否为标准模式
                isStrict: document.compatMode === 'CSS1Compat',
                // 是否支持subtitle
                supportSubTitle: function () {
                    return 'track' in document.createElement('track');
                },
                // 是否支持scoped
                supportScope: function () {
                    return 'scoped' in document.createElement('style');
                },

                // 获取IE的版本号
                ieVersion: function () {
                    let rMsie = /(msie\s|trident.*rv:)([\w.]+)/;
                    let match = rMsie.exec(agent);
                    try {
                        return match[2];
                    } catch (e) {
                        return IEMode;
                    }
                },
                // Opera版本号
                operaVersion: function () {
                    try {
                        if (window.opera) {
                            return agent.match(/opera.([\d.]+)/)[1];
                        } else if (agent.indexOf('opr') > 0) {
                            return agent.match(/opr\/([\d.]+)/)[1];
                        }
                    } catch (e) {
                        return 0;
                    }
                }
            };

            try {
                // 浏览器类型(IE、Opera、Chrome、Safari、Firefox)
                system.type = system.isIE ? 'IE' :
                    window.opera || (agent.indexOf('opr') > 0) ? 'Opera' :
                        (agent.indexOf('chrome') > 0) ? 'Chrome' :
                            //safari也提供了专门的判定方式
                            window.openDatabase ? 'Safari' :
                                (agent.indexOf('firefox') > 0) ? 'Firefox' :
                                    'unknow';

                // 版本号
                system.version = (system.type === 'IE') ? system.ieVersion() :
                    (system.type === 'Firefox') ? agent.match(/firefox\/([\d.]+)/)[1] :
                        (system.type === 'Chrome') ? agent.match(/chrome\/([\d.]+)/)[1] :
                            (system.type === 'Opera') ? system.operaVersion() :
                                (system.type === 'Safari') ? agent.match(/version\/([\d.]+)/)[1] :
                                    '0';

                // 浏览器外壳
                system.shell = function () {
                    if (agent.indexOf('edge') > 0) {
                        system.version = agent.match(/edge\/([\d.]+)/)[1] || system.version;
                        return 'Edge';
                    }
                    // 遨游浏览器
                    if (agent.indexOf('maxthon') > 0) {
                        system.version = agent.match(/maxthon\/([\d.]+)/)[1] || system.version;
                        return 'Maxthon';
                    }
                    // QQ浏览器
                    if (agent.indexOf('qqbrowser') > 0) {
                        system.version = agent.match(/qqbrowser\/([\d.]+)/)[1] || system.version;
                        return 'QQBrowser';
                    }
                    // 搜狗浏览器
                    if (agent.indexOf('se 2.x') > 0) {
                        return '搜狗浏览器';
                    }

                    // Chrome:也可以使用window.chrome && window.chrome.webstore判断
                    if (chrome && system.type !== 'Opera') {
                        let external = window.external;
                        let clientInfo = window.clientInformation;
                        // 客户端语言:zh-cn,zh.360下面会返回undefined
                        let clientLanguage = clientInfo.languages;

                        // 猎豹浏览器:或者agent.indexOf("lbbrowser")>0
                        if (external && 'LiebaoGetVersion' in external) {
                            return 'LBBrowser';
                        }
                        // 百度浏览器
                        if (agent.indexOf('bidubrowser') > 0) {
                            system.version = agent.match(/bidubrowser\/([\d.]+)/)[1] ||
                                agent.match(/chrome\/([\d.]+)/)[1];
                            return 'BaiDuBrowser';
                        }
                        // 360极速浏览器和360安全浏览器
                        if (system.supportSubTitle() && typeof clientLanguage === 'undefined') {
                            let storeKeyLen = Object.keys(chrome.webstore).length;
                            let v8Locale = 'v8Locale' in window;
                            return storeKeyLen > 1 ? '360极速浏览器' : '360安全浏览器';
                        }
                        return 'Chrome';
                    }
                    return system.type;
                };

                // 浏览器名称(如果是壳浏览器,则返回壳名称)
                system.name = system.shell();
                // 对版本号进行过滤过处理
                // System.version = System.versionFilter(System.version);

            } catch (e) {
                // console.log(e.message);
            }

            return system;

        })(window);

        if (browser.name == undefined || browser.name == '') {
            browser.name = 'Unknown';
            browser.version = 'Unknown';
        } else if (browser.version == undefined) {
            browser.version = 'Unknown';
        }
        return browser;
    }

    function fetchRetry(url, options = {}, times = 1, delay = 1000, checkStatus = true) {
        return new Promise((resolve, reject) => {
            // fetch 成功处理函数
            function success(res) {
                if (checkStatus && !res.ok) {
                    failure(res);
                } else {
                    resolve(res);
                }
            }

            // 单次失败处理函数
            function failure(error) {
                times--;

                if (times) {
                    setTimeout(fetchUrl, delay);
                } else {
                    reject(error);
                }
            }

            // 总体失败处理函数
            function finalHandler(error) {
                throw error;
            }

            function fetchUrl() {
                return fetch(url, options)
                    .then(success)
                    .catch(failure)
                    .catch(finalHandler);
            }

            fetchUrl();
        });
    }

    // 下载指定url的资源
    async function downloadUrl(url, name = (new Date()).valueOf() + '.mp4') {
        let browser = getBrowerInfo();

        // Greasemonkey 需要把 url 转为 blobUrl
        if (GM_info.scriptHandler == 'Greasemonkey') {
            let res = await fetchRetry(url);
            let blob = await res.blob();
            url = URL.createObjectURL(blob);
        }

        // Chrome 可以使用 Tampermonkey 的 GM_download 函数绕过 CSP(Content Security Policy) 的限制
        if (window.GM_download) {
            GM_download({url, name});
        } else {
            // firefox 需要禁用 CSP, about:config -> security.csp.enable => false
            let a = document.createElement('a');
            a.href = url;
            a.download = name;
            // a.target = '_blank';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);

            setTimeout(function () {
                URL.revokeObjectURL(url);
            }, 100);
        }
    }

    function humanSize(size) {
        let n = Math.log(size) / Math.log(1024) | 0;
        return (size / Math.pow(1024, n)).toFixed(0) + ' ' + (n ? 'KMGTPEZY'[--n] + 'B' : 'Bytes');
    }

    if (!player) return;

    // 获取视频信息
    const res = await fetchRetry(playlistBaseUrl + videoId, {
        headers: {
            'referer': 'refererBaseUrl + videoId',
            'authorization': 'oauth c3cef7c66a1843f8b3a9e6a1e3160e20' // in zplayer.min.js of zhihu
        }
    }, 3);
    const videoInfo = await res.json();

    // 获取不同分辨率视频的信息
    for (let [key, video] of Object.entries(videoInfo.playlist)) {
        video.name = key;

        if (!videos.find(v => v.width == video.width)) {
            videos.push(video);
        }
    }

    // 按分辨率大小排序
    videos = videos.sort(function (v1, v2) {
        return v1.width == v2.width ? 0 : (v1.width > v2.width ? 1 : -1);
    }).reverse();

    document.addEventListener('DOMNodeInserted', (evt) => {
        let domControlBar = evt.relatedNode.querySelector(':scope > div:last-child > div:first-child');
        if (!domControlBar || domControlBar.querySelector('.download')) return;

        let domFullScreenBtn = domControlBar.querySelector(':scope > div:nth-last-of-type(1)');
        let domResolutionBtn = domControlBar.querySelector(':scope > div:nth-last-of-type(3)');
        let domDownloadBtn, defaultResolution, buttons;
        if (!domFullScreenBtn || !domFullScreenBtn.querySelector('button')) return;

        // 克隆分辨率菜单或全屏按钮为下载按钮
        domDownloadBtn = (domResolutionBtn && (domResolutionBtn.className == domFullScreenBtn.className))
            ? domResolutionBtn.cloneNode(true)
            : domFullScreenBtn.cloneNode(true);

        defaultResolution = domDownloadBtn.querySelector('button').innerText;

        // 生成下载按钮图标
        domDownloadBtn.querySelector('button:first-child').outerHTML = domFullScreenBtn.cloneNode(true).querySelector('button').outerHTML;
        domDownloadBtn.querySelector('svg').innerHTML = svgDownload;
        domDownloadBtn.className = domDownloadBtn.className + ' download';

        buttons = domDownloadBtn.querySelectorAll('button');

        // button 元素添加对应的下载地址
        buttons.forEach(dom => {
            let video = videos.find(v => v.name == resolutionMap[dom.innerText || defaultResolution]);
            video = video || videos[0];
            dom.dataset.video = video.play_url;
            if (dom.innerText) {
                (dom.innerText = `${dom.innerText} (${humanSize(video.size)})`);
            } else if (buttons.length == 1) {
                dom.nextSibling.querySelector('div').innerText = humanSize(video.size);
            }
        });

        // 鼠标事件 - 显示菜单
        domDownloadBtn.addEventListener('pointerenter', () => {
            let domMenu = domDownloadBtn.querySelector('div:nth-of-type(1)');
            if (domMenu) {
                domMenu.style.cssText = menuStyle + 'opacity:1 !important; visibility:visible !important';
            }
        });

        // 鼠标事件 - 隐藏菜单
        domDownloadBtn.addEventListener('pointerleave', () => {
            let domMenu = domDownloadBtn.querySelector('div:nth-of-type(1)');
            if (domMenu) {
                domMenu.style.cssText = menuStyle;
            }
        });

        // 鼠标事件 - 选择菜单项
        domDownloadBtn.addEventListener('pointerup', event => {
            if (downloading) {
                alert('当前正在执行下载任务,请等待任务完成。');
                return;
            }

            let e = event.srcElement || event.target;

            while (e.tagName != 'BUTTON') {
                e = e.parentNode;
            }

            downloadUrl(e.dataset.video);
        });

        // 显示下载按钮
        domControlBar.appendChild(domDownloadBtn);

    });
})();