// ==UserScript== // @name B站简化 // @namespace https://github.com/huanfeiiiii/UserScript/tree/main/bilibiliSimplified // @version 0.6.1 // @description 简化B站 // @author huanfei // @match *.bilibili.com/* // @match https://t.bilibili.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @connect app.bilibili.com // @connect api.bilibili.com // @connect www.mcbbs.net // @connect passport.bilibili.com // @license WTFPL // @run-at document-start // ==/UserScript== (function () { var style = ""; var recommendData = new Array(); var accessKey = GM_getValue("accessKey") ? GM_getValue("accessKey") : ""; const url = window.location.href.match("[a-zA-z]+://(.*)/")[1]; if (url == "www.bilibili.com") { console.log("首页"); homePage(); } else if (url == "t.bilibili.com") { console.log("动态"); dynamicPage(); } else if (url.match("www.bilibili.com/(.*)")) { if (url.split("/")[1] == "video") { console.log("视频播放页"); videoPlayPage(); } else if (url.match("www.bilibili.com/(.*)")[1] == "read") { console.log("专栏页"); readPage(); } } else if (url.includes("space.bilibili.com")) { console.log("个人空间"); spacePage(); } GM_addStyle(style); function homePage() {} function dynamicPage() { // 精选评论 style += ".bili-dyn-item__interaction{display:none;}"; // 右上角贴纸 style += ".bili-dyn-item__ornament{display:none;}"; // 头像边框 style += ".bili-avatar-pendent-dom{display:none;}"; // 右上角按钮 style += ".bili-dyn-item__more{display:none;}"; // 右边话题 style += "aside.right .sticky{display:none;}"; let timer = setInterval(function () { if (document.querySelector("aside.right")) { clearInterval(timer); if (!accessKey) { getAccessKey(); } setRecommend(); getRecommendData(); scrollRefsh(); } }); } function videoPlayPage() { // 头像框 style += ".bili-avatar-pendent-dom{display:none;}"; // 右上角贴纸 style += ".reply-decorate{display:none;}"; // 大家都围观的直播 style += ".pop-live-small-mode{display:none;}"; // 活动 style += ".activity-m-v1{display:none;}"; // 联合创作页面作者头像下面的关注按钮,防止误触 style += ".attention{display:none !important;}"; // 去除弹幕弹窗 style += ".bpx-player-cmd-dm-wrap{display:none !important;}"; } function readPage() { // 专栏去除复制小尾巴 window.onload = function () { [...document.querySelectorAll("*")].forEach((item) => { item.oncopy = function (e) { e.stopPropagation(); }; }); }; } function spacePage() { // 解决选择视频排序时,页面序号没有回到第一个的问题 let buttons = document.getElementsByClassName("be-tab-input"); window.onload = function () { buttons.forEach(function (e) { e.addEventListener("change", function () { document.querySelector("#submit-video-list > ul.be-pager > li:nth-child(2)").click() }); }); }; } function setRecommend() { // 设置推荐元素 let style = ` .recommend_switch{display:flex;align-items:center;margin:0 15px 0 auto} .recommend_switch p{color:#6D757A;font-size:14px;line-height:100%} .switch_button{position:relative;margin-left:15px;width:35px;height:20px;border-radius:10px;background:#9499A0;cursor:pointer} .switch_button::before{position:absolute;top:2px;left:3px;width:16px;height:16px;border-radius:100%;background-color:#FFFFFF;content:'';transition:all 0.2s} .switch_button.on{background:#00A1D6} .switch_button.on::before{left:16px} .recommend_content{margin-bottom:8px;padding:10px;border-radius:5px;background-color:#FFFFFF} .video_content{position:relative;display:flex;width:100%} .video_content .preview_pic{position:absolute;top:0;width:100%;height:-moz-available;height:-webkit-fill-available} .video_content img{width:100%} .video_content:hover .video_mask{opacity:0} .video_mask{position:absolute;bottom:0;display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;padding:16px 8px 6px;width:100%;background-image:linear-gradient(180deg,rgba(0,0,0,0) 0,rgba(0,0,0,0.8) 100%);color:#FFFFFF;font-size:14px;font-size:13px;line-height:18px;transition:opacity 1s} .video_mask .views{display:flex;align-items:center} .video_mask .views svg{margin-right:3px;width:18px;height:18px} .video_mask .views .num{margin:0} .video_mask .views p:nth-child(2){margin-right:10px} .video_mask .duration{height:100%} .video_text{margin-top:10px} .video_text a:hover{color:#00AEEC} .video_text .video_title{display:-webkit-box;overflow:hidden;-webkit-box-orient:vertical;text-overflow:ellipsis;font-size:16px;-webkit-line-clamp:2;overflow-wrap:anywhere} .video_text .owner{display:flex;margin-top:5px;color:#9499A0;font-size:14px} .video_text .owner .up_name{display:flex} .video_text .owner .up_name svg{margin-right:5px;width:18px;height:18px} .video_text .owner p{margin:0;line-height:18px} .video_text .owner .time{margin-left:10px} .video_content:hover .video_mark{opacity:1} .video_mark{position:absolute;top:10px;right:10px;width:22px;height:22px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAABT0lEQVQ4je3VMYrCQBTG8b/DWASLNKJgJ1hY2sloZeF2gkeYW+wZvIVXsLBJY5UdtLJLk17EIghCwChukWRxFzSaaLdfMwm8/EgemTclgOl02gEmwAAoky8RsAA+tdbrUoJ+AVZO8G9CoCeJ39Sq1+sopbBtO5e23+8xxrDdbi1gIog/vxAKYNs2Sqn0diBIenoP9X2fIAgyccv66WZZZBXvdjtc18UYkwlfJxM+n8+/1pfBefMPPw4LEZcEQcBqteJ0Or0GrlartFotLpcLnucxm83YbDbFYSEE/X6f4XBIpVLhcDjgOA6u63I8HvPDaRqNBuPxmHa7DcS7cT6f36yXj8IAUkq63S7NZpPlcomUtx9/Ck5Tq9UYjUZ3a976u0UQz9OiCcMwvYwk8XHyYYxBKXU9+p5Grybg4m1Hk9Bar4Ee4JC0JWeixOhprdffE/1yRW/TLMYAAAAASUVORK5CYII=);background-position:50%;background-size:cover;background-repeat:no-repeat;opacity:0;transition:opacity 0.2s cubic-bezier(0.22,0.58,0.12,0.98)} .video_mark.active{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAABiklEQVQ4jbXVzyvDcRzH8efns1+JIRtbOSiKrMRBrZZC5IzcHJYTJyc1J464ubuY5MQ/oLSTNSHfIg5KyEmbzY/5sa++c/hOCtv47rvX8f2pR+/3u0+fjwAgfNoFLAH9gA1jUYEIECLoU0QOjQIVBsHveQECEr1Ts1By1pJEH9/s9EuM77RQbLIMKACG4QaHhYNBL7EBj3lwtU2yFXDT6rRil8Ic2C4F634XnbU24m8aY9F46bAUsNJdR1+9g6f3LKPROBfp99LhxY5aRhorULUs43sJlFQmfxO/FWMDHpQhL+3VXzdxps3JVEsVAJOHSSK3rwWbsP5WtAhorrSy09vAxH6CeoeFOV8NALPHKTZvnovMBoLwafZ7sc4uWfe76HE70HKnUsDy+SNzJ/dFUciziruMxvBunNXLNFLo6Mb1M/N/RCHPKgAyWpbpoyQHdxmaKi0snD3wYzQj8GfWrtL/4L5S1rdCLYOrSvTvxOxEJBBC/07MygsQkgR9ChAAtiltLWrOCBD0KR9smmovo1v+1QAAAABJRU5ErkJggg==)} .video_mark:hover .video_mark_text{opacity:1} .video_mark_text{position:absolute;top:-27px;left:50%;box-sizing:border-box;padding:6px 8px;border-radius:4px;background:rgba(0,0,0,0.7);color:#FFFFFF;white-space:nowrap;font-size:12px;line-height:12px;opacity:0;transform:translateX(-50%)} .preview_pic{display:none} .preview_bar{box-sizing:border-box;width:100%;height:10px;border:solid #000000;border-top-width:4px;border-right-width:8px;border-bottom-width:4px;border-left-width:8px;background-color:#444444} .bar_content{width:100%;height:2px;background-color:#FFFFFF} `; GM_addStyle(style); let main = document.createElement("div"); main.id = "dynamic_recommend"; document.querySelector("aside.right").appendChild(main); // 推荐开关 let recommend_switch = document.createElement("div"); recommend_switch.className = "recommend_switch"; recommend_switch.innerHTML = `

