Greasy Fork

来自缓存

Greasy Fork is available in English.

发送到115

115离线下载功能

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         发送到115
// @author       zxf10608
// @version      7.5.1
// @icon         https://115.com/favicon.ico
// @namespace    http://greasyfork.icu/zh-CN/scripts/408466
// @description  115离线下载功能
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @require      http://greasyfork.icu/scripts/398240-gm-config-zh-cn/code/GM_config_zh-CN.js
// @require      http://greasyfork.icu/scripts/412267-base64-v1-0/code/base64_v10.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/toastr.min.js
// @resource     toastrCss   https://cdn.jsdelivr.net/npm/[email protected]/build/toastr.min.css
// @match        http*://*/*
// @match        http*://*.115.com/*
// @exclude      http*://*.115.com/bridge*
// @exclude      http*://*.115.com/*/static*
// @exclude      http*://*.baidu.com/*
// @exclude      http*://*.iqiyi.com/*
// @exclude      http*://*.qq.com/*
// @exclude      http*://*.youku.com/*
// @exclude      http*://*.bilibili.com/
// @exclude      http*://*.pptv.com/*
// @exclude      http*://*.fun.tv/*
// @exclude      http*://*.sohu.com/*
// @exclude      http*://*.le.com/*
// @exclude      http*://*.tudou.com/*
// @exclude      http*://*.bilibili.com/*
// @exclude      http*://music.163.com/*
// @exclude      http*://github.com/*
// @exclude      http*://gitee.com/*
// @exclude      http*://btcache.me/*
// @exclude      http*://*.jd.com/*
// @exclude      http*://*.taobao.com/*
// @exclude      http*://*.tmall.com/*
// @exclude      http*://*.vip.com/*
// @exclude      http*://*.pinduoduo.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @grant        GM_download
// @grant        GM_openInTab
// @grant        GM_setClipboard
// @grant        GM_getResourceText
// @grant        GM_xmlhttpRequest
// @grant        GM_registerMenuCommand
// @connect      115.com
// @connect      *
// @grant        unsafeWindow
// @grant        window.open
// @grant        window.close
// @run-at       document-start
// @compatible   chrome
// @license      GPL License
// ==/UserScript==

