// ==UserScript==
// @name 发送到115
// @author zxf10608
// @version 7.5.1
// @icon https://115.com/favicon.ico
// @namespace https://greasyfork.org/zh-CN/scripts/408466
// @description 115离线下载功能
// @require https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js
// @require https://greasyfork.org/scripts/398240-gm-config-zh-cn/code/GM_config_zh-CN.js
// @require https://greasyfork.org/scripts/412267-base64-v1-0/code/base64_v10.js
// @require https://cdn.jsdelivr.net/npm/toastr@2.1.4/toastr.min.js
// @resource toastrCss https://cdn.jsdelivr.net/npm/toastr@2.1.4/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
// @downloadURL https://update.greasyfork.icu/scripts/531243/%E5%8F%91%E9%80%81%E5%88%B0115.user.js
// @updateURL https://update.greasyfork.icu/scripts/531243/%E5%8F%91%E9%80%81%E5%88%B0115.meta.js
// ==/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: 'https://greasyfork.org/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 = `
打开任务列表`;
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 = ` 删除任务`;
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 = `
播放`;
var h2 = ` 下载`;
var h3 = ` 删除`;
var h4 = ` 重命名`;
var h5 = ` 查看`;
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 = `
打开文件列表`;
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},下载进度为:${down_result}%。`;
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('');
});
},
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('
');
return;
}
}
}
});
},
addSelect: function() {
if ($('.115offline').length < 3) return;
$('.115offline:not([Sed])').each(function() {
$(this).attr('Sed', 1);
var url = $(this).data('href');
$(this).after('');
});
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('
');
$(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(`