// ==UserScript==
// @name 哔哩哔哩站内链接信息显示 BilibiliLinksInfos
// @namespace ckylin-bilibili-show-links-target
// @version 1.3
// @description 替换bilibili页面的视频链接为视频名,专栏链接为专栏文章名,音频链接为音频名
// @author CKylinMC
// @include *.bilibili.com/*
// @grant none
// @license GPL-3.0-only
// ==/UserScript==
(function () {
let opts = {
debug: false
};
function CKBilibiliLinksUtil(dom) {
const that = this;
this.dom = dom;
this.desIndex = 0;
this.des = [];
this.link = "";
this.dataInfo = {};
this.textprefix = "";
this.ensureHTTPSAddr = function (url) {
if (url.indexOf("//:") == 0) return url.replace("//:", "https://");
return url.replace("http://", "https://");
};
this.regMenuEvent = function () {
that.dom.oncontextmenu = function (e) {
that.desIndex++;
if (that.desIndex >= that.des.length) that.desIndex = 0;
//that.dom.innerHTML = that.des[that.desIndex];
that.setText(that.des[that.desIndex]);
return false;
}
}
this.generateDes = function () {
if ("type" in this.dataInfo) {
switch (this.dataInfo.type) {
case "video":
that.des.push(this.dataInfo.aid);
that.des.push(this.dataInfo.bvid);
that.des.push(that.link);
break;
case "article":
that.des.push(that.link);
break;
case "audio":
that.des.push(that.link);
break;
}
}
};
this.addText = function (txt) {
that.setText(that.getText() + txt);
}
this.setText = function (txt) {
that.dom.innerHTML = that.textprefix + txt;
}
this.getText = function () {
return that.dom.innerHTML.replace(that.textprefix,"");
}
this.doGetInfos = function () {
if (this.dom instanceof HTMLElement) {
if (!('href' in this.dom)) return;
if (this.dom.className != "dynamic-link-hover-bg" && this.dom.className != "") return;
if (this.dom.className == "dynamic-link-hover-bg") {
this.textprefix = '<i class="bp-svg-icon link" style="position:relative;top:-1px;margin-left:2px;"></i>';
}
if ((this.dom.href.indexOf("https://www.bilibili.com/video/") == 0 || this.dom.href.indexOf("http://www.bilibili.com/video/") == 0 || this.dom.href.indexOf("//www.bilibili.com/video/") == 0) && !this.dom.hasAttribute("data-blblinfo")) {
this.dom.setAttribute("data-blblinfo", true);
this.addText(" (正在获取信息...)");
setTimeout(() => {
this.link = this.ensureHTTPSAddr(this.dom.href);
fetch("https://api.bilibili.com/x/web-interface/view" + this.getAPIParam())
.then(res => res.json())
.then(json => {
if (json.code == 0) {
that.dataInfo = json.data;
that.dataInfo.isOk = true;
that.dataInfo.aid = "av" + that.dataInfo.aid;
that.dataInfo.type = "video";
} else {
that.dataInfo.isOk = false;
that.dataInfo.fetchError = false;
that.dataInfo.message = json.message;
}
}, failReason => {
that.dataInfo.isOk = false;
that.dataInfo.fetchError = true;
that.dataInfo.message = failReason;
that.setText(that.getText().replace(" (正在获取信息...)", " (信息获取失败)"));
that.des = [that.dom.innerHTML];
})
.then(() => {
if (that.dataInfo.isOk) {
that.setText("[视频] " + that.dataInfo.title);
that.des = [that.dom.innerHTML];
that.generateDes();
that.regMenuEvent();
} else if (!that.dataInfo.fetchError) {
that.setText(that.getText().replace(" (正在获取信息...)", " (视频不存在或已删除)"));
that.des = [that.dom.innerHTML];
//that.dom.style.color = "rgb(86, 86, 86)";
//that.generateDesFromUrl();
that.dom.style.textDecoration = "line-through";
}
})
}, 100);
} else if ((this.dom.href.indexOf("https://www.bilibili.com/read/cv") == 0 || this.dom.href.indexOf("http://www.bilibili.com/read/cv") == 0 || this.dom.href.indexOf("//www.bilibili.com/read/cv") == 0) && !this.dom.hasAttribute("data-blblinfo")) {
this.dom.setAttribute("data-blblinfo", true);
this.addText(" (正在获取信息...)");
setTimeout(() => {
this.link = this.ensureHTTPSAddr(this.dom.href);
fetch("https://api.bilibili.com/x/article/viewinfo" + this.getAPIParam())
.then(res => res.json())
.then(json => {
if (json.code == 0) {
that.dataInfo = json.data;
that.dataInfo.isOk = true;
that.dataInfo.type = "article";
that.dataInfo.cid = this.getCidFromLink();
} else {
that.dataInfo.isOk = false;
that.dataInfo.fetchError = false;
that.dataInfo.message = json.message;
}
}, failReason => {
that.dataInfo.isOk = false;
that.dataInfo.fetchError = true;
that.dataInfo.message = failReason;
that.setText(that.getText().replace(" (正在获取信息...)", " (信息获取失败)"));
that.des = [that.dom.innerHTML];
})
.then(() => {
if (that.dataInfo.isOk) {
that.setText("[专栏] " + that.dataInfo.title);
that.des = [that.dom.innerHTML];
that.generateDes();
that.regMenuEvent();
} else if (!that.dataInfo.fetchError) {
that.setText(that.getText().replace(" (正在获取信息...)", " (专栏不存在或已删除)"));
that.des = [that.dom.innerHTML];
//that.dom.style.color = "rgb(86, 86, 86)";
//that.generateDesFromUrl();
that.dom.style.textDecoration = "line-through";
}
})
}, 100);
} else if ((this.dom.href.indexOf("https://www.bilibili.com/audio/au") == 0 || this.dom.href.indexOf("http://www.bilibili.com/audio/au") == 0 || this.dom.href.indexOf("//www.bilibili.com/audio/au") == 0) && !this.dom.hasAttribute("data-blblinfo")) {
this.dom.setAttribute("data-blblinfo", true);
this.addText(" (正在获取信息...)");
setTimeout(() => {
this.link = this.ensureHTTPSAddr(this.dom.href);
fetch("https://www.bilibili.com/audio/music-service-c/web/song/info" + this.getAPIParam())
.then(res => res.json())
.then(json => {
if (json.code == 0) {
that.dataInfo = json.data;
that.dataInfo.isOk = true;
that.dataInfo.type = "audio";
that.dataInfo.cid = this.getSidFromLink();
} else {
that.dataInfo.isOk = false;
that.dataInfo.fetchError = false;
that.dataInfo.message = json.message;
}
}, failReason => {
that.dataInfo.isOk = false;
that.dataInfo.fetchError = true;
that.dataInfo.message = failReason;
that.setText(that.getText().replace(" (正在获取信息...)", " (信息获取失败)"));
that.des = [that.dom.innerHTML];
})
.then(() => {
if (that.dataInfo.isOk) {
that.setText("[音频] " + that.dataInfo.title + "(" + that.dataInfo.author + ")");
that.des = [that.dom.innerHTML];
that.generateDes();
that.regMenuEvent();
} else if (!that.dataInfo.fetchError) {
that.setText(that.getText().replace(" (正在获取信息...)", " (音频不存在或已删除)"));
that.des = [that.dom.innerHTML];
//that.dom.style.color = "rgb(86, 86, 86)";
//that.generateDesFromUrl();
that.dom.style.textDecoration = "line-through";
}
})
}, 100);
}
}
};
this.getCidFromLink = function () {
var id;
var tmpindex = that.link.indexOf("/cv");
id = that.link.substr(tmpindex + 1);
if (id.indexOf("/")) {
id = id.split("/")[0];
}
if (id.indexOf("?")) {
id = id.split("?")[0];
}
if (id.indexOf("#")) {
id = id.split("#")[0];
}
return id;
}
this.getSidFromLink = function () {
var id;
var tmpindex = that.link.indexOf("/audio/au");
id = that.link.substr(tmpindex + 7);
if (id.indexOf("/")) {
id = id.split("/")[0];
}
if (id.indexOf("?")) {
id = id.split("?")[0];
}
if (id.indexOf("#")) {
id = id.split("#")[0];
}
return id;
}
this.getAPIParam = function () {
var tmpindex, id, key = "aid";
if ((tmpindex = that.link.indexOf("/av")) != -1) {
id = that.link.substr(tmpindex + 1);
if (id.indexOf("/") != -1) {
id = id.split("/")[0];
}
if (id.indexOf("?") != -1) {
id = id.split("?")[0];
}
if (id.indexOf("#") != -1) {
id = id.split("#")[0];
}
id = id.substr(2);
} else if ((tmpindex = that.link.indexOf("/BV1")) != -1 || (tmpindex = that.link.indexOf("/bv1")) != -1) {
key = "bvid";
id = that.link.substr(tmpindex + 1);
if (id.indexOf("/") != -1) {
id = id.split("/")[0];
}
if (id.indexOf("?") != -1) {
id = id.split("?")[0];
}
if (id.indexOf("#") != -1) {
id = id.split("#")[0];
}
} else if ((tmpindex = that.link.indexOf("/cv")) != -1) {
key = "id";
id = this.getCidFromLink();
id = id.substr(2);
} else if ((tmpindex = that.link.indexOf("/au")) != -1) {
key = "sid";
id = this.getSidFromLink();
id = id.substr(2);
}
return "?" + key + "=" + id;
};
}
function CK_getParentElements(el){
if(!(el instanceof HTMLElement)) return [];
let els = [];
while(el.parentElement){
el = el.parentElement;
els.push(el);
}
return els;
}
function CK_parentsHasClass(el,className){
let hasclass = false;
CK_getParentElements(el).forEach(e=>{
if(e.classList.contains(className)) hasclass = true;
});
return hasclass;
}
function CK_parentsHasClassSeries(el,className){
let hasclass = false;
CK_getParentElements(el).forEach(e=>{
e.classList.forEach(i=>{
if(i.startsWith(className)) hasclass = true;
})
});
return hasclass;
}
function CK_parentsHasId(el,id){
let hasid = false;
CK_getParentElements(el).forEach(e=>{
if(e.id===id) hasid = true;
});
return hasid;
}
function CK_verifyElements(el){
if(!(el instanceof HTMLElement)) {
CK_debug("it's not a element\n",el);
return false;
}
if(el.tagName!="A") {
CK_debug("it's not a link\n",el);
return false;
}
if(el.hasAttribute("title")) {
CK_debug("it contained a title\n",el);
return false;
}
if(CK_parentsHasClassSeries(el,"video-card")) {
CK_debug("it has a banned parent with class 'card'\n",el);
return false;
}
/*if(CK_parentsHasId(el,"series")) {
//CK_debug("it has a banned parent with ID 'series'\n",el);
return false;
}*/
return true;
}
function CK_debug(){
if(opts.debug) console.info("[CKBLI] ",...arguments);
}
function doUpdateAllLinksHook() {
document.querySelectorAll("a").forEach((e, i) => {
e.onmouseover = e => {
if (CK_verifyElements(e.target)) {
(new CKBilibiliLinksUtil(e.target)).doGetInfos();
}
}
});
}
document.addEventListener("DOMSubtreeModified", function (e) {
doUpdateAllLinksHook();
});
/*window.blblinfo_globalSelect = false;
document.addEventListener("mousemove", function (e) {
if (!window.blblinfo_globalSelect) return;
e.path.forEach(el => {
if (el.tagName == "a") {
(new CKBilibiliLinksUtil(el)).doGetInfos();
}
})
})
document.addEventListener("keydown", function (e) {
if (e.key != "Control") return;
if (window.blblinfo_globalSelect) return;
console.log("window.blblinfo_globalSelect = true;");
window.blblinfo_globalSelect = true;
});
document.addEventListener("keyup", function (e) {
if (e.key != "Control") return;
if (!window.blblinfo_globalSelect) return;
console.log("window.blblinfo_globalSelect = false;");
window.blblinfo_globalSelect = false;
});*/
doUpdateAllLinksHook();
})();