Greasy Fork

Greasy Fork is available in English.

B站|bilibili 分P视频详情页优化

调整bilibili 分P视频合集列表,使得可以根据窗口大小上下铺满,标题显示得更长;适配了宽屏显示;支持小窗大小设置;以及一些其他的调整

当前为 2024-04-18 提交的版本,查看 最新版本

// ==UserScript==
// @name         B站|bilibili 分P视频详情页优化
// @license      MIT
// @namespace    https://sumver.cn
// @version      1.1.4
// @description  调整bilibili 分P视频合集列表,使得可以根据窗口大小上下铺满,标题显示得更长;适配了宽屏显示;支持小窗大小设置;以及一些其他的调整
// @author       lonelylizard
// @match        https://www.bilibili.com/video/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// ==/UserScript==

// 添加控制菜单
const menu_widescreen_status = GM_registerMenuCommand("宽屏适配开关(试验)", function() {
    let cur_choose = window.confirm("当前宽屏适配状态:\n" + (GM_getValue("widescreen_status") === true ? "已开启" : "已关闭")+"\n\n按【确认】修改状态,按【取消】保持设置不变\n\n设置后请手动刷新一次网页");
    if(cur_choose){
        if(GM_getValue("widescreen_status")){
            GM_setValue("widescreen_status",false)
        }else{
            GM_setValue("widescreen_status",true)
        }
    }
  });

const miniwin_status = GM_registerMenuCommand("小窗尺寸设置", function() {
    let num = window.prompt("小窗缩放倍率,在1.1~3之间是最合理的,\n推荐倍率1.6~2.0尺寸最佳\n如设置后出现问题(如误设置为100,请输入0即可消除错误尺寸")
    // 调整小窗大小
    if(typeof(Number(num)) === 'number'){
        if(num.toString().split('.').pop().length <=2){

            let ori_area = document.querySelector("#bilibili-player-placeholder")
                let o_height = ori_area.offsetHeight
                let o_width = ori_area.offsetWidth
                let sc_height = Math.round((o_height-56)/3 *num)
                let sc_width  = Math.round(o_width/3 *num)

            if(num!=0){

                GM_addStyle(`@media screen and (min-width: 1681px){
                    .bpx-player-container[data-revision="1"][data-screen=mini], .bpx-player-container[data-revision="2"][data-screen=mini]{
                        height:${sc_height}px !important;
                        width:${sc_width}px !important;
                    }
                }`);
                GM_addStyle(`
                    .bpx-player-container[data-revision="1"][data-screen=mini], .bpx-player-container[data-revision="2"][data-screen=mini]{
                        height:${sc_height}px !important;
                        width:${sc_width}px !important;
                    }`); 
                
                // 保存设置
                GM_setValue("mini_height",sc_height)
                GM_setValue("mini_width",sc_width)
            }else{
                // 重置尺寸
                GM_setValue("mini_height",0)
                GM_setValue("mini_width",0)
                // 恢复小窗
                GM_addStyle(`@media screen and (min-width: 1681px){
                    .bpx-player-container[data-revision="1"][data-screen=mini], .bpx-player-container[data-revision="2"][data-screen=mini]{
                        height:${Math.round((o_height-56)/3)}px !important;
                        width:${Math.round((o_width-56)/3)}px !important;
                    }
                }`);
                GM_addStyle(`
                    .bpx-player-container[data-revision="1"][data-screen=mini], .bpx-player-container[data-revision="2"][data-screen=mini]{
                        height:${Math.round((o_height-56)/3)}px !important;
                        width:${Math.round((o_width-56)/3)}px !important;
                    }`); 
            }
            
        }
    }
});

