您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在视频标题下方插入链接,点击可以通过访问B站API查看视频详情
// ==UserScript== // @name Bilibili Video Detail // @name:zh-CN 哔哩哔哩视频详情 // @namespace http://tampermonkey.net/ // @version 1.5 // @description Insert a hyperlink under video title named "info" to get the video details by BV code through Bilibili API. // @description:zh-CN 在视频标题下方插入链接,点击可以通过访问B站API查看视频详情 // @author philimao // @match https://www.bilibili.com/video/* // @match https://www.bilibili.com/opus/* // @match https://t.bilibili.com/* // @icon https://www.google.com/s2/favicons?domain=bilibili.com // @grant unsafeWindow // @license MIT // ==/UserScript== (async function () { // for video async function playerReady() { let counter = 0; return new Promise((resolve) => { function wait() { if ( unsafeWindow.player && unsafeWindow.player.isInitialized && unsafeWindow.player.isInitialized() ) { return resolve(); } if (counter === 10000) { console.log("[BiliDetail] Player Timeout, Increase Interval"); } counter++; const timeout = counter < 10000 ? 500 : 2000; if (counter % 10000 === 0) console.log("[BiliDetail] Waiting", counter, timeout); setTimeout(wait, timeout); } setTimeout(wait, 3000); }); } // for dynamic async function titleReady(titleClass) { let counter = 0; return new Promise((resolve, reject) => { const id = setInterval(() => { if (document.querySelector(titleClass)) resolve(clearInterval(id)); if (counter > 50) { reject(clearInterval(id)); } counter++; }, 200); }); } function setSessionSpeed(speed) { const data = JSON.parse( window.sessionStorage.getItem("bilibili_player_settings") ); data.video_status.videospeed = speed; window.sessionStorage.setItem( "bilibili_player_settings", JSON.stringify(data) ); } function injectSpeedIcon() { const video = document.querySelector("video"); const playerStyle = document.querySelector(".bpx-player-container") ? 0 : 1; let ul; if (playerStyle) ul = document.querySelector("ul.bilibili-player-video-btn-speed-menu"); else ul = document.querySelector("ul.bpx-player-ctrl-playbackrate-menu"); if (!ul) return console.log("[BiliDetail] Speed Icon Not Detected"); let x3 = playerStyle ? document.querySelector(".bilibili-player-video-btn-speed-menu-list[data-value='3']") : document.querySelector(".bpx-player-ctrl-playbackrate-menu-item[data-value='3']"); if (x3) return; const sp3 = document.createElement("li"); sp3.innerText = "3.0x"; if (playerStyle) sp3.className = "bilibili-player-video-btn-speed-menu-list "; else sp3.className = "bpx-player-ctrl-playbackrate-menu-item "; sp3.setAttribute("data-value", "3"); sp3.addEventListener("click", () => { if (playerStyle) sp3.classList.add("bilibili-player-active"); else sp3.classList.add("bpx-state-active"); video.playbackRate = 3; setSessionSpeed(3); // showSpeed.innerText = "3.0x"; }); const sp4 = document.createElement("li"); sp4.innerText = "4.0x"; if (playerStyle) sp4.className = "bilibili-player-video-btn-speed-menu-list "; else sp4.className = "bpx-player-ctrl-playbackrate-menu-item "; sp4.setAttribute("data-value", "4"); sp4.addEventListener("click", () => { if (playerStyle) sp4.classList.add("bilibili-player-active"); else sp4.classList.add("bpx-state-active"); video.playbackRate = 4; setSessionSpeed(4); // showSpeed.innerText = "4.0x"; }); ul.insertBefore(sp3, ul.firstElementChild); ul.insertBefore(sp4, ul.firstElementChild); document .querySelectorAll(".bilibili-player-video-btn-speed-menu-list") .forEach((el) => el.addEventListener("click", () => { document .querySelectorAll( playerStyle ? ".bilibili-player-video-btn-speed-menu-list.bilibili-player-active" : ".bpx-player-ctrl-playbackrate-menu-item.bpx-state-active" ) .forEach((active) => { // 切回1.0x时有问题 if (active && active.innerHTML !== el.innerHTML) { if (playerStyle) active.classList.remove("bilibili-player-active"); else active.classList.remove("bpx-state-active"); } }); }) ); } function registerPageObserver() { const target = unsafeWindow.__INITIAL_STATE__; let videoData = target.videoData; const desc = Object.getOwnPropertyDescriptor(target, "videoData"); const vueHook = desc.set; Object.defineProperty(target, "videoData", { get: desc.get || (() => videoData), set(data) { videoData = data; injectSpeedIcon(); if (vueHook) vueHook.call(this, data); }, enumerable: true, configurable: true, }); } const info = document.createElement("a"); info.id = "custom_info"; info.innerText = "info"; info.style.height = "16px"; info.style.color = "#999"; info.style.marginLeft = "12px"; info.target = "_blank"; let titleClass, isVideo; if (window.location.href.includes("video")) { const match = window.location.href.match(/BV[^?#&\/]*/); if (match) { info.href = "https://api.bilibili.com/x/web-interface/view?bvid=" + match[0]; titleClass = ".video-info-detail-list"; isVideo = true; info.style.paddingBottom = "3px"; } } else { const match = window.location.href .split("spm_id_from")[0] .split("tab")[0] .match(/\d+/); if (match) { info.href = "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=" + match[0]; if (window.location.href.includes("opus")) titleClass = ".opus-module-author__pub" else titleClass = ".bili-dyn-time"; } } if (titleClass) { if (isVideo) await playerReady(); else await titleReady(titleClass); const bvid = unsafeWindow?.__INITIAL_STATE__?.bvid; if (bvid) info.innerText = bvid; document.querySelector(titleClass).appendChild(info); console.log("[BiliDetail] Custom Info Icon Injected.", bvid); if (isVideo) { injectSpeedIcon(); registerPageObserver(); console.log("[BiliDetail] Speed Control Injected."); const observer = new MutationObserver((mutationList, observer) => { console.log( "[BiliDetail] New Custom Info Icon Injected", bvid ); info.innerText = bvid; info.href = "https://api.bilibili.com/x/web-interface/view?bvid=" + bvid; document.querySelector(titleClass).appendChild(info); }); observer.observe(document.querySelector(".video-info").children[0], { attributes: true, }); } } })();