// ==UserScript==
// @name 哔哩哔哩(B站|Bilibili)收藏夹Fix
// @namespace http://tampermonkey.net/
// @version 1.1
// @description 修复 哔哩哔哩(www.bilibili.com) 失效的收藏。(可查看av号、简介、标题、封面)
// @author Mr.Po
// @match https://space.bilibili.com/*
// @require http://code.jquery.com/jquery-1.11.0.min.js
// @resource iconError https://raw.githubusercontent.com/Mr-Po/bilibili-favorites-fix/master/media/error.png
// @resource iconSuccess https://raw.githubusercontent.com/Mr-Po/bilibili-favorites-fix/master/media/success.png
// @resource iconInfo https://raw.githubusercontent.com/Mr-Po/bilibili-favorites-fix/master/media/info.png
// @connect biliplus.com
// @grant GM_xmlhttpRequest
// @grant GM_notification
// @grant GM_setClipboard
// @grant GM_getResourceURL
// ==/UserScript==
(function() {
'use strict';
/**
* 失效收藏标题颜色(默认为灰色)
* @type {String}
*/
var invalTitleColor = "#999";
/**
* 是否启用调试模式
* 启用后,浏览器控制台会显示此脚本运行时的调试数据
* @type {Boolean}
*/
var isDebug = false;
/**
* 重试延迟[秒]
* @type {Number}
*/
var retryDelay = 5;
/**
* 每隔 space 毫秒检查一次,是否有新的微博被加载出来
* 此值越小,检查越快;过小会造成浏览器卡顿
* @type {Number}
*/
var space = 2000;
/**
* 收藏夹地址正则
* @type {RegExp}
*/
var favlistRegex = /https:\/\/space\.bilibili\.com\/\d+\/favlist.*/;
// 修改收藏
function updateFav() {
var flag = favlistRegex.test(window.location.href);
//console.log(flag);
if (flag) {
var $lis = $("ul.fav-video-list.content li.small-item.disabled");
if ($lis.size() > 0) {
console.info($lis.size() + "个收藏待修复...");
$lis.each(function(i, it) {
var aid = $(it).attr("data-aid");
var $as = $(it).find("a");
$as.attr("href", "https://www.biliplus.com/video/av" + aid + "/");
$as.attr("target", "_blank");
addCopyAVCodeButton($(it), aid);
fixTitleAndPic($(it), $($as[1]), aid);
$(it).removeClass("disabled");
$as.removeClass("disabled");
});
showDetail($lis);
}
}
}
function addOperation($item, name, fun) {
var $ul = $item.find(".be-dropdown-menu").first();
var lastChild = $ul.children().last();
// 未添加过扩展
if (!lastChild.hasClass('be-dropdown-item-extend')) {
lastChild.addClass("be-dropdown-item-delimiter");
}
var $li = $("<li class=\"be-dropdown-item be-dropdown-item-extend\">" + name + "</li>");
$li.click(fun);
$ul.append($li);
}
function addCopyAVCodeButton($item, aid) {
addOperation($item, "复制av号", function() {
GM_setClipboard("av" + aid, "text");
tipSuccess("av号复制成功!");
});
}
function addCopyInfoButton($item, content) {
addOperation($item, "复制简介", function() {
GM_setClipboard(content, "text");
tipSuccess("简介复制成功!");
});
}
// 标记失效
function signInval($it, $a) {
// 收藏时间
var $pubdate = $it.find("div.meta.pubdate");
$pubdate.attr("style", "text-decoration:line-through");
$a.attr("style", "text-decoration:line-through;color:" + invalTitleColor + ";");
}
// 绑定重新加载
function bindReload($a, fun) {
$a.text("->手动加载<-");
$a.click(function() {
$(this).unbind("click");
$a.text("Loading...");
fun();
});
}
// 再次尝试加载
function retryLoad($a, aid, retry, fun) {
console.warn("查询:av" + aid + ",请求过快!");
if (retry) { // 手动重试
$a.text("请求过快,请稍后[" + retryDelay + "]s再试!");
setTimeout(bindReload, retryDelay * 1000, $a, fun);
countdown($a, retryDelay);
} else { // 首次
$a.attr("href", "javascript:void(0);");
bindReload($a, fun);
}
}
// 加载倒计时
function countdown($a, second) {
if ($a.text().indexOf("请求过快") === 0) {
$a.text("请求过快,请稍后[" + second + "]s再试!");
if (second > 1) {
setTimeout(countdown, 1000, $a, second - 1);
}
}
}
// 修复成功
function fixSuccess($it, $a, aid, title, pic, history) {
// 设置标题
$a.text(title);
$a.attr("title", $a.text());
var $as = $it.find("a");
$as.attr("href", "https://www.biliplus.com/" + history + "video/av" + aid + "/");
signInval($it, $a);
isLoad(pic, function() {
var $img = $it.find("img");
$img.attr("src", pic);
});
}
// 修复标题和海报
function fixTitleAndPic($it, $a, aid) {
if (isDebug) {
console.log("fixTitleAndPic");
}
$a.text("Loading...");
fixTitleAndPicEnhance3($it, $a, aid);
}
// 修复标题和海报 增强 - 0
function fixTitleAndPicEnhance0($it, $a, aid, retry) {
if (isDebug) {
console.log("fixTitleAndPicEnhance0");
}
GM_xmlhttpRequest({
method: 'GET',
url: "https://www.biliplus.com/api/view?id=" + aid,
responseType: "json",
onload: function(response) {
var res = response.response;
if (isDebug) {
console.log("0---->:");
console.log(res);
}
// 找到了
if (res.title) {
fixSuccess($it, $a, aid, res.title, res.pic, "");
} else if (res.code == -503) { // 请求过快
retryLoad($a, aid, retry, function() {
fixTitleAndPicEnhance0($it, $a, aid, true);
});
} else { // 未找到
fixTitleAndPicEnhance1($it, $a, aid);
}
},
onerror: function(e) {
console.log("出错啦");
console.log(e);
}
});
}
// 修复标题和海报 增强 - 1
function fixTitleAndPicEnhance1($it, $a, aid) {
if (isDebug) {
console.log("fixTitleAndPicEnhance1");
}
GM_xmlhttpRequest({
method: 'GET',
url: "https://www.biliplus.com/all/video/av" + aid + "/",
onload: function(response) {
//console.log("1---->:"+response.responseText);
var params = response.responseText.match(/getjson\('(\/api\/view_all.+)'/);
fixTitleAndPicEnhance2($it, $a, aid, params[1]);
}
});
}
// 修复标题和海报 增强 - 2
function fixTitleAndPicEnhance2($it, $a, aid, param, retry) {
if (isDebug) {
console.log("fixTitleAndPicEnhance2");
}
GM_xmlhttpRequest({
method: 'GET',
url: "https://www.biliplus.com" + param,
responseType: "json",
onload: function(response) {
var res = response.response;
if (isDebug) {
console.log("2---->:");
console.log(res);
}
// 找到了
if (res.code === 0) {
fixSuccess($it, $a, aid, res.data.info.title, res.data.info.pic, "all/");
} else if (res.code == -503) { // 请求过快
retryLoad($a, aid, retry, function() {
fixTitleAndPicEnhance2($it, $a, aid, param, true);
});
} else { // 未找到
$a.text("已失效(" + aid + ")");
$a.attr("title", $a.text());
}
}
});
}
// 修复标题和海报 增强 - 3
function fixTitleAndPicEnhance3($it, $a, aid) {
if (isDebug) {
console.log("fixTitleAndPicEnhance3");
}
var jsonRegex;
GM_xmlhttpRequest({
method: 'GET',
url: "https://www.biliplus.com/video/av" + aid + "/",
onload: function(response) {
try {
if (isDebug) {
console.log("3---->:" + response.responseText);
}
jsonRegex = response.responseText.match(/window\.addEventListener\('DOMContentLoaded',function\(\){view\((.+)\);}\);/);
if (isDebug) {
console.log(jsonRegex);
}
var jsonStr = jsonRegex[1];
if (isDebug) {
console.log(jsonStr);
}
var res = $.parseJSON(jsonStr);
if (res.title) { // 存在
fixSuccess($it, $a, aid, res.title, res.pic, "");
} else if (res.code == -503) { // 请求过快
retryLoad($a, aid, null, function() {
fixTitleAndPicEnhance0($it, $a, aid, true);
});
} else { // 不存在
fixTitleAndPicEnhance1($it, $a, aid);
}
} catch (err) {
console.error(err);
console.log(jsonRegex);
// 当出现错误时,出现手动加载
retryLoad($a, aid, null, function() {
fixTitleAndPicEnhance0($it, $a, aid, true);
});
}
}
});
}
// 判断一个url是否可以访问
function isLoad(url, fun) {
$.ajax({
url: url,
type: 'GET',
success: function(response) {
fun();
},
error: function(e) {}
});
}
// 显示详细
function showDetail($lis) {
var fidRegex = window.location.href.match(/fid=(\d+)/);
var fid;
if (fidRegex) {
fid = fidRegex[1];
} else {
fid = $("div.fav-item.cur").attr("fid");
}
var pn = $("ul.be-pager li.be-pager-item.be-pager-item-active").text();
$.ajax({
url: "https://api.bilibili.com/medialist/gateway/base/spaceDetail?media_id=" + fid + "&pn=" + pn + "&ps=20&keyword=&order=mtime&type=0&tid=0&jsonp=jsonp",
success: function(json) {
var $medias = json.data.medias;
$lis.each(function(i, it) {
var aid = $(it).attr("data-aid");
var $mediaF = $medias.filter(function(it) {
if (it.id == aid) {
return it;
}
});
var $media = $mediaF[0];
var $a = $(it).find("a");
var titles = "";
if ($media.pages) {
var $titlesM = $media.pages.map(function(it, i, arry) {
return it.title;
});
titles = $titlesM.join("、");
}
var content = "av:" + aid + "\nP数:" + $media.page + "\n子P:" + titles + "\n简介:" + $media.intro;
$($a[0]).attr("title", content);
addCopyInfoButton($(it), content);
});
}
});
}
function tip(text, iconName) {
GM_notification({
text: text,
image: GM_getResourceURL(iconName)
});
}
function tipInfo(text) {
tip(text, "iconInfo");
}
function tipError(text) {
tip(text, "iconError");
}
function tipSuccess(text) {
tip(text, "iconSuccess");
}
setInterval(updateFav, space);
})();