// ==UserScript== // @name 115优化大师 // @author zxf10608 // @version 2.0 // @namespace https://greasyfork.org/zh-CN/scripts/408466 // @icon https://115.com/favicon.ico // @description 任意浏览器自由登录、一键离线下载、调用Dplayer播放视频、调用Potplayer本地播放、文件快捷下载等功能 // @require https://cdn.bootcss.com/jquery/3.5.1/jquery.min.js // @require https://greasyfork.org/scripts/398240-gm-config-zh-cn/code/GM_config_zh-CN.js // @require https://greasyfork.org/scripts/408457-fec115/code/fec115.js // @require https://greasyfork.org/scripts/408462-js-xxhash/code/js-xxhash.js // @require https://openuserjs.org/src/libs/zxf10608/elliptic.js // @require https://cdn.bootcdn.net/ajax/libs/toastr.js/2.1.4/toastr.min.js // @resource toastrCss https://cdn.bootcdn.net/ajax/libs/toastr.js/2.1.4/toastr.min.css // @require https://cdn.bootcdn.net/ajax/libs/crc-32/1.2.0/crc32.min.js // @require https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.16.0/js/md5.min.js // @require https://cdn.bootcdn.net/ajax/libs/aes-js/3.1.2/index.min.js // @require https://cdn.bootcdn.net/ajax/libs/jsSHA/2.4.2/sha1.js // @require https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js // @resource Dplayercss https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.css // @require https://cdn.jsdelivr.net/npm/hls.js@0.14.3/dist/hls.min.js // @require https://cdn.jsdelivr.net/npm/lz4@0.6.4/build/lz4.min.js // @require https://cdn.jsdelivr.net/npm/js-md4@0.3.2/src/md4.min.js // @require https://cdn.jsdelivr.net/npm/compare-versions@3.6.0/index.js // @include * // @exclude http*://*.baidu.com* // @grant GM_log // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // @grant GM_openInTab // @grant GM_getResourceText // @grant GM_xmlhttpRequest // @grant unsafeWindow // @grant GM_registerMenuCommand // @grant GM_xmlhttpRequest // @connect 115.com // @grant window.open // @grant window.close // @run-at document-start // @compatible chrome // @license MIT License // @downloadURL none // ==/UserScript== (function() { 'use strict'; if ( typeof (GM_config) == 'undefined') { alert('115优化大师:相关库文件加载失败,脚本无法使用,请刷新网页重新加载!'); return false; } else { console.log('115优化大师:相关库文件加载成功'); }; function config(){ var windowcss = ' #Cfg .config_var {margin-left: 10%;margin-right: 10%;} #Cfg input[type="checkbox"] {margin: 3px 3px 3px 0px;} #Cfg input[type="text"] {width: 50px;} #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: 'https://greasyfork.org/zh-CN/scripts/408466', target: '_blank', textContent: '115优化大师', title: '作者:zxf10608 版本:v2.0 点击访问主页' }), isTabs: true, skin: 'tab', css: windowcss, frameStyle: { height: '420px', width: '425px', zIndex:'2147483648', }, fields: { account_Login: { section: ['登录管理', '修改登录模式,实现自由登录'], label: '启用帐号登录', labelPos: 'right', type: 'checkbox', default: true, }, hide_qrcodeLogin: { label: '隐藏二维码登录', labelPos: 'right', type: 'checkbox', default: false, }, hide_officeLogin: { label: '隐藏115组织登录', labelPos: 'right', type: 'checkbox', default: false, }, login_Alidity: { label: '登录有效期', labelPos: 'left', type: 'select', options: ['1天', '7天', '30天'], default: '7天', }, show_Alidity: { label: '显示登录有效截止时间', labelPos: 'right', type: 'checkbox', default: false, }, reminder: { label: '温馨提示', labelPos: 'right', type: 'button', click: function() { alert('登录有效期仅对以“帐号登录”生效。'); } }, 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', }, reminder2: { label: '温馨提示', labelPos: 'right', type: 'button', click: function() { alert('显示离线下载结果有10s延时,用于服务器响应时间。'); } }, open_Dplayer: { section: ['视频播放', '调用第三方播放器,优化播放体验'], label: '启用Dplayer播放', labelPos: 'right', type: 'checkbox', default: true, }, play_Number: { label: '播放记录最大保存数量', labelPos: 'left', type: 'select', 'options': ['0', '15', '30'], default: '15', }, skip_titles: { label: '跳过片头秒数', type: 'unsigned int', default: '0', }, skip_credits: { label: '跳过片尾秒数', type: 'unsigned int', default: '0', }, reminder3: { label: '温馨提示', labelPos: 'right', type: 'button', click: function() { alert('1、播放记录最大保存数量设置为“0”,可关闭记忆播放或清空播放记录。\n 2、播放界面右键可显示更多功能菜单,谨慎使用“删除”操作。'); } }, hide_sidebar: { section: ['更多设置', '优化浏览体验'], label: '隐藏侧边栏', labelPos: 'right', type: 'checkbox', default: false, }, file_Down: { label: '启用文件快捷下载', labelPos: 'right', type: 'checkbox', default: true, }, open_Potplayer: { label: '启用Potplayer播放', labelPos: 'right', type: 'checkbox', default: false, }, }, events: { save: function() { GM_config.close(); } }, }); }; config(); var login = function(){ var Buffer, LZ4, LoginEncrypt_, browserInterface, bytesToHex, bytesToString, cloneInto, dictToForm, dictToQuery, ec115_compress_decode, ec115_decode, ec115_decode_aes, ec115_encode_data, ec115_encode_token, ec115_init, elliptic, g_ver, get_key, md4, md4_init, preLoginEncrypt, ref, sig_calc, sig_init, stringToBytes; g_ver = '8.3.0.25'; Buffer = require('buffer').Buffer; LZ4 = require('lz4'); elliptic = window.elliptic; md4 = window.md4; stringToBytes = function(s) { var i, l, ref, ret; ret = []; for (i = l = 0, ref = s.length; (0 <= ref ? l < ref : l > ref); i = 0 <= ref ? ++l : --l) { ret.push(s.charCodeAt(i)); } return ret; }; bytesToString = function(b) { var i, l, len1, ret; ret = ''; for (l = 0, len1 = b.length; l < len1; l++) { i = b[l]; ret += String.fromCharCode(i); } return ret; }; bytesToHex = function(b) { var l, len1, ret, t; ret = ''; for (l = 0, len1 = b.length; l < len1; l++) { t = b[l]; ret += (t >> 4).toString(16); ret += (t & 0xf).toString(16); } return ret; }; ec115_init = function() { var Q, c, key, keys, pub; c = new elliptic.ec('p224'); keys = c.genKeyPair(); pub = [0x1d].concat(keys.getPublic(true, true)); Q = c.keyFromPublic('0457A29257CD2320E5D6D143322FA4BB8A3CF9D3CC623EF5EDAC62B7678A89C91A83BA800D6129F522D034C895DD2465243ADDC250953BEEBA'.toLowerCase(), 'hex'); key = (keys.derive(Q.getPublic())).toArray(); return {pub, key}; }; ec115_encode_token = function(pub, tm, cnt) { var i, l, m, o, q, r20, r21, tmp, tmp2; r20 = Math.floor(Math.random() * 256); r21 = Math.floor(Math.random() * 256); tmp = Buffer.alloc(48); for (i = l = 0; l < 15; i = ++l) { tmp[i] = pub[i] ^ r20; } tmp[15] = r20; tmp.writeInt32LE(115, 16); tmp.writeInt32LE(tm, 20); for (i = m = 16; m < 24; i = ++m) { tmp[i] ^= r20; } for (i = o = 24; o < 39; i = ++o) { tmp[i] = pub[i - 9] ^ r21; } tmp[39] = r21; tmp.writeInt32LE(cnt, 40); for (i = q = 40; q < 44; i = ++q) { tmp[i] ^= r21; } tmp2 = Buffer.concat([Buffer.from('^j>WD3Kr?J2gLFjD4W2y@'), tmp.slice(0, 44)]); tmp.writeInt32LE(CRC32.buf(tmp2), 44); return tmp.toString('base64'); }; ec115_encode_data = function(data, key) { var aesEcb, i, j, k, key1, key2, l, n, part, rets, tmp; key1 = key.slice(0, 16); key2 = key.slice(-16); aesEcb = new aesjs.ModeOfOperation.ecb(key1); tmp = stringToBytes(data); n = tmp.length; j = 0; rets = []; while (n > 0) { part = Buffer.alloc(16); for (i = l = 0; l < 16; i = ++l) { k = n <= 0 ? 0 : tmp[i + j]; part[i] = key2[i] ^ k; --n; } key2 = aesEcb.encrypt(part); rets.push(Buffer.from(key2)); j += 16; } return Buffer.concat(rets); }; ec115_decode_aes = function(data, key) { var aesCbc, i, iv, key1, ret; key1 = key.slice(0, 16); iv = key.slice(-16); aesCbc = new aesjs.ModeOfOperation.cbc(key1, iv); ret = aesCbc.decrypt(data); i = ret.length; while (i > 0 && ret[i - 1] === 0) { --i; } return Buffer.from(ret.buffer, ret.byteOffset, i); }; ec115_compress_decode = function(data) { var len, p, r, rets, tmp; p = 0; rets = []; while (p < data.length) { len = data.readInt16LE(p) + 2; if (p + len > data.length) { return null; } tmp = Buffer.alloc(0x2000); r = LZ4.decodeBlock(data.slice(p + 2, p + len), tmp); if (r < 0) { return null; } rets.push(tmp.slice(0, r)); p += len; } return Buffer.concat(rets); }; get_key = function(data_buf) { var i, l, p, ret, t; p = 0; ret = Buffer.alloc(40); for (i = l = 0; l < 40; i = ++l) { t = data_buf.readInt32LE(p); p = t + 1; ret[i] = data_buf[t]; } return ret; }; md4_init = function(pSig) { var ret; ret = md4.create(); ret.h0 = pSig.readInt32LE(4); ret.h1 = pSig.readInt32LE(8); ret.h2 = pSig.readInt32LE(12); ret.h3 = pSig.readInt32LE(16); ret.first = false; return ret; }; sig_init = function(body) { var data_buf, data_buf_p, dhash, md4h, ori_data_p, pSig, sz; ori_data_p = Module._malloc(body.length); Module.HEAPU8.set(body, ori_data_p); data_buf_p = Module._malloc(body.length); sz = Module.ccall('calc_out', 'number', ['number', 'number', 'number'], [ori_data_p, body.length, data_buf_p]); Module._free(ori_data_p); data_buf = Buffer.from(Module.buffer, data_buf_p, sz); pSig = get_key(data_buf); md4h = md4_init(pSig); md4h.update(data_buf); dhash = md4h.digest(); return {data_buf, data_buf_p, pSig, dhash}; }; sig_calc = function({data_buf, data_buf_p, pSig, dhash}, src) { var h1, h1_p, h2, h2b, i, l, md4h, out_data, out_data_p, pad, ret, sz, xxh; xxh = XXH.h64(); xxh.init(pSig.readUInt32LE(8)); xxh.update(src); h2 = xxh.digest().toString(16); pad = '0000000000000000'; h2b = Buffer.from(pad.slice(0, 16 - h2.length) + h2, 'hex').swap64(); md4h = md4_init(pSig); md4h.update(dhash); md4h.update(src); md4h.update(h2b); md4h.update(pSig); h1 = new Uint8Array(md4h.buffer()); h1_p = Module._malloc(16); Module.HEAPU8.set(h1, h1_p); out_data_p = Module._malloc(0x10000); sz = Module.ccall('encode', 'number', ['number', 'number', 'number', 'number', 'number', 'number', 'number'], [data_buf_p, data_buf.length / 2, h1_p, 16, out_data_p, 8, 10]); Module._free(data_buf_p); Module._free(h1_p); out_data = new Uint8Array(Module.buffer, out_data_p, sz); md4h = md4_init(pSig); md4h.update(out_data); ret = md4h.digest(); Module._free(out_data_p); ret.push(pSig[0]); for (i = l = 36; l < 40; i = ++l) { ret.push(pSig[i]); } return bytesToHex(ret); }; ec115_decode = function(data, key) { var dec, unzip; dec = data[data.length - 12 + 5]; unzip = data[data.length - 12 + 4]; data = data.slice(0, -12); if (dec === 1) { data = ec115_decode_aes(data, key); } if ((data != null) && unzip === 1) { data = ec115_compress_decode(data); } return data; }; dictToQuery = function(dict) { var k, tmp, v; tmp = []; for (k in dict) { v = dict[k]; tmp.push(`${encodeURIComponent(k)}=${encodeURIComponent(v)}`); } return tmp.join('&'); }; dictToForm = function(dict) { var k, tmp, v; tmp = []; for (k in dict) { v = dict[k]; tmp.push(`${k}=${v}`); } return tmp.join('&'); }; LoginEncrypt_ = function({account, passwd, environment, goto, login_type}, g, {pub, key}, sig) { var data, fake, tm, tmus, token; tmus = (new Date()).getTime(); tm = Math.floor(tmus / 1000); fake = md5(account); token = ec115_encode_token(pub, tm, 1); data = ec115_encode_data(dictToForm({ GUID: fake.slice(0, 20), account: account, device: 'GhostXP', device_id: fake.slice(2, 14).toUpperCase(), device_type: 'windows', disk_serial: fake.slice(0, 8).toUpperCase(), dk: '', environment: environment, goto: goto, login_source: '115chrome', network: '5', passwd: passwd, sign: md5(`${account}${tm}`), system_info: ` ${fake[1]}${fake[0]}${fake[3]}${fake[2]}${fake[5]}${fake[4]}${fake[7]}${fake[6]}`.toUpperCase(), time: tm, login_type: login_type, signew: 1, sign115: sig_calc(sig, md5(`${account}${tm}`)) }), key); return GM_xmlhttpRequest({ method: 'POST', url: `http://passport.115.com/?ct=encrypt&ac=login&k_ec=${token}`, data: GM_info.scriptHandler === 'Violentmonkey' && compareVersions.compare(GM_info.version, 'v2.12.2', '<') ? new Blob([data.buffer], { type: 'application/octet-binary' }) : data.toString('latin1'), binary: true, responseType: 'arraybuffer', headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, onerror: function(response) { return GM_log(`response.status = ${response.status}, response.statusText = ${response.statusText}`); }, onload: function(response) { var date, datestr, json; if (response.status === 200) { data = Buffer.from(response.response); data = ec115_decode(data, key); if (data != null) { json = JSON.parse(data.toString('latin1')); if (json.state && (json.data != null)) { date = new Date(); date.setTime(date.getTime() + day * 32 * 3600 * 1000); datestr = date.toUTCString(); var time = date.Format("yyyy-MM-dd HH:mm:ss"); GM_setValue('login_Last',time); document.cookie = `UID=${json.data.cookie.UID}; expires=${datestr}; path=/; domain=115.com`; document.cookie = `CID=${json.data.cookie.CID}; expires=${datestr}; path=/; domain=115.com`; document.cookie = `SEID=${json.data.cookie.SEID}; expires=${datestr}; path=/; domain=115.com`; document.cookie = `OOFL=${json.data.user_id}; expires=${datestr}; path=/; domain=115.com`; delete json.data; } return unsafeWindow[g](JSON.stringify(json)); } else { return GM_log('data is null'); } } else { return GM_log(`response.status = ${response.status}`); } } }); }; preLoginEncrypt = function(n, g) { var key, pub, tm, tmus, token; tmus = (new Date()).getTime(); tm = Math.floor(tmus / 1000); ({pub, key} = ec115_init()); token = ec115_encode_token(pub, tm, 0); return GM_xmlhttpRequest({ method: 'GET', url: `https://passportapi.115.com/app/2.0/web/${g_ver}/login/sign?k_ec=${token}`, responseType: 'arraybuffer', anonymous: true, onerror: function(response) { return GM_log(`response.status = ${response.status}, response.statusText = ${response.statusText}`); }, onload: function(response) { var body, data, error, json, sig; if (response.status === 200) { data = Buffer.from(response.response); data = ec115_decode(data, key); if (data != null) { json = JSON.parse(data.toString('latin1')); if (json.state) { body = Buffer.from(json.sign, 'base64'); try { sig = sig_init(body); return LoginEncrypt_(JSON.parse(n), g, {pub, key}, sig); } catch (error1) { error = error1; return GM_log(`${error.message}\n${error.stack}`); } } else { return GM_log(JSON.stringify(json)); } } else { return GM_log('data is null'); } } else { return GM_log(`response.status = ${response.status}`); } } }); }; browserInterface = (ref = unsafeWindow.browserInterface) != null ? ref : {}; browserInterface.LoginEncrypt = function(n, g) { var error; try { return preLoginEncrypt(n, g); } catch (error1) { error = error1; return GM_log(`${error.message}\n${error.stack}`); } }; browserInterface.GetBrowserVersion = function() { return new String(g_ver); }; browserInterface.ChromeGetIncognitoState = function() { return false; }; if (typeof cloneInto !== 'function') { cloneInto = function(x) { return x; }; } unsafeWindow.browserInterface = cloneInto(browserInterface, unsafeWindow, { cloneFunctions: true }); }; var G = GM_config; var localHref = window.location.href; var sign_url = 'http://115.com/?ct=offline&ac=space'; var add_url = 'http://115.com/web/lixian/?ct=lixian&ac=add_task_url'; var lists_url = 'http://115.com/web/lixian/?ct=lixian&ac=task_lists'; GM_addStyle(GM_getResourceText("toastrCss")); toastr.options = { "closeButton": true, "debug": false, "progressBar": true, "timeOut": "3000", "extendedTimeOut": "2000", "allowHtml": true, "newestOnTop" : false, }; function AjaxCall(href,callback) { GM_xmlhttpRequest({ method: "GET", url: href, onload: function(data,status) { 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 download(key){ var href = 'https://webapi.115.com/files/download?pickcode='+key; AjaxCall(href,function(error,htmlTxt) { var json = JSON.parse(htmlTxt); console.log('文件下载信息:'); console.log(json); if(json.state) { var link = json.file_url.replace(/\\/g,''); GM_openInTab(link,false); console.log('下载地址:'+link); } else { toastr.warning(json.msg,'下载失败!'); }; }); }; function palyData(video){ GM_setValue('videoInfo',video); var herfLink = 'https://115.com/api/video/m3u8/'+video.pid+'.m3u8'; AjaxCall(herfLink,function(error,htmlTxt) { if (typeof (htmlTxt) == 'undefined') { toastr.warning('视频转码中或非VIP会员','播放失败!'); return }; var dataList = htmlTxt.split('\n'); var m3u8 = []; var temp = '"YH"|原画|"BD"|4K|"UD"|蓝光|"HD"|超清|"SD"|高清|"3G"|标清'; var txt = temp.split('|'); for (var i=0; i<6; i++){ dataList.forEach(function (e,j,arr) { if (e.indexOf(txt[i*2])!= -1) { m3u8.push({name: txt[i*2+1], url: arr[j+1].replace(/\r/,''), type: 'hls'}); }; }); }; GM_setValue('m3u8List',m3u8); GM_openInTab('http://115.com/web/lixian',false); }); }; 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 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 enterPiP(videoEl){ if(document.pictureInPictureEnabled && !videoEl.disablePictureInPicture) { if (!document.pictureInPictureElement) { videoEl.requestPictureInPicture(); }else{ document.exitPictureInPicture(); }; }else{ alert('浏览器不支持或已关闭画中画功能!'); }; }; if(localHref.indexOf('https://115.com/') != -1) { if (G.get('account_Login')){ if (G.get('login_Alidity') =='1天'){ var day = 1; } else if(G.get('login_Alidity') =='7天'){ var day = 7; } else { var day = 30; }; if ( typeof (require) == 'undefined') { alert('115优化大师:帐号登录库文件加载失败,该功能无法使用,请刷新网页重新加载!'); return false; }; Date.prototype.Format = function (fmt) { var o = { "M+": this.getMonth() + 1, "d+": this.getDate(), "H+": this.getHours() + 8, "m+": this.getMinutes(), "s+": this.getSeconds(), "q+": Math.floor((this.getMonth() + 3) / 3), "S": this.getMilliseconds() }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return fmt; }; login(); }; $(document).ready(function(){ if (typeof (unsafeWindow.USER_ID) != 'undefined') { GM_setValue('115ID', unsafeWindow.USER_ID); var UserID = GM_getValue('115ID'); console.log('115账号已登录,账号ID获取成功!'); } else { if (G.get('hide_officeLogin')){ $('.ltab-office').hide(); }; if (G.get('hide_qrcodeLogin')){ $('.login-scene,.login-footer span:eq(0),.login-footer i:eq(0)').hide(); $('[lg_rel="login"]').show(); } else if ($('[lgb-nav="download"]').length > 0) { $('[lgb-nav="download"]').attr('lgb-nav','login'); }; console.log('115账号未登录,账号ID获取失败!'); }; if (G.get('hide_sidebar')){ $('.sub-core').hide(); setTimeout(function(){ $('.main-core').css({'left':'16px','top':'16px'}); },50); }; if (G.get('file_Down')){ var herfd = 'li[rel="item"][file_type="1"]:not([down_button="1"])'; $('body').on('mouseenter',herfd,function(){ var tempEl = $(this).attr('down_button', '1'); tempEl.find('.file-opr [menu="download_one"]').hide(); tempEl.find('.file-opr').prepend('快捷下载'); }); $('body').on('click','.Down',function(){ var El = $(this).parents('li'); var pickcode = El.attr('pick_code'); download(pickcode); return false; }); }; if (G.get('open_Potplayer') || G.get('open_Dplayer')){ var herfv = 'li[rel="item"][file_type="1"][file_mode="9"]:not([paly_button="1"])'; $('body').on('mouseenter',herfv,function(){ var tempEl = $(this).attr('paly_button', '1'); var txt0 = ['Pot','Dp']; var txt1 = ['使用Potplayer播放视频','使用Dplayer播放视频']; var txt2 = ['Pot播放','Dp播放']; for (var i=0; i<2; i++){ tempEl.find('.file-opr').prepend(''); }; if (G.get('open_Potplayer')){ $('.Pot').show(); }; if (G.get('open_Dplayer')){ $('.Dp').show(); }; }); }; if (G.get('open_Potplayer')){ $('body').on('click', '.Pot',function () { var El = $(this).parents('li'); var pickcode = El.attr('pick_code'); var herfLink = 'https://115.com/api/video/m3u8/' + pickcode + '.m3u8'; AjaxCall(herfLink,function(error,htmlTxt) { if (typeof (htmlTxt) == 'undefined') { alert('播放失败,视频转码中或非VIP会员'); return }; var m3u8Link = htmlTxt.split('\n').slice(2).toString().replace(/\r/, ''); console.log('m3u8地址:'+ m3u8Link); window.location.href = 'potplayer://'+m3u8Link; }); return false; }); }; if (G.get('open_Dplayer')){ $('body').on('click', '.Dp',function () { var El = $(this).parents('li'); var video = {}; video['name'] = El.attr('title').replace(/\s*/g, ''); video['pid'] = El.attr('pick_code'); video['fid1'] = El.attr('cid'); video['fid2'] = El.attr('file_id'); video['size'] = change(El.attr('file_size')); palyData(video); return false; }); }; }); }; if(localHref.indexOf('https://115.com/?cid=0&offset=0&mode=wangpan') != -1) { //var rsc = setInterval(function(){ window.onload=function(){ //clearInterval(rsc); var errorLink = GM_getValue('error'); if (typeof (errorLink) != 'undefined'){ GM_setValue('error',''); unsafeWindow.Core.OFFL5Plug.OpenLink(); setTimeout(function() { $('#js_offline_new_add').val(errorLink); setTimeout(function() { console.log('已点击!'); }, 500); }, 50); }else if (G.get('show_Alidity')){ var loginTime= GM_getValue('login_Last'); if (typeof (unsafeWindow.USER_ID) != 'undefined') { toastr.success(loginTime, '登录有效期为'); } else { toastr.warning('其他方式登录,未知有效期!', '登录有效期为'); }; }; }; //}, 3000); }; if(localHref.indexOf('http://115.com/web/lixian') != -1 ) { var m3u8 = GM_getValue('m3u8List'); var video = GM_getValue('videoInfo'); var titleTxt = video.name; var pickID = video.pid; var folderID = video.fid1; var videoID = video.fid2; var size = video.size; var jsonList = GM_getValue('palyList'); if (!jsonList){ var jsonList = {}; }; var curTime = jsonList[pickID]; if (curTime){ delete jsonList[pickID]; }; var skipTime = G.get('skip_titles'); var skipTime2 = G.get('skip_credits'); $('pre').remove(); $('head').html(`${titleTxt} ${size}`); GM_addStyle(`html,body,div{margin:0;padding:0;border:0;outline:0;background:transparent}`); GM_addStyle(GM_getResourceText('Dplayercss')); $('body').append('
'); function playVideo(m3u8) { if(m3u8.length >1){ var z = 1; }else{ var z = 0; }; var dp = new DPlayer({ container: $('#Dplayer')[0], screenshot: true, volume: 1, video: { quality: m3u8, defaultQuality: z, }, contextmenu: [{ text: '下载视频', click: function(t) { download(pickID); } },{ text: '删除视频', click: function(t) { offline.del(videoID); } },{ text: '打开文件夹', click: function(t) { GM_openInTab(`https://115.com/?cid=${folderID}&offset=0&mode=wangpan`,false); } },{ text: '删除文件夹', click: function(t) { if (folderID==0){ alert('根目录,不可删除!'); return ; }; offline.del(folderID); } },{ text: '开启画中画', click: function(t) { enterPiP(t.video) } }], }); unsafeWindow.dp = dp; $('.dplayer-setting-loop,.dplayer-mobile-play,.dplayer-menu-item:gt(-3)').hide(); $('.dplayer-menu').css('width','98px'); dp.on('loadstart', function () { dp.notice('视频加载中,请稍等。', 1000); }); var a = 0; dp.on('loadeddata', function () { dp.notice('视频加载完成,即将播放。', 1000); a = a+1; if( a==1){ setTimeout(function(){ if (curTime && curTime > skipTime){ dp.seek(curTime); dp.notice('已跳转到上次观看进度'+tranTime(curTime), 2500); }else if(skipTime>0){ dp.seek(skipTime); dp.notice('已跳过片头'+skipTime+'秒', 2500); }; if(m3u8.length >1){ setTimeout(function(){ dp.notice('本视频支持切换清晰度', 2500); }, 3000); }; dp.play(); }, 1000); }; }); dp.on('timeupdate', function () { if ((dp.video.duration - dp.video.currentTime > 30) && dp.video.currentTime > 30) { jsonList[pickID] = dp.video.currentTime; var setNum = G.get('play_Number'); var saveNum = Object.keys(jsonList).length; if (saveNum > parseInt(setNum)){ var palyOld = JSON.stringify(jsonList).split('"')[1]; delete jsonList[palyOld]; }; }else{ delete jsonList[pickID]; }; GM_setValue('palyList',jsonList); if(0< skipTime2 && (dp.video.duration - dp.video.currentTime) <= skipTime2){ dp.pause(); dp.notice('已跳过片尾'+skipTime2+'秒', 2500); setTimeout(function(){ alert('视频已播放结束!'); }, 2000); }; }); dp.on('error', function () { alert('视频加载失败!'); return }); dp.on('ended', function () { alert('视频已播放结束!'); }); }; playVideo(m3u8); }; var offline = function(){ return { getSign:function () { return new Promise(function(resolve, reject){ var time = Date.now(); GM_xmlhttpRequest({ method: 'GET', url: sign_url, onload: function(response) { if (response.responseText.indexOf('html')!= -1) { toastr.error('请先登录115网盘账号!','离线任务添加失败!'); setTimeout(function(){ GM_openInTab('https://115.com/?mode=login',false); }, 3000); return; }; var json = JSON.parse(response.responseText); resolve(json); }, onerror: function(error) { reject(error); }, }); }); }, param2:function (data,e) { if (typeof e != 'undefined'){ return e; }; var res = ''; for(var key in data){ var value = data[key]; res += '&' + encodeURIComponent( key ) + "=" + encodeURIComponent( value ); }; return res.slice(1); }, getData:function (url,herf,e) { var UserID = GM_getValue('115ID'); return offline.getSign().then(function(json){ return new Promise(function(resolve, reject){ var data = { uid: UserID, sign: json.sign, time: json.time, url: url }; GM_xmlhttpRequest({ method: 'POST', data: offline.param2(data,e), url: herf, headers: { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Accept": "application/json, text/javascript, */*; q=0.01", Origin: "http://115.com", "X-Requested-With": "XMLHttpRequest" }, onload: function(response) { var json = JSON.parse(response.responseText); resolve(json); }, onerror: function(error) { reject(error); }, }); }); }); }, del:function (key) { var url = ''; var del_url ='https://webapi.115.com/rb/delete'; var fidInfo = 'fid='+key; offline.getData(url,del_url,fidInfo).then(function(json){ console.log('文件删除结果:'); console.log(json); if(json.state) { alert('删除成功,可从回收站还原。'); setTimeout(function(){ window.opener=null; window.open('','_self'); window.close(); }, 1000); } else { alert('删除失败:'+json.error); }; }); }, search:function (name,fid1,offlined,callback){ var title = name.replace(/(\.|-|_)?(mp4|avi|rmvb|mkv|wmv|f?hd|sd)/gi,' '); var title2 = title.replace(/\.|-|_|@/g,' '); var searchLink = 'https://webapi.115.com/files/search?cid='+fid1+'&search_value='+encodeURIComponent(title)+'%20'+encodeURIComponent(title)+'&type=4'; console.log('搜索链接:'+searchLink); AjaxCall(searchLink,function(error,htmlTxt) { if (typeof htmlTxt == 'undefined'){ toastr.warning('搜索关键词异常,无返回数据。','视频搜索失败!',{timeOut:6000}); return; }; var json = JSON.parse(htmlTxt); if (!json.state) { console.log('视频搜索失败,原因:'+json.error); return; }; console.log('视频搜索结果:'); console.log(json); if(json.count > 0) { var num= json.data.length; for(var i=0; i= 99){ if (show_result) { var txtTemp = `文件(夹)名:${dataEl.name},大小:${change(dataEl.size)},点击此处打开任务列表。`; var txt = `${txtTemp}`; toastr.success(txt, '离线下载已完成',{timeOut:5000}); }; if (G.get('open_search')) { var name = dataEl.name; var fid1 = dataEl.file_id; offline.search(name,fid1,offlined,function(search_result,pickcode,fileName,fid2,size,time,j,num) { if (search_result) { var video = {'name':fileName,'pid':pickcode,'fid1':fid1,'fid2':fid2,'size':size}; if (G.get('search_result')) { var txtTemp = `视频:${fileName},大小:${size},时间:${tranTime(time)},点击此处播放视频。`; var note = `${txtTemp}`; var noteTitle = `发现第${j}个视频(共${num}个)`; toastr.success(note,noteTitle,{timeOut:8000}); $('.'+pickcode).off('click'); $('.'+pickcode+':not([click="1"])').on('click',function(){ $(this).attr('click', '1'); palyData(video); return false; }); }; if (G.get('open_Popup') && j==1){ setTimeout(function(){ palyData(video); }, 500); }; }else { if(offlined){ var txtTemp = '视频可能已被重命名或删除,请自行到115查看或删除离线任务重试!点击此处打开文件列表。'; }else{ var txtTemp = '视频名称不规则或无视频文件,请自行到115查看!点击此处打开文件列表。'; }; toastr.options.onclick = function(){ GM_openInTab(`https://115.com/?cid=${folderID}&offset=0&mode=wangpan`,false); }; toastr.warning(txtTemp, '未发现视频!',{timeOut:8000}); console.log(name+' 无搜索结果!'); return; }; }); }; }else if(show_result) { var txtTemp = `文件名:${dataEl.name},下载进度为:${down_result}%,点击此处打开任务列表。`; var txt = `${txtTemp}`; toastr.warning(txt, '离线下载中。',{timeOut:8000}); console.log(`文件名:${dataEl.name},下载进度为:${down_result}%`); }; }else if(show_result) { var txt = `未知原因,请到115查看。点击此处打开任务列表。`; toastr.error(txt,'离线下载失败',{timeOut:8000}); return; }; }; }; }else{ toastr.error('查询离线结果失败。','服务器错误!',{timeOut:5000}); return; }; }); }, }; }(); $('body').on('click','.open115:not([click="1"])',function(){ $(this).attr('click', '1'); GM_openInTab('https://115.com/?tab=offline&mode=wangpan',false); return false; }); $('body').on('click','.offline_logo',function(){ var link = $(this).data('href'); offline.getData(link,add_url).then(function(json){ console.log('离线任务添加结果:'); console.log(json); if(json.state) { if (G.get('offline_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); }; }; toastr.info(txt, '离线任务添加成功。'); setTimeout(function(){ var offlined = false; offline.check(offlined,link) }, 10000); } else if (json.errcode == 10008){ toastr.warning('任务已存在,无需重复添加。','离线任务添加无效!'); if (G.get('open_List')){ setTimeout(function(){ GM_openInTab('https://115.com/?tab=offline&mode=wangpan',false); }, 2000); }; var offlined = true; offline.check(offlined,link); } else if (json.errcode == 911){ toastr.warning('账号异常,请手动添加一次离线任务用于验证帐号。','离线失败,请验证账号!'); GM_setValue('error',link); setTimeout(function(){ GM_openInTab('https://115.com/?cid=0&offset=0&mode=wangpan',false); }, 2000); } else { toastr.warning(json.error_msg,'离线任务添加失败!'); }; console.log('离线链接:'+link+ ' 添加结果:' +json.state+ ' 原因:' +json.error_msg); return }, function(error) { toastr.error('服务器繁忙,请稍后再试。','离线任务添加异常!'); console.log(error); }); return false; }); function addButton(){ var supportHref = 'a[href^="magnet:"],[href^="ed2k:"],a[href^="thunder:"],[href^="ftp:"],[href$=".torrent"],[href$=".rar"],[href$=".7z"],[href$=".zip"],[href$=".mp4"],[href$=".rmvb"],[href$=".mkv"],[href$=".avi"],[href$=".iso"]'; $(supportHref).each(function(){ if ($(this).attr('offline_button')){ console.log('已添加离线按钮'); return; }; $(this).attr('offline_button', true); var link = $(this).attr('href'); $(this).attr('style','display:inline-block;'); $(this).after(''); }); }; if (G.get('offline_Down')){ $(document).ready(function(){ if (localHref.match(/[0-9]mag.net/) != null) { var trigger; $('body').on('mouseenter mouseleave','a:not([offline_button="true"])',function(event){ if(event.type == 'mouseenter'){ trigger = setTimeout(function(){ addButton(); }, 200); }else if(event.type == 'mouseleave'){ clearTimeout(trigger); }; }); } else if(localHref.match(/pianku/) != null) { $('body').on('click','.torrent',function(){ setTimeout(function(){ addButton(); },50); }); } else { setTimeout(function(){ addButton(); },100); }; }); }; })();