🏠 

BVHover

B站视频评论区BV信息显示


安装此脚本?
// ==UserScript==
// @name         BVHover
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  B站视频评论区BV信息显示
// @author       KeJun
// @include      *://www.bilibili.com/video/BV*
// @require      https://unpkg.com/@popperjs/core@2
// @require      https://unpkg.com/tippy.js@6
// @require      https://unpkg.com/[email protected]/anime.min.js
// ==/UserScript==
"use strict";
const api = {
view: "https://api.bilibili.com/x/web-interface/view?bvid=",
videoshot: "https://api.bilibili.com/x/player/videoshot?bvid=",
};
const log = console.log.bind(console, "[BVHOVER]:");
function throttle(fun, delay) {
let last, deferTimer;
return function (args) {
let that = this;
let _args = arguments;
let now = +new Date();
if (last && now < last + delay) {
clearTimeout(deferTimer);
deferTimer = setTimeout(function () {
last = now;
fun.apply(that, _args);
}, delay);
} else {
last = now;
fun.apply(that, _args);
}
};
}
// 过滤未添加事件的元素
function getBVATag(comment) {
return Array.from(comment.querySelectorAll("a")).filter((v) => !v.instance);
}
// 获取数据设置事件等乱七八糟
async function getDataAndSetEvent(ele) {
const bvid = ele.innerText;
if (!/^(bv|BV)[a-zA-Z0-9]{10}$/.test(bvid)) return;
ele.instance = tippy(ele, {
content: "加载中...",
interactiveBorder: 5,
interactive: true,
});
try {
const { data: viewData } = await (await fetch(`${api.view}${bvid}`)).json();
const { data: videoshotData } = await (
await fetch(`${api.videoshot}${bvid}`)
).json();
const { title, pic: image } = viewData;
const [shotImage] = videoshotData.image;
const boxEl = document.createElement("div");
const titleEl = document.createElement("marquee");
const imageEl = document.createElement("div");
imageEl.style.backgroundImage = `url(${image})`;
imageEl.style.backgroundSize = "cover";
imageEl.style.width = boxEl.style.width = "160px";
imageEl.style.height = "90px";
titleEl.innerText = title;
boxEl.style.margin = "5px 0 ";
boxEl.append(titleEl, imageEl);
ele.instance.setContent(boxEl);
let PX = new Array(10)
.fill(
new Array(10).fill({}).map((v, i) => ({
value: `-${i * 160}px`,
delay: 100,
}))
)
.flat();
let PY = new Array(10).fill({}).map((v, i) => ({
value: `-${i * 90}px`,
delay: 1000,
}));
imageEl.addEventListener("mouseover", function () {
if (!shotImage) return;
imageEl.style.backgroundSize = "auto";
imageEl.style.backgroundImage = `url(${shotImage})`;
imageEl.animation = anime({
targets: imageEl,
backgroundPositionX: PX,
backgroundPositionY: PY,
loop: true,
duration: 1,
});
});
imageEl.addEventListener("mouseout", function () {
if (!imageEl.animation) return;
imageEl.style.backgroundImage = `url(${image})`;
imageEl.style.backgroundSize = "cover";
imageEl.animation.restart();
imageEl.animation.pause();
});
} catch (e) {
log(e);
ele.instance.setContent("加载失败!");
}
}
// 悬停事件
// 本来打算使用事件委托,最后想想感觉还不如这样实现好
const hoverHandle = throttle(function (target) {
getBVATag(target).forEach((v) => getDataAndSetEvent(v));
}, 1000);
(function () {
log("脚本启动");
document
.querySelector("#comment")
.addEventListener("mouseover", async ({ target }) => {
hoverHandle(target);
});
document
.querySelector("#v_desc")
.addEventListener("mouseover", async ({ target }) => {
hoverHandle(target);
});
})();