推荐视频

`; document.querySelector(".bili-dyn-list-tabs__list").appendChild(recommend_switch); let button = recommend_switch.querySelector(".switch_button"); // 按钮点击 button.onclick = function () { if (button.classList.contains("on")) { button.classList.remove("on"); GM_setValue("recommend_status", false); } else { button.classList.add("on"); GM_setValue("recommend_status", true); } recommendShow(); }; recommendShow(); function recommendShow() { if (button.classList.contains("on")) { main.style.display = "block"; } else { main.style.display = "none"; } } } function addRecommend() { // 添加推荐视频 let data = recommendData.pop(); let url = `https://www.bilibili.com${data.goto == "av" ? `/video/av${data.param}` : data.uri}`; let text = `
${
            data.title
        }

${numConverter.view( data.play )}

${numConverter.view( data.like )}

${numConverter.duration( data.duration )}
${ data.title }

${ data.name }

${numConverter.getTime(data.ctime).mini}

`; let dom = document.createElement("div"); dom.className = "recommend_content"; dom.innerHTML = text; document.getElementById("dynamic_recommend").appendChild(dom); // 悬浮预览 hoverPreview(dom, data.param); // 添加稍后在看 addMarkVideo(dom.querySelector(".video_mark"), data.param); } function getRecommendData() { // 获取推荐API数据 GM_xmlhttpRequest({ method: "GET", url: "https://app.bilibili.com/x/feed/index?build=1&mobi_app=android&idx=" + (Date.now() / 1000).toFixed(0) + (accessKey ? "&access_key=" + accessKey : ""), onload: (res) => { try { var list = JSON.parse(res.response); if (list.code != 0) { console.error(`获取推荐数据失败 code ${list.code}
msg:${list.message}`); return; } else { recommendData.push.apply(recommendData, list.data); } } catch (e) { console.error("获取推荐数据失败"); } }, onerror: (e) => { console.error(e, "请求app首页发生错误"); }, }); } const numConverter = { // 数量 view(num) { num = Number(num); if (Math.abs(num) > 100000000) { return (num / 100000000).toFixed(1) + "亿"; } else if (Math.abs(num) > 10000) { return (num / 10000).toFixed(1) + "万"; } else { return num.toFixed(0); } }, // 时长换算 duration(num) { let second = num % 60; let minute = Math.floor(num / 60); let hour; if (minute > 60) { hour = Math.floor(minute / 60); minute = minute % 60; } if (second < 10) second = "0" + second; if (minute < 10) minute = "0" + minute; return hour ? `${hour}:${minute}:${second}` : `${minute}:${second}`; }, // 时间戳换算 getTime(timestamp) { let date = new Date(parseInt(timestamp) * 1000); let Year = date.getFullYear(); let Moth = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; let Day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); let Hour = date.getHours() < 10 ? "0" + date.getHours() : date.getHours(); let Minute = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes(); let Sechond = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds(); let GMT = Year + "-" + Moth + "-" + Day + " " + Hour + ":" + Minute + ":" + Sechond; let miniGMT = Moth + "-" + Day; return { full: GMT, mini: miniGMT, }; }, }; function hoverPreview(dom, aid) { // 悬停预览 let seed; let hoverDom = dom.querySelector("a"); let picDom = dom.querySelector(".preview_pic"); let bar = dom.querySelector(".bar_content"); hoverDom.addEventListener("mouseenter", function (e) { seed = setTimeout(function () { // 鼠标悬停事件 getPic(); }, 300); }); hoverDom.addEventListener("mousemove", function (e) { // 鼠标移动事件 if (picDom.dataset.num) { setPic(e.offsetX); } }); hoverDom.addEventListener("mouseleave", function () { // 鼠标离开事件 picDom.style.display = "none"; clearTimeout(seed); }); function getPic() { if (picDom.dataset.num) { picDom.style.display = "block"; } else { GM_xmlhttpRequest({ method: "GET", url: `https://api.bilibili.com/x/player/videoshot?aid=${aid}&index=1`, onload: function (response) { try { let text = JSON.parse(response.responseText); let data = text.data; picDom.dataset.num = data.index.length >= 99 ? 99 : data.index.length; picDom.style.backgroundImage = `url(${data.image[0]})`; picDom.style.backgroundPosition = "0px 0px"; picDom.style.backgroundSize = "2800px"; picDom.style.display = "block"; } catch { console.error("获取封面出错"); } }, onerror: function () { console.error("获取封面出错"); }, }); } } function setPic(offsetX) { // 根据鼠标位置更改背景位置 if (picDom.dataset.num) { let num = ~~((offsetX / picDom.offsetWidth) * picDom.dataset.num); picDom.style.backgroundPosition = `-${(num % 10) * 280 + 15}px -${~~((num % 100) / 10) * 158}px`; bar.style.width = `${~~((offsetX / picDom.offsetWidth) * 100)}%`; } } } function getCookie(key) { const reg = `(^| )${key}=([^;]*)(;|$)`; console.log(document.cookie); const arr = document.cookie.match(reg); if (!arr) { return null; } return arr[2]; } function scrollRefsh() { // 监听滚动实现自动添加推荐 let timer = setInterval(function () { if (recommendData[0] != undefined) { for (let index = 0; index < 5; index++) { addRecommend(); } clearInterval(timer); } }); var lastAdd = Date.now(); window.onscroll = function () { if (document.querySelector("div.recommend_switch > span").classList.contains("on")) { let scrollPlace = document.body.scrollTop || document.documentElement.scrollTop; let domHight = document.getElementById("dynamic_recommend").clientHeight - window.screen.availHeight; if (recommendData[0] != undefined && scrollPlace >= domHight) { addRecommend(); } if (recommendData.length < 2 && Date.now() - lastAdd >= 1000) { lastAdd = Date.now(); getRecommendData(); } } }; } function addMarkVideo(markVideo, id) { // 添加稍后在看 markVideo.addEventListener("mouseenter", function () { if (markVideo.classList.contains("active")) { markVideo.querySelector(".video_mark_text").innerHTML = "移除"; } else { markVideo.querySelector(".video_mark_text").innerHTML = "稍后在看"; } }); markVideo.addEventListener("click", function (e) { // 点击按钮不跳转 e.preventDefault(); if (markVideo.classList.contains("active")) { markVideo.classList.remove("active"); markVideo.querySelector(".video_mark_text").innerHTML = "已从稍后在看列表中移除"; markVideoApi("del"); } else { markVideo.classList.add("active"); markVideo.querySelector(".video_mark_text").innerHTML = "已加稍后在看"; markVideoApi("add"); } }); function markVideoApi(action) { const req = new XMLHttpRequest(); req.open("POST", `https://api.bilibili.com/x/v2/history/toview/${action}`); req.withCredentials = true; req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); req.onload = function (res) { try { var list = JSON.parse(res.target.response); if (list.code != 0) { console.log(`请求稍后再看错误 code ${list.code}
msg:${list.message}`, { list, target }); return; } } catch (e) { console.log("请求稍后再看发生错误"); } }; req.send(`aid=${id}&csrf=${getCookie("bili_jct")}`); } } function getAccessKey() { // 获取AccessKey fetch( "https://passport.bilibili.com/login/app/third?appkey=27eb53fc9058f8c3" + "&api=https%3A%2F%2Fwww.mcbbs.net%2Ftemplate%2Fmcbbs%2Fimage%2Fspecial_photo_bg.png&sign=04224646d1fea004e79606d3b038c84a", { method: "GET", credentials: "include", } ) .then(async (res) => { try { return await res.json(); } catch { console.warn("请求接口错误"); } }) .then((data) => { if (data.code || !data.data) { throw { msg: data.msg || data.message || data.code, data }; } else if (!data.data.has_login) { throw { msg: "你必须登录B站之后才能使用授权", data }; } else if (!data.data.confirm_uri) { throw { msg: "无法获得授权网址", data }; } else { return data.data.confirm_uri; } }) .then((url) => { GM_xmlhttpRequest({ method: "GET", url: url, headers: { cookie: document.cookie }, onload: function (resp) { accessKey = resp.finalUrl.match(/access_key=([0-9a-z]{32})/)[1]; console.log("获取accessKey成功", accessKey); GM_setValue("accessKey", accessKey); }, onerror: function (e) { console.error("获取失败"); }, }); }); } })();