(function() {
    'use strict';
    var newVersion = 'v7.5.1';

    if (typeof GM_config == 'undefined') {
        alert('115优化大师:\n网络异常,相关库文件加载失败,脚本无法使用,请刷新网页重新加载!');
        return;
    } else {
        console.log('115优化大师:相关库文件加载成功!');
    }

    // 配置界面
    function config() {
        var windowCss = '#Cfg .nav-tabs {margin: 20 2} #Cfg .config_var textarea{width: 310px; height: 50px;} #Cfg .inline {padding-bottom:0px;} #Cfg .config_header a:hover {color:#1e90ff;} #Cfg .config_var {margin-left: 10%;margin-right: 10%;} #Cfg input[type="checkbox"] {margin: 3px 3px 3px 0px;} #Cfg input[type="text"] {width: 53px;} #Cfg {background-color: lightblue;} #Cfg .reset_holder {float: left; position: relative; bottom: -1em;} #Cfg .saveclose_buttons {margin: .7em;} #Cfg .section_desc {font-size: 10pt;}';

        GM_registerMenuCommand('设置', opencfg);
        function opencfg() {
            GM_config.open();
        }

        GM_config.init({
            id: 'Cfg',
            title: GM_config.create('a', {
                href: 'http://greasyfork.icu/zh-CN/scripts/408466',
                target: '_blank',
                className: 'setTitle',
                textContent: '115优化大师',
                title: '作者:zxf10608 版本:' + newVersion + ' 点击访问主页'
            }),
            isTabs: true,
            skin: 'tab',
            css: windowCss,
            frameStyle: {
                height: '550px',
                width: '445px',
                zIndex: '2147483648',
            },
            fields: {
                // 离线升级
                offline_Down: {
                    section: ['离线升级', '升级离线下载功能'],
                    label: '启用一键离线下载',
                    labelPos: 'right',
                    type: 'checkbox',
                    default: true,
                },
                offline_result: {
                    label: '任务添加后显示离线结果',
                    labelPos: 'right',
                    type: 'checkbox',
                    default: true,
                },
                open_List: {
                    label: '离线后自动打开任务列表',
                    labelPos: 'right',
                    type: 'checkbox',
                    default: false,
                },
                open_search: {
                    label: '离线成功后开启视频搜索',
                    labelPos: 'right',
                    type: 'checkbox',
                    default: true,
                    line: 'start',
                },
                search_result: {
                    label: '显示视频搜索结果',
                    labelPos: 'right',
                    type: 'checkbox',
                    default: true,
                },
                open_Popup: {
                    label: '搜到视频自动播放',
                    labelPos: 'right',
                    type: 'checkbox',
                    default: false,
                    line: 'end',
                },
                fuzzy_find: {
                    label: '启用下载地址模糊匹配',
                    labelPos: 'right',
                    type: 'checkbox',
                    default: false,
                },
                diy_folder: {
                    label: '自定义离线下载文件夹',
                    labelPos: 'right',
                    type: 'checkbox',
                    default: false,
                    line: 'start',
                },
                save_folder: {
                    label: '设置文件夹',
                    labelPos: 'right',
                    type: 'button',
                    line: 'end',
                    click: function() {
                        setFolder();
                    }
                },
                reminder2: {
                    label: '温馨提示',
                    labelPos: 'right',
                    type: 'button',
                    click: function() {
                        alert('1、显示离线下载结果有10s延时,用于服务器响应时间。\n2、为避免通知弹窗过多,最多只显示3个视频搜索结果,更多请自行到115查看。\n3、“启用下载地址模糊匹配”后,能根据哈希值或纯文本模糊匹配磁力链接和迅雷专用链,如在磁力搜索引擎、资源网等有奇效,但在某些网页有一定几率误识别,请谨慎开启。');
                    }
                },
            },
            events: {
                save: function() {
                    GM_config.close();
                    location.reload();
                }
            },
        });
    }
    config();

    var G = GM_config;
    var localHref = window.location.href;
    var show_result = G.get('offline_result');
    var down_reg = /^(magnet|thunder|ftp|ed2k):/i;
    var UA = navigator.userAgent; // 使用浏览器默认UA
    var sign_url = 'http://115.com/?ct=offline&ac=space';
    var task_del = 'https://115.com/web/lixian/?ct=lixian&ac=task_del';
    var add_url = 'http://115.com/web/lixian/?ct=lixian&ac=add_task_url';
    var add_urls = 'http://115.com/web/lixian/?ct=lixian&ac=add_task_urls';
    var lists_url = 'http://115.com/web/lixian/?ct=lixian&ac=task_lists';
    var a_list = `<br><a target="_blank" class="openList" href="javascript:void(0);" style="color:blue;" title="点击打开离线链接任务列表">打开任务列表</a>`;
    console.log('115脚本UA:' + UA);

    // 通知样式
    function notice() {
        GM_addStyle(GM_getResourceText('toastrCss'));
        GM_addStyle('.toast{font-size:15px!important;width:360px!important;} .toast-title{font-size:16px!important;text-align:center}');
        toastr.options = {
            "closeButton": true,
            "debug": false,
            "progressBar": true,
            "timeOut": 8000,
            "extendedTimeOut": 8000,
            "positionClass": 'toast-top-right', // 固定右上角
            "allowHtml": true,
            "newestOnTop": false,
        };
    }
    notice();

    // AJAX请求
    function AjaxCall(href, callback) {
        GM_xmlhttpRequest({
            method: "GET",
            url: href,
            headers: {
                "User-Agent": UA,
                Origin: "https://115.com",
            },
            onload: function(data) {
                if (data.readyState == 4 && data.status == 200) {
                    var htmlTxt = data.responseText;
                    callback(null, htmlTxt);
                }
            },
            onerror: function(error) {
                callback(error);
            },
            ontimeout: function(error) {
                callback(error);
            },
        });
    }

    // 设置离线下载文件夹
    function setFolder() {
        var old_cid = GM_getValue('offlineFolder') || '';
        var new_cid = prompt('请输入离线下载保存文件夹的cid值:\n   ※ 获取cid值方法:打开需要保存到的网盘文件夹,复制地址栏中"cid="后面的一串数字,以"&"截止,如https://115.com/?cid=012345678912345678&...,cid值则为 012345678912345678。该项不填或填无效值则保存至默认文件夹(云下载)。※', old_cid);
        if (/^(\d{17,19}|0)$/.test(new_cid)) {
            GM_setValue('offlineFolder', new_cid);
            alert('设置成功,现cid值为:\n' + new_cid);
        } else if (new_cid == '') {
            GM_setValue('offlineFolder', '');
            alert('未输入cid值,保存至默认文件夹(云下载)。');
        } else if (new_cid == null) {
            console.log('已点击取消');
        } else {
            alert('设置失败,cid值无效,请重新输入!\n(该值除根目录为 0 外,其他文件夹均为17至19位纯数字)');
            setFolder();
        }
    }

    // 处理下载链接
    function getRightUrl(url) {
        var newUrl = url;
        if (/^thunder/i.test(url)) {
            var key = url.replace(/thunder:\/\//i, '');
            var temp = decode64(key);
            newUrl = decodeURIComponent(temp.slice(2, -2));
        }
        if (/^magnet/i.test(newUrl)) {
            var hash = newUrl.split('&')[0].substring(20) || newUrl.substring(20);
            if (hash.length == 32) {
                hash = base32To16(hash);
            }
            newUrl = 'magnet:?xt=urn:btih:' + hash;
        } else if (/^\/\//.test(url)) {
            newUrl = location.protocol + url;
        } else if (/^\/(?!\/)/.test(url)) {
            newUrl = location.protocol + '//' + location.host + url;
        }
        return newUrl;
    }

    // Base32转Base16
    function base32To16(str) {
        if (str.length % 8 !== 0 || /[0189]/.test(str)) {
            return str;
        }
        str = str.toUpperCase();
        var bin = "", newStr = "", i;
        for (i = 0; i < str.length; i++) {
            var charCode = str.charCodeAt(i);
            if (charCode < 65) charCode -= 24;
            else charCode -= 65;
            charCode = '0000' + charCode.toString(2);
            charCode = charCode.substr(charCode.length - 5);
            bin += charCode;
        }
        for (i = 0; i < bin.length; i += 4) {
            newStr += parseInt(bin.substring(i, i + 4), 2).toString(16);
        }
        return newStr;
    }

    // 检查重复链接
    function repeat(link) {
        var result = false;
        var A = link.slice(0, 60);
        if ($('.115offline').length == 0) return result;
        $('.115offline').each(function() {
            var B = $(this).data('href').slice(0, 60);
            if (A.toLowerCase() == B.toLowerCase()) {
                result = true;
                return false;
            }
        });
        return result;
    }

    // 搜索离线任务
    function searchTask(json, link) {
        var dataEl = false;
        for (var i = 0; i < json.tasks.length; i++) {
            if (json.tasks[i].url == link || json.tasks[i].url == decodeURIComponent(link)) {
                dataEl = json.tasks[i];
                break;
            }
        }
        return dataEl;
    }

    // 账号验证弹窗
    function verify() {
        var time = new Date().getTime();
        var w = 335;
        var h = 500;
        var t = (window.screen.availHeight - h) / 2;
        var l = (window.screen.availWidth - w) / 2;
        var link = 'https://captchaapi.115.com/?ac=security_code&type=web&cb=Close911_' + time;
        var a = confirm('立即打开验证账号弹窗?');
        if (a) {
            var blocked = false;
            try {
                var wroxWin = window.open(link, '请验证账号', 'height=' + h + ',width=' + w + ',top=' + t + ',left=' + l + ',toolbar=no,menubar=no,scrollbars=no,resizable=no,location=no,status=no');
                if (wroxWin == null) {
                    blocked = true;
                }
            } catch (e) {
                blocked = true;
            }
            if (blocked) {
                alert('验证弹窗已被拦截,请允许本页面弹出式窗口!');
            }
        }
    }

    // 离线下载核心逻辑
    var offline = function() {
        return {
            getSign: function(key, save_name) {
                return new Promise(function(resolve, reject) {
                    if (/^\w+=/.test(key)) {
                        resolve(key);
                        return;
                    }

                    var UserID = GM_getValue('115ID') || '';
                    var cid = G.get('diy_folder') ? GM_getValue('offlineFolder') : '';
                    var title = save_name ? save_name : '';
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: sign_url,
                        responseType: 'json',
                        headers: {
                            "User-Agent": UA,
                            Origin: "https://115.com",
                        },
                        onload: function(result) {
                            if (result.responseText.indexOf('html') != -1) {
                                toastr.error('请先登录115网盘账号!', '离线任务添加失败。');
                                setTimeout(function() {
                                    var a = confirm('立即打开115网盘登录页面?');
                                    if (a) {
                                        GM_openInTab('https://115.com/?mode=login', false);
                                    }
                                }, 3000);
                                return;
                            }
                            var data = {
                                uid: UserID,
                                sign: result.response.sign,
                                time: result.response.time,
                                wp_path_id: cid,
                                savepath: title
                            };

                            if ($.isPlainObject(key)) {
                                var value = $.param($.extend(data, key));
                            } else {
                                var value = $.param(data) + `&url=${key}`;
                            }
                            resolve(value);
                        },
                        onerror: function(error) {
                            reject(error);
                        },
                    });
                });
            },

            getData: function(herf, key, save_name) {
                return offline.getSign(key, save_name).then(function(value) {
                    return new Promise(function(resolve, reject) {
                        GM_xmlhttpRequest({
                            method: 'POST',
                            data: value,
                            url: herf,
                            responseType: 'json',
                            headers: {
                                "User-Agent": UA,
                                "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                                "Accept": "application/json, text/javascript, */*; q=0.01",
                                Origin: "https://115.com",
                                "X-Requested-With": "XMLHttpRequest"
                            },
                            onload: function(result) {
                                resolve(result.response);
                            },
                            onerror: function(error) {
                                reject(error);
                            },
                        });
                    });
                });
            },

            check: function(link, link2, one) {
                if (document.hidden) {
                    GM_setValue('noTimeOut', true);
                    toastr.options.timeOut = 0;
                } else {
                    GM_setValue('noTimeOut', false);
                    toastr.options.timeOut = 12000;
                }

                var c = 1;
                var retry = false;
                var txt2 = '5秒后自动重试,请稍等。';
                function add(retry, txt2) {
                    if (c == 6) {
                        console.log('离线结果查询异常。离线任务数量过多,请清空后再试。');
                        toastr.warning('离线任务数量过多,请清空后再试。', '离线结果查询异常!');
                        return;
                    }

                    var key = '';
                    var lists_url2 = lists_url + '&page=' + c;
                    console.log('离线任务数据地址:' + lists_url2);
                    offline.getData(lists_url2, key).then(function(json) {
                        console.log('离线任务列表第' + c + '页:');
                        console.log(json);
                        if (json.state) {
                            var dataEl = searchTask(json, link);
                            if (dataEl) {
                                var name = dataEl.del_path == '' ? dataEl.name : dataEl.del_path.slice(0, -1);
                                var a_del = `  <a target="_blank" class="delTask" data=${dataEl.info_hash} href="javascript:void(0);" style="color:blue;" title="删除该离线任务">删除任务</a>`;
                                if (dataEl.status != -1) {
                                    if (dataEl.move == -1) {
                                        toastr.warning('空间不足,请到115扩容', '离线下载异常!');
                                        return;
                                    }
                                    var down_result = dataEl.percentDone.toFixed(0);
                                    var cid = dataEl.file_id || 0;
                                    if (down_result >= 99 && cid != 0) {
                                        var txt = `文件(夹)名:${name},大小:${change(dataEl.size)}。`;
                                        resultMark(link2, 3);
                                        if (one) {
                                            console.log(txt + '离线下载已完成。');
                                            return;
                                        }

                                        if (show_result && !retry) {
                                            toastr.success(txt + a_list + a_del, '离线下载已完成', { timeOut: 5000 });
                                        }

                                        if (G.get('open_search')) {
                                            offline.search(dataEl.name, cid, function(search_result, video, j, num) {
                                                if (search_result) {
                                                    if (G.get('search_result')) {
                                                        var videoTxt = JSON.stringify(video);
                                                        var txt = `文件名:${video.name},大小:${video.size},时长:${tranTime(video.time)}。`;
                                                        var h1 = `<br><a target="_blank" class="115play" data=${videoTxt} href="javascript:void(0);" style="color:blue;" title="播放该视频">播放</a>`;
                                                        var h2 = `  <a target="_blank" class="115down" data=${videoTxt} one="1" href="javascript:void(0);" style="color:blue;" title="下载该视频">下载</a>`;
                                                        var h3 = `  <a target="_blank" class="115del" data=${videoTxt} href="javascript:void(0);" style="color:blue;" title="删除该视频文件夹">删除</a>`;
                                                        var h4 = `  <a target="_blank" class="115newName" data=${videoTxt} href="javascript:void(0);" style="color:blue;" title="重命名该视频">重命名</a>`;
                                                        var h5 = `  <a target="_blank" class="openFolder" data=${cid} href="javascript:void(0);" style="color:blue;" title="查看所属文件列表">查看</a>`;
                                                        toastr.success(txt + h1 + h2 + h3 + h4 + h5, `发现第 ${j} 个视频(共 ${num} 个)`);
                                                    }

                                                    if (G.get('open_Popup') && j == 1) {
                                                        setTimeout(function() {
                                                            var type = '115play';
                                                            palyData(video, type);
                                                        }, 500);
                                                    }
                                                } else {
                                                    if (dataEl.move == 2 || dataEl.move == 0 || dataEl.status == 0) {
                                                        var txt = '离线数据取回网盘中。';
                                                    } else {
                                                        var txt = '未发现任何视频文件。';
                                                    }
                                                    var h1 = `<br><a target="_blank" class="openFolder" data=${cid} href="javascript:void(0);" style="color:blue;" title="点击打开所属文件列表">打开文件列表</a>`;
                                                    toastr.warning(txt + txt2 + h1, '视频搜索无结果!');

                                                    if (!retry) {
                                                        setTimeout(function() {
                                                            retry = true;
                                                            txt2 = '';
                                                            toastr.clear();
                                                            console.log('重试搜索结果:');
                                                            add(retry, txt2);
                                                        }, 5000);
                                                    }
                                                }
                                            });
                                        }
                                    } else if (show_result) {
                                        resultMark(link2, 4);
                                        if (one) {
                                            console.log(`文件(夹)名:${name},已离线下载 ${down_result}%。`);
                                            return;
                                        }
                                        var txt = `文件(夹)名:${name},下载进度为:<span style="color:purple;">${down_result}%</span>。`;
                                        toastr.warning(txt + a_list + a_del, '离线下载中...');
                                    }
                                } else if (show_result) {
                                    resultMark(link2, 4);
                                    if (one) {
                                        console.log(`文件(夹)名:${name},离线下载失败。`);
                                        return;
                                    } else if (dataEl.err == 10016) {
                                        var txt = '文件含违规内容,已自动拦截。';
                                    } else {
                                        var txt = '未知原因,请到115网盘查看。';
                                        var a_del = '';
                                    }
                                    toastr.error(txt + a_list + a_del, '离线下载失败!', { timeOut: 8000 });
                                    return;
                                }
                            } else {
                                console.log('第' + c + '页查询失败,无匹配数据');
                                if (c == json.page_count) {
                                    console.log('离线链接对比异常,已搜索所有离线列表页面,无返回结果。');
                                    toastr.warning('搜索参数错误。', '离线结果查询异常!', { timeOut: 5000 });
                                    return;
                                }
                                c++;
                                add();
                            }
                        } else {
                            toastr.error('查询离线结果失败。', '服务器错误!');
                            return;
                        }
                    });
                }
                add(retry, txt2);
            },

            addButton: function() {
                $('[href]').each(function() {
                    var url = $(this).attr('href');
                    var reg1 = /\.(torrent|rar|zip|7z|mp4|rmvb|mkv|avi)$/i;
                    var $El = $(this).parent().filter('li,td,th,:header').find('[Searched]');

                    if ((!down_reg.test(url) && !reg1.test(url)) || $(this).is('[Searched]') || $El.length > 1 || ($El.length = 1 && url.indexOf($El.attr('Searched')) != -1)) {
                        return;
                    }

                    if (down_reg.test(url)) {
                        $(this).attr('Searched', url.split(':')[0]);
                    } else if (/torrent$/i.test(url)) {
                        $(this).attr('Searched', 'torrent');
                    } else {
                        $(this).attr('Searched', 'other');
                    }

                    var link = getRightUrl(url);
                    if (repeat(link)) {
                        return;
                    }

                    $(this).css('display', 'inline-block');
                    $(this).after('<img src="https://cdn.jsdelivr.net/gh/zxf10608/JavaScript/icon/115logo.ico" class="115offline" data-href=' + link + ' style="z-index:9123456789;display:inline-block;cursor:pointer;margin:0px 5px 2px;border-radius:50%;border:0px;vertical-align:middle;outline:none!important;padding:0px!important;height:20px!important;width:20px!important;left:0px!important;top:0px!important;" title="使用115网盘离线下载,右键复制地址\n' + link + '">');
                });
            },

            addLink: function() {
                $('a,button,span,li').each(function() {
                    var reg1 = /(^|\/|&|-|\.|\?|=|:|#|_|@)([a-f0-9]{40}|[a-z2-7]{32})(?!\w)/i;
                    var reg2 = /[a-z]{40}|[a-z]{32}/i;

                    if ($(this).next().addBack().is('[Searched],[href*="google"],[href*="motelppp.com"],[href*="bvmqkla.de"]') || $(this).find('img').length > 0) {
                        return;
                    }

                    var url = getAttribute(this);
                    if (url.length > 0) {
                        for (var i = 0; i < url.length; i++) {
                            if (down_reg.test(url[i]) || (reg1.test(url[i]) && !reg2.test(url[i].match(reg1)[2]))) {
                                if (down_reg.test(url[i])) {
                                    var value = url[i].split(':')[0];
                                    var templink = url[i];
                                } else {
                                    var value = 'magnet';
                                    var templink = 'magnet:?xt=urn:btih:' + url[i].match(reg1)[2];
                                }
                                var link = getRightUrl(templink);
                                if (repeat(link)) {
                                    return;
                                }
                                $(this).attr('Searched', value);
                                $(this).after('<img src="https://cdn.jsdelivr.net/gh/zxf10608/JavaScript/icon/115logo.ico" class="115offline" data-href=' + link + ' style="z-index:9123456789;display:inline-block;cursor:pointer;margin:0px 5px 2px;border-radius:50%;border:0px;vertical-align:middle;outline:none!important;padding:0px!important;height:20px!important;width:20px!important;left:0px!important;top:0px!important;" title="使用115网盘离线下载2,右键复制地址\n' + link + '">');
                                return;
                            }
                        }
                    }
                });
            },

            addSelect: function() {
                if ($('.115offline').length < 3) return;

                $('.115offline:not([Sed])').each(function() {
                    $(this).attr('Sed', 1);
                    var url = $(this).data('href');
                    $(this).after('<input type="checkbox" class="115select" value=' + url + ' title="长按shift键,连续选择" style="z-index:9123456789;display:inline-block;cursor:pointer;height:16px!important;width:16px!important;margin:0px 2px 1px;border-radius:50%;border:0px;vertical-align:middle;outline:none!important;padding:0px!important;left:0px!important;top:0px!important;" />');
                });

                var sel = $('.115offline').length > 10 ? $('.115select:eq(-1),.115select:eq(0)') : $('.115select:eq(-1)');
                sel.each(function() {
                    if ($(this).is('[batched]')) return;
                    $(this).attr('batched', 1);
                    $(this).after('<img src="https://cdn.jsdelivr.net/gh/zxf10608/JavaScript/icon/batch_down00.png" class="115offline_batch" style="z-index:9123456789;display:inline-block;cursor:pointer;margin:0px 1px 2px;border:0px;vertical-align:middle;outline:none!important;padding:0px!important;height:23px!important;width:23px!important;left:0px!important;top:0px!important;" title="使用115网盘批量离线下载所选地址,右键可全选等">');
                    $(this).parent().css('overflow', 'visible');
                });
            },

            search: function(name, cid, callback) {
                var title = new Array();
                title[0] = name.replace(/(\.|-|_)?(f?hd|sd|720p|1080p|full|mp4|avi|mkv|wmv|rmvb|rm|flv|f4v)/gi, ' ');
                title[1] = title[0].replace(/\/|&|-|\.|\?|=|:|#|_|@/g, ' ');
                title[2] = '.';

                var a = 0;
                function add2() {
                    if (a == 3) {
                        console.log('该文件夹无视频文件。');
                        callback(false);
                        return;
                    }
                    var searchLink = 'https://webapi.115.com/files/search?cid=' + cid + '&search_value=' + encodeURIComponent(title[a]) + '&type=4';
                    AjaxCall(searchLink, function(error, htmlTxt) {
                        if (typeof htmlTxt == 'undefined') {
                            a++;
                            add2();
                        } else {
                            var json = JSON.parse(htmlTxt);
                            if (a == 2 && json.folder.name == '云下载') {
                                callback(false);
                                return;
                            }

                            if (json.count > 0) {
                                var num = json.count;
                                for (var i = 0; i < num; i++) {
                                    var $dataEh = json.data[i];
                                    var video = {};
                                    video['name'] = name2($dataEh.n);
                                    video['pid'] = $dataEh.pc;
                                    video['cid'] = $dataEh.cid;
                                    video['fid'] = $dataEh.fid;
                                    video['size'] = change($dataEh.s);
                                    video['sha'] = $dataEh.sha;
                                    video['time'] = $dataEh.play_long;

                                    callback(true, video, i + 1, num);
                                    console.log('第' + a + '次搜索结果' + i + ':' + $dataEh.n + ' ' + video.size);
                                    if (i == 2) {
                                        return;
                                    }
                                }
                            } else {
                                a++;
                                add2();
                            }
                        }
                    });
                }
                add2();
            }
        };
    }();

    // 文件大小转换
    function change(number) {
        var size = "";
        if (number < 1024 * 1024 * 1024) {
            size = (number / (1024 * 1024)).toFixed(2) + "MB";
        } else {
            size = (number / (1024 * 1024 * 1024)).toFixed(2) + "GB";
        }
        var sizeStr = size + "";
        var index = sizeStr.indexOf(".");
        var dou = sizeStr.substr(index + 1, 2);
        if (dou == "00") {
            return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2);
        }
        return size;
    }

    // 文件名处理
    function name2(txt) {
        var newName = txt.replace(/\.(?!\w{2,4}$)/g, '_').replace(/\s/g, ' ');
        return newName;
    }

    // 时间转换
    function tranTime(num) {
        var showTime = '';
        if (num > 3600) { showTime += ' ' + parseInt(num / 3600) + ' 小时'; num = num % 3600; }
        if (num > 60) { showTime += ' ' + parseInt(num / 60) + ' 分'; num = num % 60; }
        return showTime += ' ' + parseInt(num) + ' 秒';
    }

    // 点击限制
    function clickOne(el, t) {
        var time = t ? t : 5000;
        if (el.attr('clicked') == 1) {
            console.log('5s内不可点击该按钮');
            return false;
        } else {
            el.attr('clicked', 1);
            el.css('opacity', '0.2');
            setTimeout(function() {
                el.attr('clicked', 0);
                el.css('opacity', '0.7');
            }, time);
            return true;
        }
    }

    // 标记结果
    function resultMark(el, type) {
        if (el.length == 0 || !show_result) return;

        var urls = [];
        var color = { 1: '#00CCFF', 2: '#DA70D6', 3: '#AEDD81', 4: '#EB7347' }[type];
        for (var i = 0; i < el.length; i++) {
            urls.push(el[i].url);
            $('.115offline').each(function() {
                var link = $(this).data('href');
                var $al = $(this).prev();
                var m = $al.attr('marked');
                if ((el[i].url == link || el[i].url == decodeURIComponent(link)) && m != 3) {
                    $al.attr('marked', type).css('background-color', color);
                    $al.find('[style]').removeAttr('style');
                    return false;
                }
            });
        }
        return urls;
    }

    // 获取属性
    function getAttribute(e) {
        var data = [];
        $.each(e.attributes, function() {
            if (this.specified && this.value.length > 30) {
                data.push(this.value);
            }
        });
        if ($(e).text().length > 25) data.push($(e).text());
        return data;
    }

    // 右键菜单
    function right_menu() {
        $('body').append(`
        <div class="115menu" style="width:97px;height:85px;z-index:9123456789;overflow:hidden;position:absolute;display:none;background-color:#D0D0D0">
            <ul style="padding:5px 7px;margin:0px;list-style:none;">
                <li><a href="javascript:;" class="right_menu00">全选</a></li>
                <li><a href="javascript:;" class="right_menu01">反选</a></li>
                <li><a href="javascript:;" class="right_menu02">复制所选</a></li>
                <li><a href="javascript:;" class="right_menu11">复制地址</a></li>
                <li><a href="javascript:;" class="right_menu12">种子下载1</a></li>
                <li><a href="javascript:;" class="right_menu13">种子下载2</a></li>
            </ul>
        </div>`);
        $('.115menu a').css({ 'line-height': '25px', 'text-decoration': 'none', 'color': '#2C3E50', 'padding': '1px 5px', 'font-size': '16px', 'font-family': 'arial' });
        $('.115menu a').hover(function() {
            $(this).css({ 'background-color': '#2777F8', 'color': '#FFF' });
        }, function() {
            $(this).css({ 'background-color': '', 'color': '#2C3E50' });
        });
    }

    // 播放视频
    function palyData(video, type) {
        var link = 'https://115.com/?ct=play&ac=location&pickcode=' + video.pid + '&hls=1';
        GM_openInTab(link, false);
    }

    // 文档加载事件
    $(document).ready(function() {
        if (localHref.indexOf('https://115.com/') != -1) {
            if (typeof (unsafeWindow.USER_ID) != 'undefined') {
                GM_setValue('115ID', unsafeWindow.USER_ID);
                console.log('115账号已登录,账号ID获取成功!');
            } else {
                console.log('115账号未登录,账号ID获取失败!');
            }
        }

        if (localHref.indexOf('https://captchaapi.115.com') != -1) {
            var t_close;
            $('body').on('click', '.vcode-hint', function() {
                t_close = setTimeout(function() {
                    console.log('验证正确');
                    window.open('', '_self');
                    window.close();
                }, 200);
                return false;
            });
            $('.vcode-hint').on('DOMNodeInserted', function(e) {
                console.log('验证错误!');
                clearTimeout(t_close);
            });
        }
    });

    // 主逻辑
    $(document).ready(function() {
        $(document).on('click', function(e) {
            $('.115menu').hide();
        });

        $('body').on('click', '.115offline', function(e) {
            if (!clickOne($(this))) return;
            var link = $(this).data('href');
            var save_name = '';
            offline.getData(add_url, link, save_name).then(function(json) {
                console.log('离线任务添加结果:');
                console.log(json);
                var errNum = json.errcode || json.error_code || '';
                var link2 = [{'url': link}];
                if (json.state) {
                    if (show_result) {
                        var txt = '10秒后显示离线结果。';
                    } else {
                        var txt = link;
                        if (G.get('open_List')) {
                            setTimeout(function() {
                                GM_openInTab('https://115.com/?tab=offline&mode=wangpan', false);
                            }, 2000);
                        }
                    }
                    resultMark(link2, 1);
                    toastr.info(txt, '离线任务添加成功。', { timeOut: 10000 });
                    setTimeout(function() {
                        offline.check(link, link2);
                    }, 10000);
                } else if (errNum == 10008) {
                    toastr.warning('任务已存在,无需重复添加。', '离线任务添加无效!', { timeOut: 5000 });
                    if (G.get('open_List')) {
                        setTimeout(function() {
                            GM_openInTab('https://115.com/?tab=offline&mode=wangpan', false);
                        }, 2000);
                    }
                    resultMark(link2, 1);
                    offline.check(link, link2);
                } else if (errNum == 911) {
                    toastr.warning('账号异常,请验证账号。', '离线下载失败!', { timeOut: 5000 });
                    setTimeout(function() {
                        verify();
                    }, 1000);
                } else {
                    resultMark(link2, 2);
                    toastr.warning(json.error_msg, '离线任务添加失败!', { timeOut: 12000 });
                }
                console.log('离线链接:' + link + ' 添加结果:' + json.state + ' 原因:' + json.error_msg);
            }, function(error) {
                toastr.error('服务器繁忙,请稍后再试。', '离线任务添加异常!');
                console.log(error);
            });
            return false;
        });

        $('body').on('click', '.115offline_batch', function() {
            var l = $('.115select:checked').length;
            if (l < 10 && !clickOne($('.115offline_batch'))) {
                return;
            } else if (l < 2 || l > 100) {
                toastr.warning('单次选中数量限 <span style="color:red;">2-99</span> 个。', '批量离线操作无效!', { timeOut: 6000 });
                return;
            } else if (l > 10) {
                toastr.info('所选中地址较多,服务器需要较长时间响应,请稍等10s以上,未弹出结果前勿重复点击。', '温馨提示。', { timeOut: 10000 });
                if (!clickOne($('.115offline_batch'), 10000)) return;
            }

            var links = {};
            $('.115select:checked').each(function(e) {
                links['url[' + e + ']'] = $(this).attr('value');
            });

            offline.getData(add_urls, links).then(function(json) {
                console.log('批量离线任务添加结果:');
                console.log(json);
                var errNum = json.errcode || json.error_code || '';

                if (json.state) {
                    var s = 0, e = 0, f = 0;
                    var success_result = [], exist_result = [], all_result = [], fail_result = [];
                    for (var n = 0; n < json.result.length; n++) {
                        var dataEl = json.result[n];
                        if (dataEl.state) {
                            s++;
                            success_result.push(dataEl);
                            all_result.push(dataEl);
                        } else if (dataEl.errcode == 10008) {
                            e++;
                            exist_result.push(dataEl);
                            all_result.push(dataEl);
                        } else {
                            f++;
                            fail_result.push(dataEl);
                        }
                    }

                    var txt2 = '10秒后显示离线结果。';
                    var error = fail_result.length > 0 ? fail_result[0].error_msg : '任务已存在';
                    if (f + e == json.result.length) {
                        var txt1 = `有 <span style="color:red;">${f + e}</span> 个任务创建失败,原因:${error}。`;
                        toastr.warning(txt1 + a_list, '批量离线任务添加失败。', { timeOut: 10000 });
                    } else if (f + e > 0) {
                        if (e > 0) txt2 = '新建任务' + txt2;
                        var txt1 = `有 <span style="color:purple;">${s}</span> 个任务创建成功。有 <span style="color:red;">${f + e}</span> 个任务创建失败,原因:${error}。`;
                        toastr.info(txt1 + txt2 + a_list, '批量离线任务添加成功。', { timeOut: 10000 });
                    } else {
                        var txt1 = `有 <span style="color:purple;">${s}</span> 个任务创建成功。`;
                        toastr.info(txt1 + txt2 + a_list, '批量离线任务添加成功。', { timeOut: 10000 });
                    }

                    var success_links = resultMark(success_result, 1);
                    var exist_links = resultMark(exist_result, 1);
                    resultMark(fail_result, 2);

                    if (s + e > 20) {
                        toastr.warning('离线数量大于20,请自行到115查看。' + a_list, '未查询离线结果!', { timeOut: 6000 });
                        return;
                    }

                    if (s > 0) {
                        setTimeout(function() {
                            for (let h = 0; h < s; h++) {
                                var one = (all_result[0].url == success_links[h]) ? false : true;
                                var url2 = [{'url': success_links[h]}];
                                offline.check(success_links[h], url2, one);
                            }
                        }, 10000);
                    }
                    if (e > 0) {
                        for (let i = 0; i < e; i++) {
                            var one = (all_result[0].url == exist_links[i]) ? false : true;
                            var url2 = [{'url': exist_links[i]}];
                            offline.check(exist_links[i], url2, one);
                        }
                    }

                    if (f != json.result.length && G.get('open_List')) {
                        setTimeout(function() {
                            GM_openInTab('https://115.com/?tab=offline&mode=wangpan', false);
                        }, 2000);
                    }
                } else if (errNum == 911) {
                    toastr.warning('账号异常,请验证账号。', '批量离线下载失败!', { timeOut: 5000 });
                    setTimeout(function() {
                        verify();
                    }, 1000);
                } else {
                    toastr.warning(json.error_msg + a_list, '批量离线任务添加失败!', { timeOut: 12000 });
                }
            }, function(error) {
                toastr.error('服务器繁忙,请稍后再试。', '批量离线任务添加异常!');
                console.log(error);
            });
            return false;
        });

        $('body').on('click', '.115select', function(e) {
            if (e.shiftKey) {
                var first = $('.115select').index($('.115select:checked').first());
                var me = $('.115select').index($(this));
                var last = $('.115select').index($('.115select:checked').last());
                var Min = Math.min(first, me, last);
                var Max = Math.max(first, me, last);

                for (var i = Min; i <= Max; i++) {
                    $('.115select').eq(i).prop('checked', true);
                }
            }
        });

        $('body').on('click', '.openList:not([click="1"]), .openFolder:not([click="1"])', function() {
            $(this).attr('click', '1');
            if ($(this).is('.openList')) {
                var txt = 'tab=offline';
            } else {
                var fID = $(this).attr('data');
                var txt = 'cid=' + fID + '&offset=0';
            }
            GM_openInTab('https://115.com/?' + txt + '&mode=wangpan', false);
            return false;
        });

        $('body').on('contextmenu', '.115offline, .115offline_batch', function(e) {
            $('.115menu').css({ left: e.pageX + 'px', top: e.pageY + 'px' });
            $('.115menu').show();
            var link = $(this).data('href') || '';
            if ($(this).is('.115offline_batch')) {
                $('.115menu [class^="right_menu0"]').show();
                $('.115menu [class^="right_menu1"]').hide();
            } else if (/^magnet/i.test(link)) {
                $('.115menu').attr('data-href', link);
                $('.115menu [class^="right_menu1"]').show();
                $('.115menu [class^="right_menu0"]').hide();
            } else {
                $('.115menu').hide();
                GM_setClipboard(link);
                toastr.success('下载地址复制成功!');
            }
            return false;
        });

        $('body').on('click', '[class^="right_menu0"]', function() {
            if ($(this).is('.right_menu00')) {
                $('.115select').prop('checked', true);
            } else if ($(this).is('.right_menu01')) {
                $('.115select').each(function() {
                    if ($(this).prop('checked')) {
                        $(this).prop('checked', false);
                    } else {
                        $(this).prop('checked', true);
                    }
                });
            } else {
                if ($('.115select:checked').length == 0) {
                    toastr.warning('复制失败,未选中任何链接!');
                    return;
                }
                var urls = [];
                $('.115select:checked').each(function() {
                    urls.push($(this).attr('value'));
                });
                GM_setClipboard(urls.join('\r\n'));
                toastr.success(urls.length + ' 个下载地址复制成功!');
            }
            return false;
        });

        $('body').on('click', '[class^="right_menu1"]', function() {
            var link = $(this).parents('.115menu').data('href');
            var hash = link.match(/[a-f0-9]{40}/i)[0].toUpperCase();
            if ($(this).is('.right_menu11')) {
                GM_setClipboard(link);
                toastr.success('下载地址复制成功!');
            } else if ($(this).is('.right_menu12')) {
                GM_openInTab(`https://itorrents.org/torrent/${hash}.torrent`, false);
            } else if ($(this).is('.right_menu13')) {
                GM_openInTab(`https://btcache.me/torrent/${hash}`, false);
            }
            return false;
        });

        if (G.get('offline_Down') && localHref.indexOf('115.com') == -1) {
            if (localHref.match(/[0-9]mag\.net|yuhuage/) != null) {
                right_menu();
                var time1 = setInterval(function() {
                    offline.addButton();
                    if ($('.115offline').length >= 20) {
                        clearInterval(time1);
                    }
                }, 500);
                setTimeout(function() {
                    offline.addSelect();
                    $('.mag1').remove();
                    clearInterval(time1);
                }, 5000);
            } else if (localHref.match(/www\.gying\./) != null) {
                right_menu();
                if (localHref.match(/\/bt\//) != null) {
                    setTimeout(function() {
                        offline.addLink();
                        offline.addSelect();
                    }, 500);
                } else {
                    var time2 = setInterval(function() {
                        if ($('.torrent').length > 0) {
                            offline.addButton();
                            offline.addSelect();
                            clearInterval(time2);
                        }
                        if ($('.torrent').length == 0) {
                            clearInterval(time2);
                        }
                    }, 1500);
                }
            } else {
                var time3 = 300;
                if (localHref.match(/av/) != null) {
                    time3 = 3000;
                }
                setTimeout(function() {
                    offline.addButton();
                    if (localHref.match(/av/) != null) {
                        $('.movie td').removeAttr('onclick');
                    }
                }, time3);
                if (G.get('fuzzy_find')) {
                    setTimeout(function() {
                        offline.addLink();
                    }, time3 + 10);
                }
                setTimeout(function() {
                    right_menu();
                    offline.addSelect();
                    $('.mag1').remove();
                }, time3 + 20);
            }
        }
    });
})();