// ==UserScript==
// @id [email protected]
// @name 豆瓣电影C+|MyDoubanMovieHelper|豆瓣|豆瓣电影|douban.movie.com
// @namespace Chang_way_enjoying
// @version 0.6.6_2016-05-20
// @description 在 movie.douban.com 网站下直接显示下载链接,可通过多个站点获取。
// @author c wt U r
// @match https://movie.douban.com/subject/*
// @connect pan.baidu.com
// @connect mp4ba.com
// @connect edmag.net
// @connect tl95.com
// @connect kat.cr
// @require https://cdn.bootcss.com/jquery/2.2.3/jquery.min.js
// @require https://cdn.bootcss.com/jBox/0.3.2/jBox.min.js
// @grant GM_xmlhttpRequest
// @grant GM_setClipboard
// ==/UserScript==
/**
* Created by c wt U r on 2016/5/18.
* QQ 3099891314
*
* node{detailURL,downloadURL,date,type[0,1,2],title}
* type[0 , // mag
* 1 , // ed2k
* 2 , // thunder
* ]
* TODO 加入book.douban.com的支持
* TODO baidu网盘的链接有效性检测函数
* TODO google 搜索 百度网盘
* TODO baidu网盘已登录(不可用)用户一键保存
*
*/
var config = {
c01: 3, //config。c01 单个类型在电影网页里面显示的最大数量
};
addCSSfile("https://cdn.bootcss.com/jBox/0.3.2/jBox.min.css");
//jQuery.getScript("https://cdn.bootcss.com/jBox/0.3.2/jBox.min.js", function(data, status, jqxhr) {});
function addCSSfile(url) {
$("<link>")
.attr({
rel: "stylesheet",
type: "text/css",
href: url
})
.appendTo("head");
}
function getDoc(url, callback) {
GM_xmlhttpRequest({
method: 'GET',
url: url,
headers: {
'User-agent': window.navigator.userAgent,
'Content-type': null
},
onload: function (responseDetail) {
var doc = '';
if (responseDetail.status == 200) {
// For Firefox, Chrome 30+ Supported
doc = new DOMParser().parseFromString(responseDetail.responseText, 'text/html');
if (doc === undefined) {
doc = document.implementation.createHTMLDocument("");
doc.querySelector('html').innerHTML = responseText;
}
}
callback(doc, responseDetail.finalUrl);
}
});
}
function postDoc(url, callback, data) {
GM_xmlhttpRequest({
anonymous:true,
method: 'POST',
url: url,
headers: {
'User-agent': window.navigator.userAgent,
'Content-type': 'application/x-www-form-urlencoded'
},
data:data,
onload: function (responseDetail) {
callback(responseDetail.responseText, responseDetail.finalUrl);
}
});
}
function timeago(stime) {
var publishTime = new Date(stime);
var d_minutes, d_hours, d_days;
var timeNow = parseInt(new Date().getTime() / 1000);
var d;
d = timeNow - publishTime;
d_days = parseInt(d / 86400);
d_hours = parseInt(d / 3600);
d_minutes = parseInt(d / 60);
if (d_days > 0 && d_days < 4) {
return d_days + "天前";
} else if (d_days <= 0 && d_hours > 0) {
return d_hours + "小时前";
} else if (d_hours <= 0 && d_minutes > 0) {
return d_minutes + "分钟前";
} else {
var s = new Date(publishTime * 1000);
// s.getFullYear()+"年";
return (s.getMonth() + 1) + "月" + s.getDate() + "日";
}
} // TODO 将绝对时间转换为相对时间;
function msg_info(msg) {
new jBox('Notice', {
content: msg,
position: {
x: 15,
y: 65
},
zIndex: 12000,
onInit: function () {
this.options.color = 'blue';
},
});
}
function msg_warning(msg) {
console.log(msg);
var color = 'yellow';
new jBox('Notice', {
attributes: {
x: 'left',
y: 'bottom'
},
delayClose: 1000 * 30,
theme: 'NoticeBorder',
color: color,
//audio: '/libraries/jBox-' + global.jBoxVersion + '/Source/audio/bling2',
// volume: noticeN3Volume,
animation: {open: 'slide:bottom', close: 'slide:left'},
onInit: function () {
this.options.color = color;
this.options.title = "提示";
this.options.content = msg;
},
});
}
function msg_error(msg) {
var color = 'red';
new jBox('Notice', {
attributes: {
x: 'left',
y: 'bottom'
},
theme: 'NoticeBorder',
color: color,
//audio: '/libraries/jBox-' + global.jBoxVersion + '/Source/audio/bling2',
// volume: noticeN3Volume,
animation: {open: 'slide:bottom', close: 'slide:left'},
onInit: function () {
this.options.color = color;
this.options.title = "错误警告";
this.options.content = msg;
},
});
console.error(msg);
}
imdb = $("#info").find("a[href^='http://www.imdb.com/title/tt']").text();
title_cn = $("#content").children()[0].firstElementChild.textContent.split(" ")[0];
title_en = undefined;// TODO title_en 可以实现,但更倾向于使用imdb搜索影视;
if (!imdb) {
msg_error('imdb is null');
} else {
if (imdb.startsWith('tt')) {
imdb = imdb.slice(2);
}
}
msg = ["IMDB:\t" + imdb, "TITLE:\t" + title_cn].join("\n");
msg_info(msg);
var linksTable = {
table: undefined,
nodes: [],
init: function () {
var div, h2 = undefined;
div = $("<div>").attr({
id: "dtable"
});
h2 = $("<h2>");
h2 = h2.html("下载地址");
div.append(h2);
$($("div.related-info")[0]).after(div);
var tr, th = undefined;
this.table = $("<table>").attr({
id: "dlinks",
class: "table table-condensed table-hover table-striped"
});
thead = $("<thead>");
tr = $("<tr>");
th = $("<th>").attr({"data-column-id": "copy", style: "width:33px"});
th = th.html(" ");
tr.append(th);
th = $("<th>").attr({"data-column-id": "detail", style: "width:33px"});
th = th.html(" ");
tr.append(th);
th = $("<th>").attr({"data-column-id": "date", style: "width:80px"});
th = th.html("时间");
tr.append(th);
th = $("<th>").attr({"data-column-id": "type", style: "width:55px"});
th = th.html("类型");
tr.append(th);
th = $("<th>").attr({"data-column-id": "title"});
th = th.html("详细信息");
tr.append(th);
//th = $("<th>").attr({"data-column-id": "link"});
//th = th.html("链接");
//tr.append(th);
thead.append(tr);
this.table.append(thead);
this.table.appendTo($("#dtable"));
},
clean: function () {
$("#dtable").remove();
this.init();
},
_add: function (data) {// TODO 链接文件名太长的,隐藏
thead = $($("#dlinks")[0].firstElementChild);
types = {0: "mag", 1: "ed2k", 2: 'thunder'};
var tr, th = undefined;
tr = $('<tr style="max-height: 19px;">');
th = $("<th>");
th = th.html('<a href="' + data.detailURL + '" target="_blank" rel="nofollow">详情</a>');
tr.append(th);
th = $("<th>");
th = th.html('<a onclick="" class="j" data-src="' + data.downloadURL + '" rel="nofollow">复制</a>');
th.click(function () {
url = $(this.firstElementChild).attr("data-src");
GM_setClipboard(url, "{ type: 'text', mimetype: 'text/plain'}");
msg_info("链接已复制");
});
tr.append(th);
th = $("<th>");
th = th.html("");// TODO data.date
tr.append(th);
th = $("<th>");
th = th.html(types[data.type]);
tr.append(th);
if (data.title.length > 45) {
th = $('<th class="link_title" data="' + data.title + '" style="max-height: 19px;">');
th = th.html(data.title.slice(0, 40) + "...");
th.jBox('Tooltip', {
id: 'jBox_dlinks_tooltip',
width: 280,
closeOnMouseleave: true,
animation: 'zoomIn',
zIndex: 8000,
content: th.attr("data")
});
tr.append(th);
} else {
th = $('<th class="link_title" style="max-height: 19px;">');
th = th.html(data.title);
tr.append(th);
}
//th = $("<th>");
//th = th.html(data.url);
//tr.append(th);
thead.append(tr);
},
print: function () {
this.clean();
var mag = [];
var ed2k = [];
var thunder = [];
var netdisk = [];
var all = [netdisk, mag, ed2k, thunder,];
for (i = 0; i < this.nodes.length; i++) {
var node = this.nodes[i];
if (node.type === 0) {
mag.push(node);
} else if (node.type === 1) {
ed2k.push(node);
} else if (node.type === 2) {
thunder.push(node);
} else if (node.type === 3) {
netdisk.push(node);
} else {
msg_warning("code:1001 msg:不支持当前链接格式.");
}
}//分类
for (var i = 0, n; (n = all[i]) != null; i++) {
if (n.length) {
//确保唯一
function unique(arr) {
var result = [], hash = {};
for (var i = 0, elem; (elem = arr[i]) != null; i++) {
if (!hash[elem.downloadURL]) {
result.push(elem);
hash[elem.downloadURL] = true;
}
}
return result;
};
n = unique(n);//绕了一大圈,其实只需要确保下载地址的唯一性
//加入
for (var i2 = 0, node; ((node = n[i2]) != null ) && i2 < config.c01; i2++) {
if (node) {
this._add(node);
}
}
}
}
//输出
/*
if (netdisk.length) {
for (i = 0; i < 3; i++) {
var node = netdisk[i];
if (node) {
this._add(node);
}
}
}
if (ed2k.length) {
for (i = 0; i < 3; i++) {
var node = ed2k[i];
if (node) {
this._add(node);
}
}
}
if (mag.length) {
for (i = 0; i < 3; i++) {
var node = mag[i];
if (node) {
this._add(node);
}
}
}
if (thunder.length) {
for (i = 0; i < 3; i++) {
var node = thunder[i];
if (node) {
this._add(node);
}
}
}
*/
},
refresh: function () {
this.nodes = [];
for (i = 0; i < dmovie.sites.length; i++) {
this.nodes = this.nodes.concat(dmovie.sites[i].nodes);
}
this.print();
},
act: function () {
$("#dtable").bootgrid();
}
};
var baidu_netdisk = {
id: "netdisk_table",
nodes: [],
hashtable: {},
init: function () {
var div, h2 = undefined;
div = $("<div>").attr({
id: this.id
});
h2 = $("<h2>");
h2 = h2.html("网盘信息");
div.append(h2);
$($("div.related-info")[0]).after(div);
var tr, th = undefined;
this.table = $("<table>").attr({
id: "nlinks",
class: "table table-condensed table-hover table-striped"
});
thead = $("<thead>");
tr = $("<tr>");
th = $("<th>").attr({"data-column-id": "copy", style: "width:33px"});
th = th.html(" ");
tr.append(th);
th = $("<th>").attr({"data-column-id": "detail", style: "width:33px"});
th = th.html(" ");
tr.append(th);
th = $("<th>").attr({"data-column-id": "title"});
th = th.html("详细信息");
tr.append(th);
thead.append(tr);
this.table.append(thead);
this.table.appendTo($("#netdisk_table"));
},
clean: function () {
$("#" + this.id).remove();
this.init();
},
add: function (sdoc) {
var re = /(pan.baidu.com\/s\/[a-zA-Z0-9]+)\s*.+\s*.([a-zA-Z0-9]{4})/g;
var m;
urls = [];
while ((m = re.exec(sdoc)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
var u = "http://" + m[1] + "#" + m[2];
urls.push(u);
}
this.verify(urls);
},//外部调用
_add: function (url,detail) {// TODO 链接文件名太长的,隐藏
thead = $($("#nlinks")[0].firstElementChild);
var tr, th = undefined;
tr = $('<tr style="max-height: 19px;">');
th = $("<th>");
th = th.html('<a href="' + url + '" target="_blank" rel="nofollow">查看</a>');
tr.append(th);
th = $("<th>");
th = th.html('<a onclick="" class="j" data-src="' + url + '" rel="nofollow">保存</a>');
th.click(function () {
msg_info("功能开发中...");
});
tr.append(th);
if (detail.length > 65) {
th = $('<th class="link_detail" data="' + detail + '" style="max-height: 19px;">');
th = th.html(detail.slice(0, 60) + "...");
th.jBox('Tooltip', {
id: 'jBox_baidu_tooltip',
width: 280,
closeOnMouseleave: true,
animation: 'zoomIn',
zIndex: 8000,
content: th.attr("data")
});
tr.append(th);
} else {
th = $('<th class="link_detail" style="max-height: 19px;">');
th = th.html(detail);
tr.append(th);
}
thead.append(tr);
},//内部调用
verify: function (data) {
type = Object.prototype.toString.call(data);
type = type.slice(1, type.length - 1).split(" ")[1];
if (type === "String") {
if (this.hashtable[data] === undefined) {
this._verify(data);
}
} else if (type === "Array") {
for (var i = 0, n; (n = data[i]) != null; i++) {
if (this.hashtable[n] === undefined) {
this._verify(n);
}
}
}
},
_verify: function (url) {
this.hashtable[url] = true;
getDoc(url, function (doc, url) {
//tmp = [url, doc];
if (doc.title === "百度云 网盘-链接不存在" || doc.title === "百度云升级") {
baidu_netdisk.hashtable[url] = false;
console.log("分享失效",url);
return;
}
if (doc.title === "百度云 请输入提取密码") {
baidu_netdisk._add(url,"带密码的分享");
/*
url = new URL(url);
var hash =url.hash.slice(1);
console.log("文件加密",hash);
var url = "http://pan.baidu.com/share/verify"+ url.search + "&t=" + (new Date().getTime());
var post = {
pwd: hash,
vcode: "",
vcode_str: ""
};
$.post(url,post,function (doc,url) {
try {
doc = $.parseJSON(doc);
} catch (e) {
return;
}
console.log(url, doc);
if (doc.errno ===-62){
baidu_netdisk.hashtable[url] = false;
//密码错误
}
});*/
return;
}
if (doc.title.endsWith("百度云 网盘-分享无限制")) {
console.log("分享正常",url);
baidu_netdisk._add(url,doc.title.split("|")[0]);
return;
}
console.log(url, doc.title);
});
},
print: function () {
this.clean();
var mag = [];
var ed2k = [];
var thunder = [];
var netdisk = [];
var all = [netdisk, mag, ed2k, thunder,];
for (i = 0; i < this.nodes.length; i++) {
var node = this.nodes[i];
if (node.type === 0) {
mag.push(node);
} else if (node.type === 1) {
ed2k.push(node);
} else if (node.type === 2) {
thunder.push(node);
} else if (node.type === 3) {
netdisk.push(node);
} else {
msg_warning("code:1001 msg:不支持当前链接格式.");
}
}//分类
for (var i = 0, n; (n = all[i]) != null; i++) {
if (n.length) {
//确保唯一
function unique(arr) {
var result = [], hash = {};
for (var i = 0, elem; (elem = arr[i]) != null; i++) {
if (!hash[elem.downloadURL]) {
result.push(elem);
hash[elem.downloadURL] = true;
}
}
return result;
};
n = unique(n);//绕了一大圈,其实只需要确保下载地址的唯一性
//加入
for (var i2 = 0, node; ((node = n[i2]) != null ) && i2 < config.c01; i2++) {
if (node) {
this._add(node);
}
}
}
}
//输出
/*
if (netdisk.length) {
for (i = 0; i < 3; i++) {
var node = netdisk[i];
if (node) {
this._add(node);
}
}
}
if (ed2k.length) {
for (i = 0; i < 3; i++) {
var node = ed2k[i];
if (node) {
this._add(node);
}
}
}
if (mag.length) {
for (i = 0; i < 3; i++) {
var node = mag[i];
if (node) {
this._add(node);
}
}
}
if (thunder.length) {
for (i = 0; i < 3; i++) {
var node = thunder[i];
if (node) {
this._add(node);
}
}
}
*/
},
refresh: function () {
this.nodes = [];
for (i = 0; i < dmovie.sites.length; i++) {
this.nodes = this.nodes.concat(dmovie.sites[i].nodes);
}
this.print();
},
};
///
edmag = {
s: title_cn,
nodes: [],
init: function () {
if (!title_cn) {
return;
}
this.url = "http://edmag.net/movie-search-" + this.s + ".html";
getDoc(this.url, function (doc, url) {
var trs = $("tr", doc);
var nodes = [];
for (i = 1; i < trs.length; i++) {
var tr = trs[i];
//tr.cat = trs[i].getElementsByClassName("cat")[0].textContent;
//tr.magTitle = trs[i]
var title = tr.getElementsByClassName("magTitle")[0].getElementsByTagName("a")[0];
var dURL = title.getAttribute("href");
dURL = "http://edmag.net" + dURL.slice(1);
title = title.getAttribute("title");
var time = tr.getElementsByClassName("time")[0].textContent;
var dow = tr.getElementsByClassName("dow")[0];
var ed2k, mag = undefined;
try {
mag = dow.getElementsByClassName("magDown")[0].getAttribute("href");
} catch (e) {
}
try {
ed2k = dow.getElementsByClassName("ed2kDown")[0].getAttribute("ed2k");
} catch (e) {
}
if (mag) {
var node = {
detailURL: dURL,
downloadURL: mag,
date: time,
type: 0,
title: title
};
edmag.nodes.push(node);
}
if (ed2k) {
var node = {
detailURL: dURL,
downloadURL: ed2k,
date: time,
type: 1,
title: title
};
edmag.nodes.push(node);
}
}
edmag.over();
});
},
over: function () {
var msg = "并入\t" + this.nodes.length + "\tedmag链接";
msg_info(msg);
linksTable.refresh();
}
};
mp4ba = {
// TODO 搜索间隔的自动重新搜索
s: title_cn,
count: 0,
nodes: [],
init: function () {
if (!title_cn) {
return;
}
var url = "http://www.mp4ba.com/search.php?keyword=" + this.s;
getDoc(url, function (doc) {
var urls = $("a[href^='show.php?hash=']", doc);
mp4ba.count = urls.length;
for (i = 0; i < urls.length; i++) {
var url = "http://www.mp4ba.com/" + urls[i].getAttribute("href");
getDoc(url, function (doc, url) {
//node{detailURL,downloadURL,date,type[0,1,2],title}
var mag = $("#magnet", doc)[0].getAttribute("href");
var title = $("div.location", doc)[0].textContent.split("»").pop();
title = title.trim();
var ps = $("p", doc);
var date = undefined;
for (i = 0; i < ps.length; i++) {
if (ps[i].textContent.startsWith("发布时间")) {
date = ps[i];
}
}
date = date.textContent.slice(5).trim();
//var size = $("span.right.text_normal", doc)[0].textContent;
//size = size.split(":").pop();
var node = {
detailURL: url,
downloadURL: mag,
date: date,
type: 0,
title: title
};
mp4ba.nodes.push(node);
baidu_netdisk.add(doc.body.outerText);
if (mp4ba.nodes.length >= mp4ba.count) {
mp4ba.over();
}
});
}
if (!urls.length) {
mp4ba.over();
}
});
},
over: function () {
var msg = "并入\t" + this.nodes.length + "\t\tmp4ba链接";
msg_info(msg);
linksTable.refresh();
}
};
tl95_com = {
s: title_cn,
count: 0,// TODO 相关逻辑的完善
nodes: [],
init: function () {
if (!title_cn) {
return;
}
url = "http://www.tl95.com/?s=" + this.s;
getDoc(url, function (doc, url) {
var urls = $($("#main", doc)[0]).find("a[rel='bookmark'][href]");
//标题匹配,过滤掉原网址的全文匹配
tl95_com.count = urls.length;
for (i = 0; i < urls.length; i++) {
var title = $(urls[i]).text();
if (title.indexOf(tl95_com.s) === -1) {
urls[i] = undefined;
--tl95_com.count;
}
}
for (i = 0; i < urls.length; i++) {
if (!urls[i]) {
continue;
}
url = urls[i].getAttribute("href");
getDoc(url, function (doc, url) {
var date = $("div.single-cat", doc)[0].textContent.split(" ")[0].slice(5);
//ed2k
var ed2k = $("a[href^='ed2k']", doc);
if (ed2k) {
for (i = 0; i < ed2k.length; i++) {
n = ed2k[i];
n = $(n);
var node = {
detailURL: url,
downloadURL: n.attr("href"),
date: date,
type: 1,
title: n.text()
};
tl95_com.nodes.push(node);
}
}
//thunder
var thunder = $("a[href^='thunder']", doc);
if (thunder) {
for (i = 0; i < thunder.length; i++) {
n = thunder[i];
n = $(n);
var node = {
detailURL: url,
downloadURL: n.attr("href"),
date: date,
type: 2,
title: n.text()
};
tl95_com.nodes.push(node);
}
}
//netdisk
baidu_netdisk.add(doc.body.outerText);
if (tl95_com.nodes.length >= tl95_com.count) {
tl95_com.over();
}
});
}
if (!urls.length) {
tl95_com.over();
}
});
},
over: function () {
var msg = "并入\t" + this.nodes.length + "\t\ttl95_cpm链接";
msg_info(msg);
linksTable.refresh();
}
};
kickass = {
//https://kat.cr/usearch/imdb:3284178/
s: imdb,
nodes: [],
init: function () {
if (!imdb) {
return;
}
var url = "https://kat.cr/usearch/imdb:" + this.s;
getDoc(url, function (doc, url) {
var s01 = "https://kat.cr";
var trs = $("tbody > tr.odd,tbody > tr.even", doc);
for (i = 0; i < trs.length; i++) {
var tr = trs[i];
tr = $(tr);
var cellMainLink = tr.find("a.cellMainLink");
var node = {
detailURL: s01 + cellMainLink.attr("href"),
downloadURL: tr.find("a[href^='magnet']").attr("href"),
date: $(tr.find("td[title]")[0]).attr("title"),
type: 0,
title: cellMainLink.text()
};
kickass.nodes.push(node);
}
kickass.over();
});
},
over: function () {
var msg = "并入\t" + this.nodes.length + "\t\tkickass链接";
msg_info(msg);
linksTable.refresh();
}
};
///
var dmovie = {
init: function () {
msg_warning("进入查询逻辑");
for (i = 0; i < dmovie.sites.length; i++) {
this.sites[i].init();
}
},
sites: [edmag,
kickass,
mp4ba,
tl95_com,
]
};
linksTable.init();
baidu_netdisk.init();
if (!title_cn) {
msg_error('title is null');
}
dmovie.init();
//addCSSfile("https://cdn.bootcss.com/jquery-bootgrid/1.3.1/jquery.bootgrid.min.css");
//jQuery.getScript("https://cdn.bootcss.com/jquery-bootgrid/1.3.1/jquery.bootgrid.min.js", function(data, status, jqxhr) {});
//
//linksTable.act();