Greasy Fork is available in English.

115优化大师

115网盘升级登录,延长登录有效期、一键离线下载、调用Dplayer或Potplayer播放视频、文件快捷下载等。

اعتبارا من 11-10-2020. شاهد أحدث إصدار.

  1. // ==UserScript==
  2. // ==UserScript==
  3. // @name 115优化大师
  4. // @author zxf10608
  5. // @version 3.3.1
  6. // @icon https://115.com/favicon.ico
  7. // @namespace https://greasyfork.org/zh-CN/scripts/408466
  8. // @description 115网盘升级登录,延长登录有效期、一键离线下载、调用Dplayer或Potplayer播放视频、文件快捷下载等。
  9. // @require https://cdn.bootcss.com/jquery/3.5.1/jquery.min.js
  10. // @require https://greasyfork.org/scripts/398240-gm-config-zh-cn/code/GM_config_zh-CN.js
  11. // @require https://greasyfork.org/scripts/412267-base64-v1-0/code/base64_v10.js
  12. // @require https://openuserjs.org/src/libs/zxf10608/fec115.js
  13. // @require https://openuserjs.org/src/libs/zxf10608/js-xxhash.js
  14. // @require https://openuserjs.org/src/libs/zxf10608/elliptic.js
  15. // @require https://cdn.jsdelivr.net/npm/toastr@2.1.4/toastr.min.js
  16. // @resource toastrCss https://cdn.jsdelivr.net/npm/toastr@2.1.4/build/toastr.min.css
  17. // @require https://cdn.bootcdn.net/ajax/libs/crc-32/1.2.0/crc32.min.js
  18. // @require https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.16.0/js/md5.min.js
  19. // @require https://cdn.bootcdn.net/ajax/libs/aes-js/3.1.2/index.min.js
  20. // @require https://cdn.bootcdn.net/ajax/libs/jsSHA/2.4.2/sha1.js
  21. // @require https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js
  22. // @resource dplayerCss https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.css
  23. // @require https://cdn.jsdelivr.net/npm/hls.js@0.14.14/dist/hls.min.js
  24. // @require https://cdn.jsdelivr.net/npm/lz4@0.6.4/build/lz4.min.js
  25. // @require https://cdn.jsdelivr.net/npm/js-md4@0.3.2/src/md4.min.js
  26. // @require https://cdn.jsdelivr.net/npm/compare-versions@3.6.0/index.js
  27. // @include *
  28. // @exclude http*://*.baidu.com/*
  29. // @exclude http*://*.jb51.*
  30. // @exclude http*://*.iqiyi.com/*
  31. // @exclude http*://*.qq.com/*
  32. // @exclude http*://v.youku.com/*
  33. // @exclude http*://*.bilibili.com/
  34. // @exclude http*://*.pptv.com/*
  35. // @exclude http*://*.fun.tv/*
  36. // @exclude http*://*.sohu.com/*
  37. // @exclude http*://*.le.com/*
  38. // @exclude http*://*.tudou.com/*
  39. // @exclude http*://www.bilibili.com/*
  40. // @exclude http*://music.163.com/*
  41. // @exclude http*://github.com/*
  42. // @exclude http*://www.sojson.com/*
  43. // @grant GM_log
  44. // @grant GM_setValue
  45. // @grant GM_getValue
  46. // @grant GM_addStyle
  47. // @grant GM_openInTab
  48. // @grant GM_setClipboard
  49. // @grant GM_getResourceText
  50. // @grant GM_xmlhttpRequest
  51. // @grant GM_registerMenuCommand
  52. // @grant GM_xmlhttpRequest
  53. // @connect 115.com
  54. // @grant unsafeWindow
  55. // @grant window.open
  56. // @grant window.close
  57. // @run-at document-start
  58. // @compatible chrome
  59. // @license GPL License
  60. // ==/UserScript==
  61.  
  62. (function() {
  63. 'use strict';
  64. var newVersion = 'v3.3';
  65. if ( typeof GM_config == 'undefined') {
  66. alert('115优化大师:\n网络异常,相关库文件加载失败,脚本无法使用,请刷新网页重新加载!');
  67. return;
  68. } else {
  69. console.log('115优化大师:相关库文件加载成功!');
  70. };
  71. function config(){
  72. 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: 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;}';
  73. GM_registerMenuCommand('设置', opencfg);
  74. function opencfg(){
  75. GM_config.open();
  76. };
  77. GM_config.init(
  78. {
  79. id: 'Cfg',
  80. title: GM_config.create('a', {
  81. href: 'https://greasyfork.org/zh-CN/scripts/408466',
  82. target: '_blank',
  83. textContent: '115优化大师',
  84. title: '作者:zxf10608 版本:'+newVersion+' 点击访问主页'
  85. }),
  86. isTabs: true,
  87. skin: 'tab',
  88. css: windowCss,
  89. frameStyle:
  90. {
  91. height: '430px',
  92. width: '425px',
  93. zIndex:'2147483648',
  94. },
  95. fields:
  96. {
  97. account_Login:
  98. {
  99. section: ['登录管理', '升级登录,延长登录有效期'],
  100. label: '升级帐号登录',
  101. labelPos: 'right',
  102. type: 'checkbox',
  103. default: true,
  104. },
  105. hide_qrcodeLogin:
  106. {
  107. label: '隐藏二维码登录',
  108. labelPos: 'right',
  109. type: 'checkbox',
  110. default: false,
  111. },
  112. hide_officeLogin:
  113. {
  114. label: '隐藏115组织登录',
  115. labelPos: 'right',
  116. type: 'checkbox',
  117. default: false,
  118. },
  119. login_Alidity:
  120. {
  121. label: '登录有效期',
  122. labelPos: 'left',
  123. type: 'select',
  124. options: ['1天', '7天', '30天'],
  125. default: '7天',
  126. },
  127. show_Alidity:
  128. {
  129. label: '显示登录有效截止时间',
  130. labelPos: 'right',
  131. type: 'checkbox',
  132. default: false,
  133. },
  134. reminder:
  135. {
  136. label: '温馨提示',
  137. labelPos: 'right',
  138. type: 'button',
  139. click: function() {
  140. alert('1、升级账号登录,方可设置登录有效期。\n2、常用帐号登录,建议关闭“两步验证”,效果更佳。');
  141. }
  142. },
  143. offline_Down:
  144. {
  145. section: ['离线升级', '升级离线下载功能'],
  146. label: '启用一键离线下载',
  147. labelPos: 'right',
  148. type: 'checkbox',
  149. default: true,
  150. },
  151. offline_result:
  152. {
  153. label: '任务添加后显示离线结果',
  154. labelPos: 'right',
  155. type: 'checkbox',
  156. default: true,
  157. },
  158. open_List:
  159. {
  160. label: '离线后自动打开任务列表',
  161. labelPos: 'right',
  162. type: 'checkbox',
  163. default: false,
  164. },
  165. open_search:
  166. {
  167. label: '离线成功后开启视频搜索',
  168. labelPos: 'right',
  169. type: 'checkbox',
  170. default: true,
  171. line: 'start',
  172. },
  173. search_result:
  174. {
  175. label: '显示视频搜索结果',
  176. labelPos: 'right',
  177. type: 'checkbox',
  178. default: true,
  179. },
  180. open_Popup:
  181. {
  182. label: '搜到视频自动播放',
  183. labelPos: 'right',
  184. type: 'checkbox',
  185. default: false,
  186. line: 'end',
  187. },
  188. fuzzy_find:
  189. {
  190. label: '开启下载地址模糊匹配',
  191. labelPos: 'right',
  192. type: 'checkbox',
  193. default: false,
  194. },
  195. reminder2:
  196. {
  197. label: '温馨提示',
  198. labelPos: 'right',
  199. type: 'button',
  200. click: function() {
  201. alert('1、显示离线下载结果有10s延时,用于服务器响应时间。\n2、为避免通知弹窗过多,最多只显示3个视频搜索结果,更多请自行到115查看。\n3、“开启下载地址模糊匹配”后,能根据哈希值或纯文本模糊匹配磁力链接和迅雷专用链,如在磁力搜索引擎、资源网等有奇效,但在某些网页有一定几率误识别,请谨慎开启。');
  202. }
  203. },
  204. player:
  205. {
  206. section: ['播放优化', '调用第三方播放器,优化播放体验'],
  207. label: '默认播放器',
  208. labelPos: 'left',
  209. type: 'select',
  210. options: ['Dplayer', 'Potplayer', '官方HTML5'],
  211. default: 'Dplayer',
  212. },
  213. play_Quality:
  214. {
  215. label: '默认播放清晰度',
  216. labelPos: 'left',
  217. type: 'select',
  218. 'options': ['最高', '次高', '最低'],
  219. default: '次高',
  220. },
  221. play_Number:
  222. {
  223. label: '保存播放进度',
  224. labelPos: 'left',
  225. type: 'select',
  226. 'options': ['0条', '20条', '50条'],
  227. default: '20条',
  228. },
  229. skip_titles:
  230. {
  231. label: '跳过片头秒数',
  232. type: 'unsigned int',
  233. default: '0',
  234. },
  235. skip_credits:
  236. {
  237. label: '跳过片尾秒数',
  238. type: 'unsigned int',
  239. default: '0',
  240. },
  241. Tab_ing:
  242. {
  243. label: '播放器跟随页面变化',
  244. labelPos: 'right',
  245. type: 'checkbox',
  246. default: false,
  247. },
  248. reminder3:
  249. {
  250. label: '温馨提示',
  251. labelPos: 'right',
  252. type: 'button',
  253. click: function() {
  254. alert('1、除第一、第二项外,其他仅在启用Dplayer时有效。\n2、保存播放进度设为0条,可关闭记忆播放或清空播放进度。\n3、播放界面右键可显示更多菜单,谨慎使用“删除”操作。\n4、播放器跟随页面变化,即页面后台则暂停,前台页面则播放,支持Dplayer和官方HTML5。\n5、关于播放器调用说明:\n 单击文件名:默认播放器;\n 双击除文件名外:官方HTML5;\n 单击“Dp播放”:Dplayer;\n 单击“Pot播放”:Potplayer;\n 非115页面:默认播放器。');
  255. }
  256. },
  257. hide_sidebar:
  258. {
  259. section: ['更多设置', '优化浏览体验'],
  260. label: '隐藏网盘侧边栏',
  261. labelPos: 'right',
  262. type: 'checkbox',
  263. default: false,
  264. },
  265. show_Star:
  266. {
  267. label: '网盘顶部显示星标',
  268. labelPos: 'right',
  269. type: 'checkbox',
  270. default: true,
  271. },
  272. file_Down:
  273. {
  274. label: '启用文件快捷下载',
  275. labelPos: 'right',
  276. type: 'checkbox',
  277. default: true,
  278. line: 'start',
  279. },
  280. show_sha:
  281. {
  282. label: '下载后显示文件校验码',
  283. labelPos: 'right',
  284. type: 'checkbox',
  285. default: false,
  286. line: 'end',
  287. },
  288. toastr:
  289. {
  290. label: '通知弹出位置',
  291. labelPos: 'left',
  292. type: 'select',
  293. 'options': ['左上', '右上', '中上','全铺'],
  294. default: '右上',
  295. },
  296. },
  297. events:
  298. {
  299. save: function() {
  300. GM_config.close();
  301. }
  302. },
  303. });
  304. };
  305. config();
  306. function login(day){
  307. 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;
  308. g_ver = '8.3.0.25';
  309. Buffer = require('buffer').Buffer;
  310. LZ4 = require('lz4');
  311. elliptic = window.elliptic;
  312. md4 = window.md4;
  313. stringToBytes = function(s) {
  314. var i, l, ref, ret;
  315. ret = [];
  316. for (i = l = 0, ref = s.length; (0 <= ref ? l < ref : l > ref); i = 0 <= ref ? ++l : --l) {
  317. ret.push(s.charCodeAt(i));
  318. }
  319. return ret;
  320. };
  321. bytesToString = function(b) {
  322. var i, l, len1, ret;
  323. ret = '';
  324. for (l = 0, len1 = b.length; l < len1; l++) {
  325. i = b[l];
  326. ret += String.fromCharCode(i);
  327. }
  328. return ret;
  329. };
  330. bytesToHex = function(b) {
  331. var l, len1, ret, t;
  332. ret = '';
  333. for (l = 0, len1 = b.length; l < len1; l++) {
  334. t = b[l];
  335. ret += (t >> 4).toString(16);
  336. ret += (t & 0xf).toString(16);
  337. }
  338. return ret;
  339. };
  340. ec115_init = function() {
  341. var Q, c, key, keys, pub;
  342. c = new elliptic.ec('p224');
  343. keys = c.genKeyPair();
  344. pub = [0x1d].concat(keys.getPublic(true, true));
  345. Q = c.keyFromPublic('0457A29257CD2320E5D6D143322FA4BB8A3CF9D3CC623EF5EDAC62B7678A89C91A83BA800D6129F522D034C895DD2465243ADDC250953BEEBA'.toLowerCase(), 'hex');
  346. key = (keys.derive(Q.getPublic())).toArray();
  347. return {pub, key};
  348. };
  349. ec115_encode_token = function(pub, tm, cnt) {
  350. var i, l, m, o, q, r20, r21, tmp, tmp2;
  351. r20 = Math.floor(Math.random() * 256);
  352. r21 = Math.floor(Math.random() * 256);
  353. tmp = Buffer.alloc(48);
  354. for (i = l = 0; l < 15; i = ++l) {
  355. tmp[i] = pub[i] ^ r20;
  356. }
  357. tmp[15] = r20;
  358. tmp.writeInt32LE(115, 16);
  359. tmp.writeInt32LE(tm, 20);
  360. for (i = m = 16; m < 24; i = ++m) {
  361. tmp[i] ^= r20;
  362. }
  363. for (i = o = 24; o < 39; i = ++o) {
  364. tmp[i] = pub[i - 9] ^ r21;
  365. }
  366. tmp[39] = r21;
  367. tmp.writeInt32LE(cnt, 40);
  368. for (i = q = 40; q < 44; i = ++q) {
  369. tmp[i] ^= r21;
  370. }
  371. tmp2 = Buffer.concat([Buffer.from('^j>WD3Kr?J2gLFjD4W2y@'), tmp.slice(0, 44)]);
  372. tmp.writeInt32LE(CRC32.buf(tmp2), 44);
  373. return tmp.toString('base64');
  374. };
  375. ec115_encode_data = function(data, key) {
  376. var aesEcb, i, j, k, key1, key2, l, n, part, rets, tmp;
  377. key1 = key.slice(0, 16);
  378. key2 = key.slice(-16);
  379. aesEcb = new aesjs.ModeOfOperation.ecb(key1);
  380. tmp = stringToBytes(data);
  381. n = tmp.length;
  382. j = 0;
  383. rets = [];
  384. while (n > 0) {
  385. part = Buffer.alloc(16);
  386. for (i = l = 0; l < 16; i = ++l) {
  387. k = n <= 0 ? 0 : tmp[i + j];
  388. part[i] = key2[i] ^ k;
  389. --n;
  390. }
  391. key2 = aesEcb.encrypt(part);
  392. rets.push(Buffer.from(key2));
  393. j += 16;
  394. }
  395. return Buffer.concat(rets);
  396. };
  397. ec115_decode_aes = function(data, key) {
  398. var aesCbc, i, iv, key1, ret;
  399. key1 = key.slice(0, 16);
  400. iv = key.slice(-16);
  401. aesCbc = new aesjs.ModeOfOperation.cbc(key1, iv);
  402. ret = aesCbc.decrypt(data);
  403. i = ret.length;
  404. while (i > 0 && ret[i - 1] === 0) {
  405. --i;
  406. }
  407. return Buffer.from(ret.buffer, ret.byteOffset, i);
  408. };
  409. ec115_compress_decode = function(data) {
  410. var len, p, r, rets, tmp;
  411. p = 0;
  412. rets = [];
  413. while (p < data.length) {
  414. len = data.readInt16LE(p) + 2;
  415. if (p + len > data.length) {
  416. return null;
  417. }
  418. tmp = Buffer.alloc(0x2000);
  419. r = LZ4.decodeBlock(data.slice(p + 2, p + len), tmp);
  420. if (r < 0) {
  421. return null;
  422. }
  423. rets.push(tmp.slice(0, r));
  424. p += len;
  425. }
  426. return Buffer.concat(rets);
  427. };
  428. get_key = function(data_buf) {
  429. var i, l, p, ret, t;
  430. p = 0;
  431. ret = Buffer.alloc(40);
  432. for (i = l = 0; l < 40; i = ++l) {
  433. t = data_buf.readInt32LE(p);
  434. p = t + 1;
  435. ret[i] = data_buf[t];
  436. }
  437. return ret;
  438. };
  439. md4_init = function(pSig) {
  440. var ret;
  441. ret = md4.create();
  442. ret.h0 = pSig.readInt32LE(4);
  443. ret.h1 = pSig.readInt32LE(8);
  444. ret.h2 = pSig.readInt32LE(12);
  445. ret.h3 = pSig.readInt32LE(16);
  446. ret.first = false;
  447. return ret;
  448. };
  449. sig_init = function(body) {
  450. var data_buf, data_buf_p, dhash, md4h, ori_data_p, pSig, sz;
  451. ori_data_p = Module._malloc(body.length);
  452. Module.HEAPU8.set(body, ori_data_p);
  453. data_buf_p = Module._malloc(body.length);
  454. sz = Module.ccall('calc_out', 'number', ['number', 'number', 'number'], [ori_data_p, body.length, data_buf_p]);
  455. Module._free(ori_data_p);
  456. data_buf = Buffer.from(Module.buffer, data_buf_p, sz);
  457. pSig = get_key(data_buf);
  458. md4h = md4_init(pSig);
  459. md4h.update(data_buf);
  460. dhash = md4h.digest();
  461. return {data_buf, data_buf_p, pSig, dhash};
  462. };
  463. sig_calc = function({data_buf, data_buf_p, pSig, dhash}, src) {
  464. var h1, h1_p, h2, h2b, i, l, md4h, out_data, out_data_p, pad, ret, sz, xxh;
  465. xxh = XXH.h64();
  466. xxh.init(pSig.readUInt32LE(8));
  467. xxh.update(src);
  468. h2 = xxh.digest().toString(16);
  469. pad = '0000000000000000';
  470. h2b = Buffer.from(pad.slice(0, 16 - h2.length) + h2, 'hex').swap64();
  471. md4h = md4_init(pSig);
  472. md4h.update(dhash);
  473. md4h.update(src);
  474. md4h.update(h2b);
  475. md4h.update(pSig);
  476. h1 = new Uint8Array(md4h.buffer());
  477. h1_p = Module._malloc(16);
  478. Module.HEAPU8.set(h1, h1_p);
  479. out_data_p = Module._malloc(0x10000);
  480. 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]);
  481. Module._free(data_buf_p);
  482. Module._free(h1_p);
  483. out_data = new Uint8Array(Module.buffer, out_data_p, sz);
  484. md4h = md4_init(pSig);
  485. md4h.update(out_data);
  486. ret = md4h.digest();
  487. Module._free(out_data_p);
  488. ret.push(pSig[0]);
  489. for (i = l = 36; l < 40; i = ++l) {
  490. ret.push(pSig[i]);
  491. }
  492. return bytesToHex(ret);
  493. };
  494. ec115_decode = function(data, key) {
  495. var dec, unzip;
  496. dec = data[data.length - 12 + 5];
  497. unzip = data[data.length - 12 + 4];
  498. data = data.slice(0, -12);
  499. if (dec === 1) {
  500. data = ec115_decode_aes(data, key);
  501. }
  502. if ((data != null) && unzip === 1) {
  503. data = ec115_compress_decode(data);
  504. }
  505. return data;
  506. };
  507. dictToQuery = function(dict) {
  508. var k, tmp, v;
  509. tmp = [];
  510. for (k in dict) {
  511. v = dict[k];
  512. tmp.push(`${encodeURIComponent(k)}=${encodeURIComponent(v)}`);
  513. }
  514. return tmp.join('&');
  515. };
  516. dictToForm = function(dict) {
  517. var k, tmp, v;
  518. tmp = [];
  519. for (k in dict) {
  520. v = dict[k];
  521. tmp.push(`${k}=${v}`);
  522. }
  523. return tmp.join('&');
  524. };
  525. LoginEncrypt_ = function({account, passwd, environment, goto, login_type}, g, {pub, key}, sig) {
  526. var data, fake, tm, tmus, token;
  527. tmus = (new Date()).getTime();
  528. tm = Math.floor(tmus / 1000);
  529. fake = md5(account);
  530. token = ec115_encode_token(pub, tm, 1);
  531. data = ec115_encode_data(dictToForm({
  532. GUID: fake.slice(0, 20),
  533. account: account,
  534. device: 'GhostXP',
  535. device_id: fake.slice(2, 14).toUpperCase(),
  536. device_type: 'windows',
  537. disk_serial: fake.slice(0, 8).toUpperCase(),
  538. dk: '',
  539. environment: environment,
  540. goto: goto,
  541. login_source: '115chrome',
  542. network: '5',
  543. passwd: passwd,
  544. sign: md5(`${account}${tm}`),
  545. system_info: ` ${fake[1]}${fake[0]}${fake[3]}${fake[2]}${fake[5]}${fake[4]}${fake[7]}${fake[6]}`.toUpperCase(),
  546. time: tm,
  547. login_type: login_type,
  548. signew: 1,
  549. sign115: sig_calc(sig, md5(`${account}${tm}`))
  550. }), key);
  551. return GM_xmlhttpRequest({
  552. method: 'POST',
  553. url: `http://passport.115.com/?ct=encrypt&ac=login&k_ec=${token}`,
  554. data: GM_info.scriptHandler === 'Violentmonkey' && compareVersions.compare(GM_info.version, 'v2.12.2', '<') ? new Blob([data.buffer], {
  555. type: 'application/octet-binary'
  556. }) : data.toString('latin1'),
  557. binary: true,
  558. responseType: 'arraybuffer',
  559. headers: {
  560. 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
  561. },
  562. onerror: function(response) {
  563. return GM_log(`response.status = ${response.status}, response.statusText = ${response.statusText}`);
  564. },
  565. onload: function(response) {
  566. var date, datestr, json;
  567. if (response.status === 200) {
  568. data = Buffer.from(response.response);
  569. data = ec115_decode(data, key);
  570. if (data != null) {
  571. json = JSON.parse(data.toString('latin1'));
  572. if (json.state && (json.data != null)) {
  573. date = new Date();
  574. date.setTime(date.getTime() + parseInt(day) * 24 * 3600 * 1000);
  575. datestr = date.toUTCString();
  576. var time = date.Format("yyyy年MM月dd日 HH:mm:ss");
  577. GM_setValue('login_Last',time);
  578. document.cookie = `UID=${json.data.cookie.UID}; expires=${datestr}; path=/; domain=115.com`;
  579. document.cookie = `CID=${json.data.cookie.CID}; expires=${datestr}; path=/; domain=115.com`;
  580. document.cookie = `SEID=${json.data.cookie.SEID}; expires=${datestr}; path=/; domain=115.com`;
  581. document.cookie = `OOFL=${json.data.user_id}; expires=${datestr}; path=/; domain=115.com`;
  582. delete json.data;
  583. }
  584. return unsafeWindow[g](JSON.stringify(json));
  585. } else {
  586. return GM_log('data is null');
  587. }
  588. } else {
  589. return GM_log(`response.status = ${response.status}`);
  590. }
  591. }
  592. });
  593. };
  594. preLoginEncrypt = function(n, g) {
  595. var key, pub, tm, tmus, token;
  596. tmus = (new Date()).getTime();
  597. tm = Math.floor(tmus / 1000);
  598. ({pub, key} = ec115_init());
  599. token = ec115_encode_token(pub, tm, 0);
  600. return GM_xmlhttpRequest({
  601. method: 'GET',
  602. url: `https://passportapi.115.com/app/2.0/web/${g_ver}/login/sign?k_ec=${token}`,
  603. responseType: 'arraybuffer',
  604. anonymous: true,
  605. onerror: function(response) {
  606. return GM_log(`response.status = ${response.status}, response.statusText = ${response.statusText}`);
  607. },
  608. onload: function(response) {
  609. var body, data, error, json, sig;
  610. if (response.status === 200) {
  611. data = Buffer.from(response.response);
  612. data = ec115_decode(data, key);
  613. if (data != null) {
  614. json = JSON.parse(data.toString('latin1'));
  615. if (json.state) {
  616. body = Buffer.from(json.sign, 'base64');
  617. try {
  618. sig = sig_init(body);
  619. return LoginEncrypt_(JSON.parse(n), g, {pub, key}, sig);
  620. } catch (error1) {
  621. error = error1;
  622. return GM_log(`${error.message}\n${error.stack}`);
  623. }
  624. } else {
  625. return GM_log(JSON.stringify(json));
  626. }
  627. } else {
  628. return GM_log('data is null');
  629. }
  630. } else {
  631. return GM_log(`response.status = ${response.status}`);
  632. }
  633. }
  634. });
  635. };
  636. browserInterface = (ref = unsafeWindow.browserInterface) != null ? ref : {};
  637. browserInterface.LoginEncrypt = function(n, g) {
  638. var error;
  639. try {
  640. return preLoginEncrypt(n, g);
  641. } catch (error1) {
  642. error = error1;
  643. return GM_log(`${error.message}\n${error.stack}`);
  644. }
  645. };
  646. browserInterface.GetBrowserVersion = function() {
  647. return new String(g_ver);
  648. };
  649. browserInterface.ChromeGetIncognitoState = function() {
  650. return false;
  651. };
  652. if (typeof cloneInto !== 'function') {
  653. cloneInto = function(x) {
  654. return x;
  655. };
  656. }
  657. unsafeWindow.browserInterface = cloneInto(browserInterface, unsafeWindow, {
  658. cloneFunctions: true
  659. });
  660. };
  661. var G = GM_config;
  662. var localHref = window.location.href;
  663. var sign_url = 'http://115.com/?ct=offline&ac=space';
  664. var add_url = 'http://115.com/web/lixian/?ct=lixian&ac=add_task_url';
  665. var lists_url = 'http://115.com/web/lixian/?ct=lixian&ac=task_lists';
  666. function notice(){
  667. GM_addStyle(GM_getResourceText('toastrCss'));
  668. if(G.get('toastr')=='全铺'|| localHref.indexOf('https://captchaapi.115.com') != -1) {
  669. GM_addStyle('.toast{font-size:15px!important;} .toast-title{font-size:16px!important;text-align:center}');
  670. }else{
  671. GM_addStyle('.toast{font-size:15px!important;width:350px!important;} .toast-title{font-size:16px!important;text-align:center}');
  672. };
  673. var place = {'左上':'toast-top-left','右上':'toast-top-right','中上':'toast-top-center'}[G.get('toastr')] || 'toast-top-full-width';
  674. toastr.options = {
  675. "closeButton": true,
  676. "debug": false,
  677. "progressBar": true,
  678. "timeOut": 8000,
  679. "extendedTimeOut": 8000,
  680. "positionClass": place,
  681. "allowHtml": true,
  682. "newestOnTop" : false,
  683. };
  684. };
  685. notice();
  686. function AjaxCall(href,callback) {
  687. GM_xmlhttpRequest({
  688. method: "GET",
  689. url: href,
  690. onload: function(data,status) {
  691. if(data.readyState==4 && data.status==200){
  692. var htmlTxt = data.responseText;
  693. callback(null,htmlTxt);
  694. };
  695. },
  696. onerror: function (error) {
  697. callback(error);
  698. },
  699. ontimeout: function (error) {
  700. callback(error);
  701. },
  702. });
  703. };
  704. function download(pid,sha){
  705. var href = 'https://webapi.115.com/files/download?pickcode='+pid;
  706. AjaxCall(href,function(error,htmlTxt) {
  707. var json = JSON.parse(htmlTxt);
  708. if(json.state) {
  709. var link = json.file_url.replace(/\\/g,'');
  710. GM_openInTab(link);
  711. if (G.get('show_sha')){
  712. setTimeout(function(){
  713. prompt('文件下载中,校验码(SHA1)为:',sha);
  714. }, 1000);
  715. };
  716. console.log('下载地址:\n'+link);
  717. console.log('校验码:\n'+sha);
  718. } else {
  719. toastr.warning(json.msg,'下载失败!');
  720. };
  721. });
  722. };
  723. function palyData(video,className){
  724. if ((G.get('player') =='官方HTML5' && className == '115play') || className == 'dblclick'){
  725. var link = 'https://115.com/?ct=play&pickcode='+video.pid+'&hls=1';
  726. GM_openInTab(link,false);
  727. return;
  728. };
  729. var herfLink = 'https://115.com/api/video/m3u8/'+video.pid+'.m3u8';
  730. AjaxCall(herfLink,function(error,htmlTxt) {
  731. if (typeof htmlTxt == 'undefined') {
  732. transcoding(video.sha,function(result,num,time) {
  733. if (result){
  734. var txt = `等待转码排名:第${num}名,耗时:约${time},请稍后再试。`;
  735. }else{
  736. var txt = '未获取到转码进度,请稍后再试。';
  737. };
  738. var h1 = `<br><a target="_blank" class="transcode" data=${video.pid} href="javascript: void(0);" style="cursor:pointer;color:blue;" title="点击打开转码进度详情页">查看转码进度详情</a>`;
  739. toastr.warning(txt+h1, '播放失败,视频未转码!',{timeOut:10000});
  740. });
  741. return;
  742. };
  743. var dataList = htmlTxt.split('\n');
  744. var m3u8 = [];
  745. var temp = '"YH"|原画|"BD"|4K|"UD"|蓝光|"HD"|超清|"SD"|高清|"3G"|标清';
  746. var txt = temp.split('|');
  747. for (var i=0; i<6; i++){
  748. dataList.forEach(function (e,j,arr) {
  749. if (e.indexOf(txt[i*2])!= -1) {
  750. m3u8.push({name: txt[i*2+1], url: arr[j+1].replace(/\r/g,''), type:'hls'});
  751. };
  752. });
  753. };
  754. if (m3u8.length ==1 || G.get('play_Quality') =='最高'){
  755. var num = 0;
  756. }else if(m3u8.length >1 && G.get('play_Quality') =='次高'){
  757. var num = 1;
  758. }else{
  759. var num = m3u8.length - 1;
  760. };
  761. video['quality'] = num;
  762. if ((G.get('player') == 'Potplayer' && className == '115play') || className == 'Pot'){
  763. window.location.href = 'potplayer://'+m3u8[num].url;
  764. return;
  765. };
  766. GM_setValue('videoInfo',video);
  767. GM_setValue('m3u8List',m3u8);
  768. GM_openInTab('http://115.com/web/lixian/',false);
  769. });
  770. };
  771. function transcoding(sha,callback){
  772. var href = 'http://transcode.115.com/api/1.0/web/1.0/trans_code/check_transcode_job?sha1='+sha+'&priority=100';
  773. console.log('转码进度地址:'+href);
  774. AjaxCall(href,function(error,htmlTxt) {
  775. var json = JSON.parse(htmlTxt);
  776. if(json.status != 127) {
  777. var num = json.count;
  778. var time = tranTime(json.time).replace(/分.*/,'分');
  779. callback(true,num,time);
  780. return;
  781. }else{
  782. callback(false,null);
  783. console.log('查询转码进度失败');
  784. }
  785. });
  786. };
  787. function change(number){
  788. var size = "";
  789. if(number < 1024 * 1024 * 1024){
  790. size = (number/(1024 * 1024)).toFixed(2) + "MB";
  791. }else{
  792. size = (number/(1024 * 1024 * 1024)).toFixed(2) + "GB";
  793. };
  794. var sizeStr = size + "";
  795. var index = sizeStr.indexOf(".");
  796. var dou = sizeStr.substr(index + 1 ,2)
  797. if(dou == "00"){
  798. return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
  799. };
  800. return size;
  801. };
  802. function tranTime(num){
  803. var showTime = '';
  804. if (num > 3600) {showTime += ' '+parseInt(num/3600)+' 小时'; num = num%3600;}
  805. if (num > 60) {showTime += ' '+parseInt(num/60)+' 分'; num = num%60;}
  806. return showTime += ' '+parseInt(num)+' 秒';
  807. };
  808. function enterPiP(videoEl){
  809. if(document.pictureInPictureEnabled && !videoEl.disablePictureInPicture) {
  810. if (!document.pictureInPictureElement) {
  811. videoEl.requestPictureInPicture();
  812. }else{
  813. document.exitPictureInPicture();
  814. };
  815. }else{
  816. alert('浏览器不支持或已关闭画中画功能!');
  817. };
  818. };
  819. function clickOne(el){
  820. if (el.attr('clicked') == 1){
  821. console.log('5s内不可点击该按钮');
  822. return false;
  823. }else{
  824. el.attr('clicked',1);
  825. el.css('opacity','0.2');
  826. setTimeout(function(){
  827. el.attr('clicked',0);
  828. el.css('opacity','0.7');
  829. }, 5000);
  830. return true;
  831. };
  832. };
  833. function verify(){
  834. var time = new Date().getTime();
  835. var w=335;
  836. var h=500;
  837. var t = (window.screen.availHeight-h)/2;
  838. var l = (window.screen.availWidth-w)/2;
  839. var url = 'https://captchaapi.115.com/?ac=security_code&type=web&cb=Close911_'+time;
  840. var a = confirm('立即打开验证账号弹窗?\n(浏览器需允许弹出式窗口)');
  841. if (a){
  842. window.open(url,'请验证账号','height='+h+',width='+w+',top='+t+',left='+l+',toolbar=no,menubar=no,scrollbars=no,resizable=no,location=no,status=no');
  843. };
  844. };
  845. function getRightUrl(url){
  846. var newUrl = url;
  847. if(/^magnet/.test(url)){
  848. var hash=url.split('&')[0].substring(20) || url.substring(20);
  849. if(hash.length==32){
  850. hash=base32To16(hash);
  851. };
  852. newUrl='magnet:?xt=urn:btih:' + hash;
  853. }else if(/^thunder/.test(url)){
  854. var key = url.replace('thunder://','');
  855. var temp = decode64(key);
  856. newUrl = temp.slice(2,-2);
  857. }else if(/^\/\//.test(url)){
  858. newUrl=location.protocol + url;
  859. }else if(/^\/(?!\/)/.test(url)){
  860. newUrl=location.protocol+'//'+location.host + url;
  861. };
  862. return newUrl;
  863. };
  864. function base32To16(str){
  865. if(str.length % 8 !== 0 || /[0189]/.test(str)){
  866. return str;
  867. };
  868. str = str.toUpperCase();
  869. var bin = "", returnStr = "", i;
  870. for(i = 0;i < str.length;i++){
  871. var charCode=str.charCodeAt(i);
  872. if(charCode<65)charCode-=24;
  873. else charCode-=65;
  874. charCode='0000'+charCode.toString(2);
  875. charCode=charCode.substr(charCode.length-5);
  876. bin+=charCode;
  877. };
  878. for(i = 0;i < bin.length;i+=4){
  879. returnStr += parseInt(bin.substring(i,i+4),2).toString(16);
  880. };
  881. return returnStr;
  882. };
  883. Date.prototype.Format = function (fmt) {
  884. var o = {
  885. "M+": this.getMonth() + 1,
  886. "d+": this.getDate(),
  887. "H+": this.getHours(),
  888. "m+": this.getMinutes(),
  889. "s+": this.getSeconds(),
  890. "q+": Math.floor((this.getMonth() + 3) / 3),
  891. "S": this.getMilliseconds()
  892. };
  893. if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  894. for (var k in o)
  895. if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  896. return fmt;
  897. };
  898. $(document).ready(function(){
  899. if(localHref.indexOf('https://115.com/') != -1) {
  900. if (G.get('account_Login')){
  901. if ( typeof (require) == 'undefined') {
  902. alert('115优化大师:帐号登录库文件加载失败,该功能无法使用,请刷新网页重新加载!');
  903. return false;
  904. };
  905. var day = G.get('login_Alidity').replace('天','');
  906. login(day);
  907. };
  908. if (typeof (unsafeWindow.USER_ID) != 'undefined') {
  909. GM_setValue('115ID', unsafeWindow.USER_ID);
  910. console.log('115账号已登录,账号ID获取成功!');
  911. } else {
  912. if (G.get('hide_officeLogin')){
  913. $('.ltab-office').hide();
  914. };
  915. if (G.get('hide_qrcodeLogin')){
  916. $('.login-scene,.login-footer span:eq(0),.login-footer i:eq(0)').hide();
  917. $('[lg_rel="login"]').show();
  918. } else if ($('[lgb-nav="download"]').length > 0) {
  919. $('[lgb-nav="download"]').attr('lgb-nav','login');
  920. };
  921. console.log('115账号未登录,账号ID获取失败!');
  922. };
  923.  
  924. var $El = $('#js_top_panel_box [menu="upload"]').addClass('btn-line');
  925. if (G.get('show_Star')){
  926. $El.after('<a href="javascript:;" file_dialog_menu="star" class="button btn-line" id="js_star_list_btn"><i class="icon-operate ifo-fav"></i><span>星标</span></a>');
  927. };
  928. $('body').append(`
  929. <script>
  930. $('body').one('mouseenter','[rel="base_content"]',function(){
  931. $(this).find('a[tab="offline_task"]').click();
  932. });
  933. </script>`);
  934.  
  935. if (G.get('hide_sidebar')){
  936. $('.sub-core').hide();
  937. setTimeout(function(){
  938. $('.main-core').css({'left':'16px','top':'16px'});
  939. },50);
  940. };
  941. if (G.get('file_Down')){
  942. var herfd = 'li[rel="item"][file_type="1"]:not([down_button="1"])';
  943. $('body').on('mouseenter',herfd,function(){
  944. var $El = $(this).attr('down_button',1);
  945. $El.find('.file-opr [menu="download_one"]').hide();
  946. $El.find('.file-opr').prepend('<a class="115down" href="javascript:;" title="快捷下载文件"><i class="icon-operate ifo-download"></i><span>快捷下载</span></a>');
  947. return false;
  948. });
  949. };
  950.  
  951. var herfv = 'li[rel="item"][file_type="1"][file_mode="9"]:not([paly_button="1"])';
  952. $('body').on('mouseenter',herfv,function(){
  953. var $El = $(this).attr('paly_button',1);
  954. var c = {'Dplayer':'Dp','Potplayer':'Pot','官方HTML5':'115play'}[G.get('player')];
  955. $El.find('.name').addClass(c).removeAttr('menu');
  956. var txt0 = ['Pot','Dp'];
  957. var txt1 = ['使用Potplayer播放视频','使用Dplayer播放视频'];
  958. var txt2 = ['Pot播放','Dp播放'];
  959. for (var i=0; i<2; i++){
  960. $El.find('.file-opr').prepend('<a href="javascript:;" class='+txt0[i]+' title='+txt1[i]+'><span>'+txt2[i]+'</span></a>');
  961. };
  962. $El.not('.name').dblclick(function(){
  963. var className = 'dblclick';
  964. var pid1 = $El.attr('pick_code');
  965. var video = {'pid':pid1};
  966. palyData(video,className);
  967. return false;
  968. });
  969. });
  970. };
  971. if(localHref.indexOf('https://captchaapi.115.com') != -1) {
  972. window.focus();
  973. toastr.info('验证成功本页面将自动关闭.');
  974. $('#js_ver_code_box').find('[rel="verify"]').click(function () {
  975. setTimeout(function(){
  976. if($('[rel="error_box"]').attr('style').indexOf('none') != -1){
  977. window.opener=null;
  978. window.open('','_self');
  979. window.close();
  980. };
  981. }, 500);
  982. return false;
  983. });
  984. };
  985. if(localHref.indexOf('https://115.com/?ct=play') != -1) {
  986. $('.bar-side ul').prepend(`<li><a href="javascript:;" class="openPiP"
  987. style="float:left;width:40px;height:20px;margin:10px 5px;border-radius:3px;font-size:12px;text-align:center;background:#666;color:#fff;opacity:0.7;">
  988. <s>画中画</s><div class="tooltip" >开启画中画</div></a></li>`);
  989. };
  990. var oldVer = GM_getValue('version') || '';
  991. if (oldVer != newVersion){
  992. var txt=`115优化大师 ${newVersion} 更新日志:\n更新日期:20201011 \n1、优化下载地址匹配规则,提高识别率;\n2Dplayer增加清晰度可切换标识:清晰度字样显绿色;\n3、适配“片库”(pianku),实现自动捕获磁力链接;\n4、“其他设置”新增“网盘导航栏显示星标”选项,点击快速打开星标列表。`;
  993. setTimeout(function(){
  994. alert(txt);
  995. },2000);
  996. GM_setValue('version',newVersion);
  997. };
  998. });
  999. if(localHref.indexOf('https://115.com/?cid=0&offset=0&mode=wangpan') != -1){
  1000. window.onload=function(){
  1001. if (G.get('show_Alidity') && G.get('account_Login')){
  1002. var loginTime= GM_getValue('login_Last');
  1003. if (typeof unsafeWindow.USER_ID != 'undefined') {
  1004. if (typeof loginTime != 'undefined') {
  1005. toastr.success(loginTime, '登录有效期为',{timeOut:5000});
  1006. }else{
  1007. toastr.warning('其他方式登录,未知有效期!', '登录有效期为',{timeOut:5000});
  1008. };
  1009. };
  1010. };
  1011. };
  1012. };
  1013. if (localHref.match(/http:\/\/115\.com\/web\/lixian\/$/) != null ) {
  1014. var m3u8 = GM_getValue('m3u8List');
  1015. var video = GM_getValue('videoInfo');
  1016. var titleTxt = video.name;
  1017. var pickID = video.pid;
  1018. var folderID = video.fid1;
  1019. var videoID = video.fid2;
  1020. var size = video.size;
  1021. var sha = video.sha;
  1022. var z = video.quality;
  1023. var jsonList = GM_getValue('palyList') || {};
  1024. var curTime = jsonList[pickID];
  1025. if (curTime){
  1026. delete jsonList[pickID];
  1027. };
  1028. var skipTime = G.get('skip_titles');
  1029. var skipTime2 = G.get('skip_credits');
  1030. $('pre').remove();
  1031. $('head').html(`<meta http-equiv="Content-Type" content="text/html; charset=GBK"><title>${titleTxt} ${size}</title>`);
  1032. GM_addStyle(`html,body,div{margin:0;padding:0;border:0;outline:0;background:transparent}`);
  1033. GM_addStyle(GM_getResourceText('dplayerCss'));
  1034. $('body').append('<div id="Dplayer"></div>');
  1035. function playVideo(m3u8) {
  1036. var dp = new DPlayer({
  1037. container: $('#Dplayer')[0],
  1038. screenshot: true,
  1039. volume: 1,
  1040. video:
  1041. {
  1042. quality: m3u8,
  1043. defaultQuality: z,
  1044. },
  1045. contextmenu:
  1046. [
  1047. {
  1048. text: '下载视频',
  1049. click: function(t) {
  1050. download(pickID,sha);
  1051. }
  1052. },
  1053. {
  1054. text: '删除视频',
  1055. click: function(t) {
  1056. dp.pause();
  1057. var a = confirm('确认删除 '+titleTxt+' 视频文件?');
  1058. if (a){
  1059. offline.del(videoID)
  1060. };
  1061. }
  1062. },
  1063. {
  1064. text: '查看文件夹',
  1065. click: function(t) {
  1066. GM_openInTab(`https://115.com/?cid=${folderID}&offset=0&mode=wangpan`,false);
  1067. }
  1068. },
  1069. {
  1070. text: '删除文件夹',
  1071. click: function(t) {
  1072. if (folderID==0){
  1073. alert('网盘根目录,不可删除!');
  1074. return ;
  1075. };
  1076. var a = confirm('确认删除 '+titleTxt+' 视频所属文件夹?');
  1077. if (a){
  1078. offline.del(folderID);
  1079. };
  1080. }
  1081. },
  1082. {
  1083. text: '设置星标',
  1084. click: function(t) {
  1085. var n=1;
  1086. offline.setStar(videoID,n);
  1087. }
  1088. },
  1089. {
  1090. text: '取消星标',
  1091. click: function(t) {
  1092. var n=0;
  1093. offline.setStar(videoID,n);
  1094. }
  1095. },
  1096. {
  1097. text: '开启画中画',
  1098. click: function(t) {
  1099. enterPiP(t.video)
  1100. }
  1101. }
  1102. ],
  1103. });
  1104. unsafeWindow.dp = dp;
  1105. $('#Dplayer').click();
  1106. $('.dplayer-menu').css('width','98px');
  1107. $('.dplayer-setting-loop,.dplayer-mobile-play,.dplayer-menu-item:gt(-3)').hide();
  1108. if(m3u8.length >1){
  1109. $('.dplayer-quality button').css('color','Lime');
  1110. };
  1111. dp.on('loadstart', function () {
  1112. dp.notice('视频加载中,请稍侯。', 1000);
  1113. });
  1114. var a = 0;
  1115. dp.on('loadeddata', function () {
  1116. dp.notice('视频加载完成。', 1000);
  1117. a++;
  1118. if( a==1){
  1119. setTimeout(function(){
  1120. if (curTime && curTime > skipTime){
  1121. dp.seek(curTime);
  1122. dp.notice('已跳转到上次观看进度'+tranTime(curTime), 2500);
  1123. }else if(skipTime>0){
  1124. dp.seek(skipTime);
  1125. dp.notice('已跳过片头'+skipTime+'秒', 2500);
  1126. };
  1127. if(m3u8.length >1){
  1128. setTimeout(function(){
  1129. dp.notice('本视频支持切换清晰度', 2500);
  1130. }, 3000);
  1131. };
  1132. if (document.hidden && G.get('Tab_ing')){
  1133. return;
  1134. };
  1135. dp.play();
  1136. }, 1000);
  1137. };
  1138. });
  1139. dp.on('timeupdate', function () {
  1140. if ((dp.video.duration - dp.video.currentTime > 30) && dp.video.currentTime > 30) {
  1141. jsonList[pickID] = dp.video.currentTime;
  1142. var setNum = G.get('play_Number').replace('条','');
  1143. var saveNum = Object.keys(jsonList).length;
  1144. if (saveNum > parseInt(setNum)){
  1145. var palyOld = JSON.stringify(jsonList).split('"')[1];
  1146. delete jsonList[palyOld];
  1147. };
  1148. }else{
  1149. delete jsonList[pickID];
  1150. };
  1151. GM_setValue('palyList',jsonList);
  1152. if(0< skipTime2 && (dp.video.duration - dp.video.currentTime) <= skipTime2){
  1153. dp.pause();
  1154. dp.notice('已跳过片尾'+skipTime2+'秒', 2500);
  1155. setTimeout(function(){
  1156. alert('视频已播放结束!');
  1157. }, 2000);
  1158. };
  1159. });
  1160. dp.on('error', function () {
  1161. alert('视频加载失败!');
  1162. return
  1163. });
  1164. dp.on('ended', function () {
  1165. alert('视频已播放结束!');
  1166. });
  1167. };
  1168. playVideo(m3u8);
  1169. };
  1170. var offline = function(){
  1171. return {
  1172. getSign:function () {
  1173. return new Promise(function(resolve, reject){
  1174. var time = Date.now();
  1175. GM_xmlhttpRequest({
  1176. method: 'GET',
  1177. url: sign_url,
  1178. onload: function(response) {
  1179. if (response.responseText.indexOf('html')!= -1) {
  1180. toastr.error('请先登录115网盘账号!','离线任务添加失败。');
  1181. setTimeout(function(){
  1182. var a = confirm('立即打开115网盘登录页面?');
  1183. if (a){
  1184. GM_openInTab('https://115.com/?mode=login',false);
  1185. };
  1186. }, 3000);
  1187. return;
  1188. };
  1189. var json = JSON.parse(response.responseText);
  1190. resolve(json);
  1191. },
  1192. onerror: function(error) {
  1193. reject(error);
  1194. },
  1195. });
  1196. });
  1197. },
  1198.  
  1199. param2:function (data,e) {
  1200. if (typeof e != 'undefined'){
  1201. return e;
  1202. };
  1203. var res = '';
  1204. for(var key in data){
  1205. var value = data[key];
  1206. res += '&' + encodeURIComponent( key ) + "=" + encodeURIComponent( value );
  1207. };
  1208. return res.slice(1);
  1209. },
  1210. getData:function (url,herf,e){
  1211. var UserID = GM_getValue('115ID') || '';
  1212. return offline.getSign().then(function(json){
  1213. return new Promise(function(resolve, reject){
  1214. var data = {
  1215. uid: UserID,
  1216. sign: json.sign,
  1217. time: json.time,
  1218. url: url
  1219. };
  1220. GM_xmlhttpRequest({
  1221. method: 'POST',
  1222. data: offline.param2(data,e),
  1223. url: herf,
  1224. headers: {
  1225. "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
  1226. "Accept": "application/json, text/javascript, */*; q=0.01",
  1227. Origin: "http://115.com",
  1228. "X-Requested-With": "XMLHttpRequest"
  1229. },
  1230. onload: function(response) {
  1231. var json = JSON.parse(response.responseText);
  1232. resolve(json);
  1233. },
  1234. onerror: function(error) {
  1235. reject(error);
  1236. },
  1237. });
  1238. });
  1239. });
  1240. },
  1241. del:function (key) {
  1242. var url = '';
  1243. var del_url ='https://webapi.115.com/rb/delete';
  1244. var fidInfo = 'fid='+key;
  1245. offline.getData(url,del_url,fidInfo).then(function(json){
  1246. if(json.state) {
  1247. var a = confirm('删除成功,可从回收站还原。是否立即关闭本页面?');
  1248. if (a){
  1249. window.opener=null;
  1250. window.open('','_self');
  1251. window.close();
  1252. };
  1253. } else {
  1254. alert('删除失败:'+json.error);
  1255. };
  1256. });
  1257. },
  1258. setStar:function (fid,n){
  1259. var url = '';
  1260. var star_url ='https://webapi.115.com/files/star';
  1261. var e = `file_id=${fid}&star=${n}`;
  1262. var txt = {'1':'设置','0':'取消'}[n];
  1263. offline.getData(url,star_url,e).then(function(json){
  1264. json.state ? alert(txt+'星标成功!') : alert(txt+'星标失败:'+json.error);
  1265. });
  1266. },
  1267. search:function (name,fid1,callback){
  1268. var title = new Array();
  1269. title[0] = name.replace(/(\.|-|_)?(f?hd|sd|720p|1080p|full|mp4|avi|mkv|wmv|rmvb|rm|flv|f4v)/gi,' ');
  1270. title[1] = title[0].replace(/\.|-|_|@/g,' ');
  1271. title[2] = 'mp4 avi mkv wmv rmvb rm flv f4v';
  1272. var a = 0;
  1273. function add2(){
  1274. if(a == 3){
  1275. console.log('该文件夹无视频文件。');
  1276. callback(false);
  1277. return;
  1278. };
  1279. var searchLink = 'https://webapi.115.com/files/search?cid='+fid1+'&search_value='+encodeURIComponent(title[a])+'&type=4';
  1280. AjaxCall(searchLink,function(error,htmlTxt) {
  1281. if (typeof htmlTxt == 'undefined'){
  1282. a++;
  1283. add2();
  1284. }else{
  1285. var json = JSON.parse(htmlTxt);
  1286. if(a == 2 && json.folder.name == '云下载'){
  1287. callback(false);
  1288. return;
  1289. };
  1290. if(json.count > 0) {
  1291. var num= json.data.length;
  1292. for(var i=0; i<num; i++){
  1293. var $dataEh = json.data[i];
  1294. var video = {};
  1295. video['name'] = $dataEh.n.replace(/\s*/g,'');
  1296. video['pid'] = $dataEh.pc;
  1297. video['fid1'] = $dataEh.cid;
  1298. video['fid2'] = $dataEh.fid;
  1299. video['size'] = change($dataEh.s);
  1300. video['sha'] = $dataEh.sha;
  1301. video['time'] =$dataEh.play_long;
  1302. callback(true,video,i+1,num);
  1303. console.log('第'+a+'次搜索结果'+i+':'+video.name+' '+video.size);
  1304. if(i == 2){
  1305. return;
  1306. };
  1307. };
  1308. }else{
  1309. a++;
  1310. add2();
  1311. };
  1312. };
  1313. });
  1314. };
  1315. add2();
  1316. },
  1317. check:function (link) {
  1318. var url = '';
  1319. var show_result = G.get('offline_result');
  1320. var a_list= `<br><a target="_blank" class="openList" href="javascript: void(0);" style="color:blue;" title="点击打开离线链接任务列表">打开任务列表</a>`;
  1321. if(document.hidden){
  1322. GM_setValue('noTimeOut',true);
  1323. toastr.options.timeOut = 0;
  1324. console.log('已切换到后台,暂停通知超时');
  1325. }else{
  1326. GM_setValue('noTimeOut',false);
  1327. toastr.options.timeOut = 12000;
  1328. };
  1329. var c = 1;
  1330. var retry = false;
  1331. var txt2 = '5秒后自动重试,请稍等。';
  1332. function add(retry,txt2){
  1333. if(c == 4){
  1334. console.log('离线结果查询异常。离线任务数量过多,请清空后再试。');
  1335. toastr.warning('离线任务数量过多,请清空后再试。', '离线结果查询异常!');
  1336. return;
  1337. };
  1338. var lists_url2 = lists_url+'&page='+c;
  1339. console.log('离线任务数据地址:'+lists_url2);
  1340. offline.getData(url,lists_url2).then(function(json){
  1341. console.log('离线任务列表第'+c+'页:');
  1342. console.log(json);
  1343. if(json.state){
  1344. for (var k=0; k<json.tasks.length; k++){
  1345. var dataEl = json.tasks[k];
  1346. if (dataEl.url == link || dataEl.url == decodeURIComponent(link)){
  1347. if (dataEl.status != -1){
  1348. if (dataEl.move == -1){
  1349. toastr.warning('空间不足,请到115扩容', '离线下载异常!');
  1350. return;
  1351. };
  1352. var down_result = dataEl.percentDone.toFixed(0);
  1353. if (down_result >= 99){
  1354. var name = dataEl.name;
  1355. var fid1 = dataEl.file_id || '0';
  1356. if (show_result && !retry) {
  1357. var txt = `文件(夹)名:${dataEl.name},大小:${change(dataEl.size)}。`;
  1358. toastr.success(txt+a_list, '离线下载已完成',{timeOut:5000});
  1359. };
  1360. if (G.get('open_search')) {
  1361. offline.search(name,fid1,function(search_result,video,j,num) {
  1362. if (search_result) {
  1363. if (G.get('search_result')) {
  1364. var videoTxt = JSON.stringify(video);
  1365. var txt = `文件名:${video.name},大小:${video.size},时长:${tranTime(video.time)}。`;
  1366. var h1 = `<br><a target="_blank" class="115play" data=${videoTxt} href="javascript:void(0);" style="color:blue;" title="点击播放该视频">播放</a>`;
  1367. var h2 = `&nbsp;&nbsp;<a target="_blank" class="115down" data=${videoTxt} href="javascript:void(0);" style="color:blue;" title="点击下载该视频">下载</a>`;
  1368. var h3 = `&nbsp;&nbsp;<a target="_blank" class="115del" data=${videoTxt} href="javascript:void(0);" style="color:blue;" title="点击删除该视频文件夹">删除</a>`;
  1369. var h4 = `&nbsp;&nbsp;<a target="_blank" class="openFolder" data=${fid1} href="javascript:void(0);" style="color:blue;" title="点击查看所属文件列表">查看</a>`;
  1370. toastr.success(txt+h1+h2+h3+h4,`发现第 ${j} 个视频(共 ${num} 个)`);
  1371. };
  1372. if (G.get('open_Popup') && j==1){
  1373. setTimeout(function(){
  1374. var className = '115play';
  1375. palyData(video,className);
  1376. }, 500);
  1377. };
  1378. }else{
  1379. if( dataEl.move == 2 || dataEl.move == 0 || dataEl.status == 0){
  1380. var txt = '离线数据取回网盘中。';
  1381. }else{
  1382. var txt = '未发现任何视频文件。';
  1383. };
  1384. var h1 = `<br><a target="_blank" class="openFolder" data=${fid1} href="javascript:void(0);" style="color:blue;" title="点击打开所属文件列表">打开文件列表</a>`;
  1385. toastr.warning(txt+txt2+h1, '视频搜索无结果!');
  1386. if (!retry){
  1387. setTimeout(function(){
  1388. retry = true;
  1389. txt2='';
  1390. toastr.clear();
  1391. console.log('重试搜索结果:');
  1392. add(retry,txt2);
  1393. }, 5000);
  1394. };
  1395. };
  1396. });
  1397. };
  1398. }else if(show_result) {
  1399. var txt = `文件(夹)名:${dataEl.name},下载进度为:<span style="color:purple;">${down_result}%</span>。`;
  1400. toastr.warning(txt+a_list, '离线下载中...');
  1401. console.log(`文件(夹)名:${dataEl.name},下载进度为:${down_result}%`);
  1402. };
  1403. }else if(show_result) {
  1404. var txt = '未知原因,请到115查看。';
  1405. toastr.error(txt+a_list,'离线下载失败',{timeOut:8000});
  1406. return;
  1407. };
  1408. break;
  1409. }else if(k == (json.tasks.length-1)) {
  1410. console.log('第'+c+'页查询失败,无匹配数据');
  1411. if(c == json.page_count) {
  1412. console.log('离线链接对比异常,已搜索所有离线列表页面,无返回结果。');
  1413. toastr.warning('搜索参数错误。', '离线结果查询异常!',{timeOut:5000});
  1414. return;
  1415. };
  1416. c++
  1417. add();
  1418. };
  1419. };
  1420. }else{
  1421. toastr.error('查询离线结果失败。','服务器错误!');
  1422. return;
  1423. };
  1424. });
  1425. };
  1426. add(retry,txt2);
  1427. },
  1428. addButton:function(){
  1429. var href = '[href^="magnet:"],[href^="ed2k:"],[href^="thunder:"],[href^="ftp:"],[href$=".torrent"],[href$=".rar"],[href$=".7z"],[href$=".zip"],[href$=".mp4"],[href$=".rmvb"],[href$=".mkv"],[href$=".avi"]';
  1430. $(href).each(function(){
  1431. var url = $(this).attr('href');
  1432. var $El = $(this).parent().filter('li,td').find('[Searched]');
  1433. if ($(this).is('[Searched]') || $El.length>1
  1434. || ($El.length>0 && url.indexOf($El.attr('Searched')) != -1)){
  1435. return;
  1436. };
  1437. var txt=['^magnet','^thunder','^ed2k','^ftp','torrent$'];
  1438. for (var i=0;i<5;i++){
  1439. if (url.match(new RegExp(txt[i])) != null){
  1440. $(this).attr('Searched',txt[i].replace(/\^|\$/,''));
  1441. break;
  1442. }else{
  1443. $(this).attr('Searched','otherLink');
  1444. };
  1445. };
  1446. var link = getRightUrl(url);
  1447. $(this).css('display','inline-block');
  1448. $(this).after('<img src="https://115.com/favicon.ico" class="115offline" data-href='+link+' style="display:inline-block;cursor:pointer; margin-left:5px;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+'">');
  1449. });
  1450. },
  1451. addLink:function(){
  1452. $('a').each(function(){
  1453. var reg1 =/(\/|&|-|\.|\?|=|:)(\w{40}|\w{32})(?!\w)/;
  1454. var reg2 =/_|[a-z]{40}|[a-z]{32}/gi;
  1455. var reg3 =/(\w{40}|\w{32})(?!\w)/i;
  1456. var reg4 =/^thunder:[a-z0-9+\/=]+/i
  1457. if ($(this).next().addBack().is('[Searched],[href*="motelppp.com"],[href*="bvmqkla.de"]')
  1458. || $(this).find('img').length>0
  1459. || $(this).parent().filter('li,td').find('[Searched]').length>0){
  1460. return;
  1461. };
  1462. var url = $(this).attr('href') || '';
  1463. if(reg1.test(url) && !reg2.test(url.match(reg1)[2])){
  1464. $(this).attr('Searched','magnet');
  1465. var templink = 'magnet:?xt=urn:btih:' + url.match(reg1)[2];
  1466. var link = getRightUrl(templink);
  1467. $(this).after('<img src="https://115.com/favicon.ico" class="115offline" data-href='+link+' style="display:inline-block;cursor:pointer; margin-left:5px;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+'">');
  1468. };
  1469. var txt = $(this).text() || '';
  1470. if(reg4.test(txt) || (reg3.test(txt) && !reg2.test(txt.match(reg3)[0]))){
  1471. if(reg4.test(txt)){
  1472. $(this).attr('Searched','thunder');
  1473. var link = getRightUrl(txt.match(reg4)[0]);
  1474. }else{
  1475. $(this).attr('Searched','magnet');
  1476. var templink = 'magnet:?xt=urn:btih:' + txt.match(reg3)[0];
  1477. var link = getRightUrl(templink);
  1478. };
  1479. $(this).after('<img src="https://115.com/favicon.ico" class="115offline" data-href='+link+' style="display:inline-block;cursor:pointer; margin-left:5px;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+'">');
  1480. };
  1481. });
  1482. },
  1483.  
  1484. };
  1485. }();
  1486. $(document).ready(function(){
  1487. $(document).on('visibilitychange',function (e){
  1488. var isHidden = e.target.hidden;
  1489. if (localHref.match(/115\.com\S*(lixian|play)/) != null &&
  1490. G.get('Tab_ing') && !document.pictureInPictureElement){
  1491. var video = $('#js-video')[0] || dp ;
  1492. isHidden ? video.pause() : video.play();
  1493. return;
  1494. };
  1495. var noTimeOut=GM_getValue('noTimeOut') || '';
  1496. if (isHidden){
  1497. }else if(noTimeOut){
  1498. GM_setValue('noTimeOut','');
  1499. setTimeout(function(){
  1500. toastr.clear();
  1501. }, 12000);
  1502. }else{
  1503. };
  1504. });
  1505. $('body').on('click mouseenter mouseleave','.openPiP',function(e){
  1506. if(e.type == 'click'){
  1507. var video = $('#js-video')[0];
  1508. enterPiP(video);
  1509. }else if(e.type == 'mouseenter'){
  1510. $(this).css('opacity', 1);
  1511. }else if(e.type == 'mouseleave'){
  1512. $(this).css('opacity', 0.7);
  1513. };
  1514. return false;
  1515. });
  1516. $('body').on('click','.transcode',function () {
  1517. var pid = $(this).attr('data');
  1518. var link = 'https://115.com/?ct=play&pickcode='+pid+'&hls=1';
  1519. GM_openInTab(link,false);
  1520. return false;
  1521. });
  1522. $('body').on('click','.115play,.Dp,.Pot',function(){
  1523. if (!clickOne($(this))) return;
  1524. var className = $(this).attr('class').replace(/name\s?/g,'');
  1525. if ($(this).is('[data]')){
  1526. var video = JSON.parse($(this).attr('data'));
  1527. }else{
  1528. var $El = $(this).parents('li');
  1529. var video = {};
  1530. video['name'] = $El.attr('title').replace(/\s*/g, '');
  1531. video['pid'] = $El.attr('pick_code');
  1532. video['fid1'] = $El.attr('cid');
  1533. video['fid2'] = $El.attr('file_id');
  1534. video['size'] = change($El.attr('file_size'));
  1535. video['sha'] = $El.attr('sha1');
  1536. };
  1537. palyData(video,className);
  1538. return false;
  1539. });
  1540. $('body').on('click','.115down',function(){
  1541. if (!clickOne($(this))) return;
  1542. if ($(this).is('[data]')){
  1543. var video = JSON.parse($(this).attr('data'));
  1544. var pid = video.pid;
  1545. var sha = video.sha;
  1546. }else{
  1547. var $El = $(this).parents('li');
  1548. var pid = $El.attr('pick_code');
  1549. var sha = $El.attr('sha1');
  1550. };
  1551. download(pid,sha);
  1552. return false;
  1553. });
  1554. $('body').on('click','.115del',function(){
  1555. if (!clickOne($(this))) return;
  1556. var video = JSON.parse($(this).attr('data'));
  1557. var title = video.name;
  1558. var folderID = video.fid1;
  1559. var videoID = video.fid2;
  1560.  
  1561. if (folderID == 0){
  1562. alert('网盘根目录,不可删除!');
  1563. return ;
  1564. };
  1565. var a = confirm('确认删除 '+title+' 视频所属文件夹?');
  1566. if (a){
  1567. offline.del(folderID);
  1568. };
  1569. return false;
  1570. });
  1571. $('body').on('click','.openList:not([click="1"]),.openFolder:not([click="1"])',function(){
  1572. $(this).attr('click', '1');
  1573. if($(this).is('.openList')){
  1574. var txt='tab=offline';
  1575. }else{
  1576. var fID=$(this).attr('data');
  1577. var txt='cid='+fID+'&offset=0';
  1578. };
  1579. GM_openInTab('https://115.com/?'+txt+'&mode=wangpan',false);
  1580. return false;
  1581. });
  1582. $('body').on('contextmenu','.115offline',function(){
  1583. GM_setClipboard($(this).data('href'));
  1584. toastr.success('下载地址复制成功!');
  1585. return false;
  1586. });
  1587. $('body').on('click','.115offline',function(){
  1588. if (!clickOne($(this))) return;
  1589. var link = $(this).data('href');
  1590. offline.getData(link,add_url).then(function(json){
  1591. console.log('离线任务添加结果:');
  1592. console.log(json);
  1593. if(json.state){
  1594. if (G.get('offline_result')) {
  1595. var txt = '10秒后显示离线结果。';
  1596. }else{
  1597. var txt = link
  1598. if (G.get('open_List')){
  1599. setTimeout(function(){
  1600. GM_openInTab('https://115.com/?tab=offline&mode=wangpan',false);
  1601. }, 2000);
  1602. };
  1603. };
  1604. toastr.info(txt, '离线任务添加成功。',{timeOut:10000});
  1605. setTimeout(function(){
  1606. offline.check(link)
  1607. }, 10000);
  1608. } else if (json.errcode == 10008){
  1609. toastr.warning('任务已存在,无需重复添加。','离线任务添加无效!',{timeOut:5000});
  1610. if (G.get('open_List')){
  1611. setTimeout(function(){
  1612. GM_openInTab('https://115.com/?tab=offline&mode=wangpan',false);
  1613. }, 2000);
  1614. };
  1615. offline.check(link);
  1616. } else if (json.errcode == 911){
  1617. toastr.warning('账号异常,请验证账号。','离线下载失败!',{timeOut:5000});
  1618. setTimeout(function(){
  1619. verify();
  1620. }, 1000);
  1621. } else {
  1622. toastr.warning(json.error_msg,'离线任务添加失败!',{timeOut:12000});
  1623. };
  1624. console.log('离线链接:'+link+ ' 添加结果:' +json.state+ ' 原因:' +json.error_msg);
  1625. }, function(error) {
  1626. toastr.error('服务器繁忙,请稍后再试。','离线任务添加异常!');
  1627. console.log(error);
  1628. });
  1629. return false;
  1630. });
  1631. if (G.get('offline_Down')){
  1632. if (localHref.match(/[0-9]mag.net/) != null) {
  1633. var trigger;
  1634. $('body').on('mouseenter mouseleave','td,.magnet-box',function(e){
  1635. if(e.type == 'mouseenter'){
  1636. trigger = setTimeout(function(){
  1637. offline.addButton();
  1638. }, 200);
  1639. }else if(e.type == 'mouseleave'){
  1640. clearTimeout(trigger);
  1641. };
  1642. });
  1643. } else if(localHref.match(/pianku/) != null) {
  1644. var time = setInterval(function(){
  1645. if (document.readyState == 'complete') {
  1646. clearInterval(time);
  1647. if(localHref.match(/\/bt\//) != null) {
  1648. var key =$('script:eq(-2)').text().match(/'.{13}'/)[0];
  1649. $('body').append(`
  1650. <script>
  1651. $('[data-clipboard-text]').each(function(){
  1652. var url = $(this).data('clipboard-text');
  1653. var newurl = decrypt(url,${key},host);
  1654. $(this).attr('href',newurl);
  1655. });
  1656. </script>`);
  1657. }else{
  1658. $('body').append('<script>$(".torrent").click();</script>');
  1659. };
  1660. offline.addButton();
  1661. };
  1662. }, 1000);
  1663. $('body').on('click','.torrent:not([Searched])',function(){
  1664. setTimeout(function(){
  1665. offline.addButton();
  1666. },50);
  1667. });
  1668. } else {
  1669. setTimeout(function(){
  1670. offline.addButton();
  1671. },100);
  1672. if (G.get('fuzzy_find')){
  1673. setTimeout(function(){
  1674. offline.addLink();
  1675. },200);
  1676. };
  1677. };
  1678. };
  1679. });
  1680. })();