(function() {
    'use strict';

    // 去除右侧广告
    GM_addStyle(`#slide_ad{display:none`);
    GM_addStyle(`.ad-report {display:none !important;min-width:0px !important;min-height:0px !important}`);
    // 去除简介下广告
    GM_addStyle(`#activity_vote{display:none !important}`);
    // 去除右下角直播窗口
    GM_addStyle(`.pop-live-small-mode{display:none !important}`);
    // 去除右侧游戏广告卡片
    GM_addStyle(`.video-page-game-card-small{display:none !important}`);

    // 去除视频下方的广播广告
    GM_addStyle(`.reply-notice{display:none !important}`);


    // 让视频列表内的视频项标题显示得更多
    GM_addStyle(`.base-video-sections-v1 .video-section-list .video-episode-card__info-title[data-v-10d2177a]{width:100% !important}`);


    var targetNode = "";
    // 选择需要观察变动的节点
    if(document.getElementsByClassName('video-sections-content-list')[0]){
        // fn1,fn2,fn3情况共同拥有video-sections-content-list,一起监听
        targetNode = document.getElementsByClassName('video-sections-content-list')[0];
    }else if(document.getElementsByClassName('multi-page-v1')[0]){
        // fn4情况
        targetNode = document.getElementsByClassName('multi-page-v1')[0];
    }

    // 观察器的配置(需要观察什么变动)
    const config = {
        attributes: false, // 开启监听属性
        childList: true, // 开启监听子节点
        subtree: true // 开启监听子节点下面的所有节点
    };

    // 当观察到变动时执行的回调函数
    const callback = function(mutationsList, observer) {
        // Use traditional 'for loops' for IE 11
        for(let mutation of mutationsList) {
            if (mutation.type === 'childList') {
                // console.log('子节点有变化');
                if(document.querySelector(".base-video-sections-v1")){
                    fn1();
                }
                if(document.querySelector(".video-sections-v1")){
                    fn2();
                }
                if(document.querySelector("video-section-title")){
                    fn3();
                }
                if(document.querySelector(".multi-page-v1")){
                    fn4()
                }
                return;
            }
            // else if (mutation.type === 'attributes') {
            //     console.log('The ' + mutation.attributeName + ' 属性有变化');
            // }
        }
    };

    // 创建一个观察器实例并传入回调函数
    const observer = new MutationObserver(callback);

    // 以上述配置开始观察目标节点
    try{
        observer.observe(targetNode, config);
    }
    catch(err) {
        // console.log("节点不存在");
    }


    // 之后,可停止观察
    // observer.disconnect();


    // 针对不带封面的视频合集列表
    let fn1 = function(){
        if(document.querySelector(".base-video-sections-v1")){
            if(document.querySelector(".video-episode-card")){

                change_right_width("fn1")

                // 带分类视频和仅标题视频合集有相同的外层div,从这里区分开两种类型
                if(document.querySelector(".video-section-title")){
                    fn3()
                }else{
                    let list_height = document.querySelector(".video-section-list").scrollHeight;
                    let res_height = window.innerHeight;
                    let right_content_top_heigt = document.querySelector(".base-video-sections-v1").offsetTop;
                    let dif_height = res_height - right_content_top_heigt - 150;

                    // 计算列表高度,如果达不到一屏就不铺满
                    if(list_height > dif_height){
                        GM_addStyle(`.video-sections-content-list{height: ${dif_height}px !important;max-height:1000px !important}`);
                    }else{
                        let temp_height = list_height + 10
                        GM_addStyle(`.video-sections-content-list{height: ${temp_height}px !important;max-height:1000px !important}`);
                    }

                    // 添加滑动鼠标一个浅的聚焦颜色
                    GM_addStyle(`.video-episode-card__info:hover{background:#DCE2E3}`);
                    // 去除字体蓝色提醒
                    GM_addStyle(`.video-episode-card__info-title:hover{color:#000 !important}`);
                    GM_addStyle(`.video-episode-card__info:hover .video-episode-card__info-title{color:#000 !important}`);
                }

            }
        }
    };

    // 针对带封面的视频合集列表
    let fn2 = function(){
        if(document.querySelector(".video-sections-v1")){
            if(document.querySelector(".video-episode-card")){

                change_right_width("fn2");

                let list_height = document.querySelector(".video-section-list").scrollHeight;

                let res_height = window.innerHeight;
                var right_content_top_heigt = document.querySelector(".video-sections-v1").offsetTop;
                var dif_height = res_height - right_content_top_heigt -160;

                // 计算列表高度,如果达不到一屏就不铺满

                if(list_height > dif_height){
                    GM_addStyle(`.video-sections-content-list{height: ${dif_height}px !important;max-height:1000px !important}`);
                }else{
                    let temp_height = list_height + 10
                    GM_addStyle(`.video-sections-content-list{height: ${temp_height}px !important;max-height:1000px !important}`);
                }
                // 添加滑动鼠标一个浅的聚焦颜色
                GM_addStyle(`.video-episode-card:hover{background:#DCE2E3}`);
                // 去除字体蓝色提醒
                GM_addStyle(`.video-episode-card__info:hover .video-episode-card__info-title{color:#000 !important}`);
                GM_addStyle(`.video-episode-card:hover .video-episode-card__info-title{color:#000 !important}`);

            }
        }
    };

    // 针对带分类的视频合集列表
    let fn3 = function(){
        if(document.querySelector(".base-video-sections-v1")){
            if(document.querySelector(".video-section-title")){

                change_right_width("fn3");

                let list_height = window.innerHeight;
                let right_content_top_heigt = document.querySelector(".base-video-sections-v1").offsetTop;
                let dif_height = list_height - right_content_top_heigt - 150;

                // 默认一屏
                GM_addStyle(`.video-sections-content-list{height: ${dif_height}px !important;max-height:1000px !important}`);

                // 分类颜色和视频标题一样,略做修改增加辨识度
                GM_addStyle(`.video-section-title{background-color: #D1D8DA !important}`);
                // 去除分类区域奇怪的圆角
                GM_addStyle(`.video-sections-content-list{border-radius: 0px !important}`);
                // 重设分割线
                GM_addStyle(`.border-bottom-line{background:#F1F2F3 !important}`);
                // 添加滑动鼠标一个浅的聚焦颜色
                GM_addStyle(`.video-episode-card__info:hover{background:#DCE2E3}`);
                // 去除字体蓝色提醒
                GM_addStyle(`.video-episode-card__info-title:hover{color:#000 !important}`);
                GM_addStyle(`.video-episode-card:hover .video-episode-card__info-title{color:#000 !important}`);
            }
        }
    };

    // 针对带选集(分P)的视频合集列表
    let fn4 = function(){
        if(document.querySelector(".multi-page-v1")){
            if(document.querySelector(".cur-list")){

                change_right_width("fn4");

                let res_height = window.innerHeight;
                let list_height =  document.querySelector(".list-box").scrollHeight;

                let right_content_top_heigt = document.querySelector(".multi-page-v1").offsetTop;
                let dif_height = res_height - right_content_top_heigt - 120;

                // 计算列表高度,如果达不到一屏就不铺满
                if(list_height > dif_height){
                    GM_addStyle(`.cur-list {height: ${dif_height}px !important;max-height:1000px !important}`);
                }else{
                    GM_addStyle(`.cur-list {height: ${list_height}px !important;max-height:1000px !important}`);
                }
                // 添加滑动鼠标一个浅的聚焦颜色
                GM_addStyle(`.list-box>li:hover{background:#DCE2E3 !important}`);
        }   }
    };

    // 宽屏适配
    let change_right_width = function(source){

        if(GM_getValue("widescreen_status")){
            let body_width = document.querySelector("#app").offsetWidth;
            let res_width = window.innerWidth;

            if(res_width-100 > body_width){
                //带鱼屏
                let left_div = document.querySelector(".left-container").offsetWidth;
                let right_div = document.querySelector(".right-container").offsetWidth;
                var dif_width = (body_width - (left_div+right_div))+right_div-100;
                // GM_addStyle(`.right-container {width: ${dif_width}px !important}`);
            }else{
                //非带鱼屏
                let left_div = document.querySelector(".left-container").offsetWidth;
                let right_div = document.querySelector(".right-container").offsetWidth;
                var dif_width = (res_width - (left_div+right_div))+right_div-80;
                // GM_addStyle(`.right-container {width: ${dif_width}px !important}`);
        }
        //不同的合集页需要单独适配
        if(source == "fn1"){
            // 调整合集名称长度
            GM_addStyle(`.first-line-left>a {max-width: ${dif_width-200}px !important}`);
            // 调整合集宽度
            GM_addStyle(`.right-container {width: ${dif_width}px !important}`);
            // 调整标题宽度
            GM_addStyle(`.video-episode-card__info-title {width: 100% !important}`);
        }
        if(source == "fn2"){
            // 调整合集名称长度
            GM_addStyle(`.first-line-left>a {max-width: ${dif_width-200}px !important}`);
            // 调整合集宽度
            GM_addStyle(`.right-container {width: ${dif_width}px !important}`);

            //调整合集内视频标题的宽度
            GM_addStyle(`.video-sections-item {width: 95% !important}`);
        }
        if(source == "fn3"){
            // 调整合集名称长度
            GM_addStyle(`.first-line-left>a {max-width: ${dif_width-200}px !important}`);
            // 调整合集宽度
            GM_addStyle(`.right-container {width: ${dif_width}px !important}`);
        }
        if(source == "fn4"){
            //分P视频无需调整标题宽度,因为选集名称固定为“视频选集”
            // 调整合集宽度
            GM_addStyle(`.right-container {width: ${dif_width}px !important}`);
            // 合集内需要单独调整
            GM_addStyle(`#multi_page .cur-list .list-box>li {width: ${dif_width}px}`);
            // 分P视频合集的分P时长偏右,微调
            GM_addStyle(`.cur-list>ul>li>a{margin-right: 15px !important}`);
            
        }
        }
    }

    // 窗口大小变化时调整合集列表大小
    const getWindowInfo = () => {
        fn1();
        fn2();
        fn3();
        fn4();
    };
    const debounce = (fn, delay) => {
        let timer;
        return function() {
            if (timer) {
                clearTimeout(timer);
            }
            timer = setTimeout(() => {
                fn();
            }, delay);
        }
    };
    const cancalDebounce = debounce(getWindowInfo, 500);
    window.addEventListener('resize', cancalDebounce);

    fn1();
    fn2();
    fn3();
    fn4();

    if(GM_getValue("mini_height") != 0 ){
        GM_addStyle(`@media screen and (min-width: 1681px){
            .bpx-player-container[data-revision="1"][data-screen=mini], .bpx-player-container[data-revision="2"][data-screen=mini]{
                height:${GM_getValue("mini_height")}px !important;
                width:${GM_getValue("mini_width")}px !important;
            }
        }`);
        GM_addStyle(`
            .bpx-player-container[data-revision="1"][data-screen=mini], .bpx-player-container[data-revision="2"][data-screen=mini]{
                height:${GM_getValue("mini_height")}px !important;
                width:${GM_getValue("mini_width")}px !important;
            }`); 
    }


    window.addEventListener('pushState', function(e) {
        fn1();
        fn2();
        fn3();
        fn4();
      });

    window.addEventListener('replaceState', function(e) {
        fn1();
        fn2();
        fn3();
        fn4();
      });

    // B站视频详情页的自动播放下一个视频,或者点击其他视频,使用的是pushState不会刷新页面,这里需要重写pushState、replaceState为来实现监听页面视频是否切换
    const bindEventListener = function(type) {
        const historyEvent = history[type];
        return function() {
            const newEvent = historyEvent.apply(this, arguments);
           const e = new Event(type);
            e.arguments = arguments;
            window.dispatchEvent(e);
            return newEvent;
        };
     };
     history.pushState = bindEventListener('pushState');
     history.replaceState = bindEventListener('replaceState');

     // 浏览器前进、后退时,重新计算高度
     window.onpopstate = function(event) {
        fn1();
        fn2();
        fn3();
        fn4();
    };

})();