b站评论区简化(保存网页用)

删除b站视频及动态中的多余元素,并展开评论区二级回复,以及调整页面样式,为通过SingleFile等工具导出网页备份评论区做准备。必须搭配油猴脚本“Bilibili - 在未登录(不可用)的情况下照常加载评论”使用。

目前为 2025-01-13 提交的版本。查看 最新版本

// ==UserScript==
// @name         b站评论区简化(保存网页用)
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  删除b站视频及动态中的多余元素,并展开评论区二级回复,以及调整页面样式,为通过SingleFile等工具导出网页备份评论区做准备。必须搭配油猴脚本“Bilibili - 在未登录(不可用)的情况下照常加载评论”使用。
// @license      GPL-3.0
// @author       Kooluve
// @match        https://www.bilibili.com/video/*
// @match        https://www.bilibili.com/opus/*
// @match        https://t.bilibili.com/*
// @exclude      https://t.bilibili.com/?tab=*
// @icon         https://www.bilibili.com/favicon.ico
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    let currentUrl = window.location.href; // 网页链接
    let isVideo, isOpus, isT;
    if (currentUrl.includes('bilibili.com/video')) { isVideo = true} // 视频
    else if (currentUrl.includes('bilibili.com/opus')) { isOpus = true} // 图文
    else if (/^https:\/\/t\.bilibili\.com\/\d+$/.test(currentUrl)) { isT = true} // 转发

    let singleFileName = ''; // singlefile文件名

    let isScriptExecuting = false; // 脚本是否正在执行

    let overlay; // 页面变暗的覆盖层
    let messageBar; // 脚本执行提示条

    let isDataLoaded = false; // 判断页面是否加载完毕,以便在一次网页刷新中重复启动脚本时顺利进行

    let elementsToRemove; // 待删除元素(部分)

    const webOpenTime = getWebOpenTime(); // 打开网页的时刻

    const scrollInterval = 500; // 检查跳转到页面底部的间隔。时间单位都为毫秒
    const scrollMaxIdleTime = 10000; // 页面底部无变化最多的停滞时间
    const anchorForLoadingText = '所有评论已加载完毕'; // 加载完毕的文字
    let isCommentLoading = true; // 评论区初始状态为正在加载
    let lastScrollHeight = 0; // 记录上一次页面的高度

    const clickIntervalMin = 100; // 展开二级回复的最小间隔
    const clickIntervalMax = 200; // 展开二级回复的最大间隔

    console.log('页面打开时刻: ', webOpenTime); // 输出打开网页的时刻

    adjustBeforeSingleFile(); // 在singlefile保存网页前调整网页

    // 输出打开网页的时刻,方便不使用该脚本后续功能,只是单纯截图时,知晓这个图片的保存时间。也便于调试脚本
    function getWebOpenTime() {
        const visitYearLocale = new Date().getFullYear();
        const visitMonthLocale = String(new Date().getMonth() + 1).padStart(2, '0');
        const visitDayLocale = String(new Date().getDate()).padStart(2, '0');
        const visitTimeLocale = new Date().toLocaleTimeString();
        const formattedTime = `(${visitYearLocale}-${visitMonthLocale}-${visitDayLocale} ${visitTimeLocale})`
        return formattedTime;
    }

    // 使用方式1:在singlefile保存网页前自动调整网页
    async function adjustBeforeSingleFile() {
        dispatchEvent(new CustomEvent("single-file-user-script-init"));

        addEventListener("single-file-on-before-capture-request", async event => {
            event.preventDefault();
            try {
                await waitForVisibility(); // 等待标签页变为可见
                await start(); // 开始脚本功能
                console.log('start 函数执行完毕');
            } catch (error) {
                console.log('start 函数有错误');
            } finally {
                dispatchEvent(new CustomEvent("single-file-on-before-capture-response"));
            }
        });
    }

    // 等待标签页变为可见
    async function waitForVisibility() {
        // 如果标签页已经是可见的,直接执行
        if (document.visibilityState === 'visible') {
            console.log('标签页当前可见,直接执行函数');
            return;
        }

        // 如果标签页不是可见的,则等待可见性变化
        return new Promise((resolve) => {
            function onVisibilityChange() {
                if (document.visibilityState === 'visible') {
                    // 标签页切换到前台,执行函数
                    console.log('标签页变为可见,开始执行函数');
                    resolve(); // 解除等待
                    document.removeEventListener('visibilitychange', onVisibilityChange); // 移除事件监听
                }
            }

            // 监听 visibilitychange 事件
            document.addEventListener('visibilitychange', onVisibilityChange);
        });
    }

    // 使用方式2:快捷键启动脚本调整网页
    window.addEventListener('keydown', function(event) {
        // Ctrl + Shift + Alt + Z 展开评论区,可根据需要修改
        if (!isScriptExecuting && event.ctrlKey && event.shiftKey && event.altKey && event.key === 'Z') {
            start();
        }
    });

    async function start() {
        console.log('脚本开始执行');

        // 初始化变量
        isCommentLoading = true;
        isScriptExecuting = true;

        // 创建变暗的覆盖层
        createDarkOverlay();
        // 显示提示条
        showStickyMessage('脚本执行中...');
        // 等待页面初步加载完毕
        await waitLoading();
        // 设置singlefile保存文件名
        setSingleFileName();
        // 预先删除页面中绝大部分没用的元素
        await preRemove();
        // 删除剩余元素
        otherRemove();

        // 点击最新按钮
        await new Promise(resolve => {
            setTimeout(function() {
                clickLastedButton();
                resolve();
            }, 500); // 延迟0.5秒
        });

        // 开始自动跳转到底部
        try {
            await startAutoScrollToBottom();
        } catch (error) {
            messageBar.innerText = '滚动加载评论区失败,请刷新网页重试。滚动加载期间不要移开标签页';
            // 在文件名中添加错误提示
            singleFileName = singleFileName.replace(/\/([^\/]*)$/, '/【错误:滚动加载评论区失败】$1');
            console.error('错误:', '滚动加载评论区失败');
            throw new Error(error.message);
            return;
        }

        // 展开二级回复
        try {
            await clickViewMoreBtns();
        } catch (error) {
            messageBar.innerText = '展开二级回复失败,请刷新网页重试。仍未解决请等一段时间再试';
            // 在文件名中添加错误提示
            singleFileName = singleFileName.replace(/\/([^\/]*)$/, '/【错误:展开二级回复失败】 $1');
            console.error('错误:', '展开二级回复失败');
            throw new Error(error.message);
            return;
        }

        // 修改动态相册样式
        modifyStyleAlbum();
        // 修改样式
        modifyStyle();
        // 创建用于保存文件名的元素
        addFilenameForSinglefile();
        // 脚本结束
        end();
    }

    // 创建一个模拟页面变暗的透明覆盖层
    function createDarkOverlay() {
        overlay = document.createElement('div');
        overlay.id = 'darkOverlay';
        overlay.style.position = 'fixed';
        overlay.style.top = '0';
        overlay.style.left = '0';
        overlay.style.width = '100%';
        overlay.style.height = '100%';
        overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; // 半透明的黑色
        overlay.style.zIndex = '9998'; // 确保它在页面内容下方但低于提示条
        overlay.style.pointerEvents = 'none'; // 不干扰页面操作
        document.body.appendChild(overlay);
    }

    // 创建并显示提示条
    function showStickyMessage(message) {
        messageBar = document.createElement('div');
        messageBar.id = 'stickyMessage';
        messageBar.style.position = 'fixed';
        messageBar.style.top = '0';
        messageBar.style.left = '0';
        messageBar.style.width = '100%';
        messageBar.style.padding = '10px';
        messageBar.style.backgroundColor = '#ff9800'; // 使用鲜亮的背景色
        messageBar.style.color = '#fff'; // 白色文本
        messageBar.style.textAlign = 'center';
        messageBar.style.zIndex = '9999'; // 确保提示条在最上面
        messageBar.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.3)'; // 提示条阴影
        messageBar.style.fontSize = '20px'; // 设置字体大小
        messageBar.innerText = message;
        document.body.appendChild(messageBar);
    }

    //删除覆盖和提示
    function removeOverlayAndMessage() {
        if (messageBar) {
            messageBar.remove();
        }
        if (overlay) {
            overlay.remove();
        }
    }

    // 等待页面初步加载完毕
    async function waitLoading() {
        const checkAndRunScript = async () => {
            const dataLoaded = document.querySelector('iframe[src="https://s1.hdslb.com/bfs/seed/jinkela/short/cols/iframe.html"][data-loaded="true"]');
            if (dataLoaded) {
                isDataLoaded = true;
                console.log('网页加载完毕');
                return 'case1';
            } else if (isDataLoaded) { // 脚本已执行过,直接跳到滚动底部功能
                console.log('网页已加载过');
                return 'case2';
            } else {
                await new Promise(resolve => setTimeout(resolve, 500)); // 每0.5秒检查一次
                return checkAndRunScript();
            }
        };

        return await checkAndRunScript(); // 初始调用
    }

    // 获取为singlefile准备的保存文件名
    function setSingleFileName() {
        let resultName = '';

        if (isVideo) {
            let author = '';
            const upName = document.querySelector('a.up-name')?.textContent;
            let staffNameAll = '';
            const staffNameList = document.querySelectorAll('a.staff-name');
            for (const staff of staffNameList) {
                staffNameAll += staff.textContent + ' ' ; // 最后一次循环多加了一个空格
            }
            let time = document.querySelector('.pubdate-ip-text')?.textContent || '';
            let title = document.querySelector('.video-title')?.textContent || '';

            author = upName?.slice(6, upName.length - 7) || staffNameAll?.slice(0, -1);
            title = title.replace(/\//g, ' ');

            resultName += author + '/视频 ' + time + ' ' + title + ' ' ;
        } else if (isOpus) {
            let author = document.querySelector('.opus-module-author__name')?.textContent || '';
            let time = document.querySelector('.opus-module-author__pub__text')?.textContent || '';
            let title = document.querySelector('.opus-module-title__text')?.textContent || '';
            let content = document.querySelector('.opus-module-content')?.textContent || '';

            time = (time.includes('编辑于') ? time.substring(4) + ' (已编辑)' : time);
            time = time.replace(/(\d{4})年(\d{2})月(\d{2})日 (\d{2}:\d{2})/, "$1-$2-$3 $4:XX");
            title = title.replace(/\//g, ' ');
            content = content.replace(/\//g, ' ');
            title = title ? title : (content ? (content.substring(0, 15) + '…') : '(无字)');

            resultName += author + '/动态 ' + time + ' ' + title + ' (图文) ';
        } else if (isT) {
            let author = document.querySelector('span.bili-dyn-title__text')?.textContent || '';
            let time = document.querySelector('.bili-dyn-time')?.textContent || '';
            let content = document.querySelector('.bili-rich-text__content')?.textContent || '';

            author = author.slice(4, author.length - 3);
            time = time.substring(3, 20);
            time = time.replace(/(\d{4})年(\d{2})月(\d{2})日 (\d{2}:\d{2})/, "$1-$2-$3 $4:XX");
            content = content.replace(/\//g, ' ');
            content = content.length > 0 ? content.substring(0, 15) + '…' : '(无字)';

            resultName += author + '/动态 ' + time + ' ' + content + ' (转发) ';
        }

        // 以页面打开时刻作为保存时间
        resultName += webOpenTime;

        console.log('文件名设置完毕');
    }

    // 预先删除页面中绝大部分没用的元素
    async function preRemove() {
        // 获取head元素
        const head = document.head || document.getElementsByTagName('head')[0];
        const headElements = Array.from(head.children);
        var keepHeadElements;

        // 公用的保留的head元素条件
        const commonHeadElements = [
            { tag: 'STYLE', innerHTMLInclude: '.reply-item .root-reply-avatar .avatar .bili-avatar' },
            { tag: 'STYLE', innerHTMLInclude: '.fan-medal' },
            { tag: 'STYLE', innerHTMLInclude: '.sub-reply-container .view-more-btn:hover' },
            { tag: 'STYLE', innerHTMLInclude: '.jump-link' },
            { tag: 'STYLE', innerHTMLInclude: ':root' },
            { tag: 'TITLE' },
        ];

        // 保留的head元素条件
        if (isVideo) {
            keepHeadElements = [
                ...commonHeadElements,
                { tag: 'Link', href: '//s1.hdslb.com/bfs/seed/jinkela/short/bili-theme/map.css' },
                { tag: 'Link', href: '//s1.hdslb.com/bfs/seed/jinkela/short/bili-theme/light.css' },
                { tag: 'Link', href: '//s1.hdslb.com/bfs/static/jinkela/video/css/video' }, // 如'//s1.hdslb.com/bfs/static/jinkela/video/css/video.0.2ce49da9698008db82fd161474a3e2cc4dcc2c2a.css'
                { tag: 'STYLE', id: 'setSizeStyle' },
            ];
        } else if (isOpus) {
            keepHeadElements = [
                ...commonHeadElements,
                { tag: 'Link', href: '//s1.hdslb.com/bfs/seed/jinkela/short/bili-theme/map.css' },
                { tag: 'Link', href: '//s1.hdslb.com/bfs/seed/jinkela/short/bili-theme/light_u.css' },
                { tag: 'Link', href: '//s1.hdslb.com/bfs/seed/jinkela/short/bili-theme/light.css' },
                { tag: 'Link', href: '//s1.hdslb.com/bfs/static/stone-free/opus-detail/css/opus-detail.1.43b5e197533b9afa5213455ea78553d2ad191767.css' },
                { tag: 'Link', href: '//s1.hdslb.com/bfs/static/stone-free/opus-detail/css/opus-detail.0.43b5e197533b9afa5213455ea78553d2ad191767.css' },
                { tag: 'STYLE', type: 'text/css' },
                { tag: 'STYLE', id: 'bmgstyle-b-img__inner' },
            ];
        } else if (isT) {
            keepHeadElements = [
                ...commonHeadElements,
                { tag: 'STYLE', type: 'text/css' },
                { tag: 'STYLE', id: 'bmgstyle-b-img__inner' },
            ];
        }

        // 处理head中的元素
        headElements.forEach(element => {
            // 保留指定的head元素
            const shouldKeep = keepHeadElements.some(item => {
                const tagMatch = element.tagName === item.tag.toUpperCase();
                const hrefMatch = item.href ? element.href && element.href.includes(item.href) : true;
                const typeMatch = item.type ? element.type === item.type : true;
                const idMatch = item.id ? element.id === item.id : true;
                const innerHTMLIncludeMatch = item.innerHTMLInclude ? element.innerHTML.includes(item.innerHTMLInclude) : true;
                return tagMatch && hrefMatch && typeMatch && idMatch && innerHTMLIncludeMatch;
            });

            if (!shouldKeep) {
                element.remove();
            }
        });

        // 获取body元素
        const body = document.body;
        const bodyElements = Array.from(body.children);
        var keepBodyElements;

        // 公用的保留的body元素条件
        const commonBodyElements = [
            //脚本增加的覆盖和提示
            { tag: 'DIV', id: 'darkOverlay' },
            { tag: 'DIV', id: 'stickyMessage' },
        ];

        // 保留的body元素条件
        if (isVideo || isOpus) {
            keepBodyElements = [
                ...commonBodyElements,
                { tag: 'DIV', id: 'app' },
            ];
        }
        else if (isT) {
            keepBodyElements = [
                ...commonBodyElements,
                { tag: 'Link', href: '//s1.hdslb.com/bfs/static/stone-free/dyn-detail/css/dyn-detail.1.43b5e197533b9afa5213455ea78553d2ad191767.css' },
                { tag: 'Link', href: '//s1.hdslb.com/bfs/static/stone-free/dyn-detail/css/dyn-detail.0.43b5e197533b9afa5213455ea78553d2ad191767.css' },
                { tag: 'DIV', id: 'app' },
            ];
        }

        // 处理body中的元素
        bodyElements.forEach(element => {
            // 保留指定的body元素
            const shouldKeep = keepBodyElements.some(item => {
                const tagMatch = element.tagName === item.tag.toUpperCase();
                const hrefMatch = item.href ? element.href && element.href.includes(item.href) : true;
                const idMatch = item.id ? element.id === item.id : true;
                return tagMatch && hrefMatch && idMatch;
            });
            if (!shouldKeep) {
                element.remove();
            }
        });

        // 删除edge浏览器中的多余元素。其他浏览器待测试
        // 获取html元素并遍历其直接子元素
        const html = document.documentElement; // 获取 <html> 元素
        const siblingElements = Array.from(html.children); // 获取 html 下的所有直接子元素(包括 <head> 和 <body>)

        // 定义需要移除的同级元素条件
        const removeSiblingElements = [
            { tag: 'DIV', style: 'all: initial;' },
            { tag: 'DIV', id: 'immersive-translate-popup' }
        ];

        // 处理同级元素
        siblingElements.forEach(element => {
            const shouldRemove = removeSiblingElements.some(item => {
                // 检查元素的style是否包含all: initial
                const style = element.getAttribute('STYLE') || '';
                const isStyleMatching = style.includes('all: initial');
                const isIdMatching = !item.id || element.id === item.id;

                // 如果匹配到条件,移除元素
                return element.tagName === item.tag.toUpperCase() && isStyleMatching && isIdMatching;
            });

            if (shouldRemove) {
                element.remove();
            }
        });
        console.log('预先删除完毕');
    }

    // 删除剩余元素
    function otherRemove() {
        if (isVideo) {
            elementsToRemove = [
                '#biliMainHeader',
                '#playerWrap',
                '.right-container',
                '.toggle-btn',
                '.fixed-sidenav-storage',
                '.activity-m-v1',
                '.video-toolbar-right',
                '.ad-report',
            ];
        }
        else if (isOpus) {
            elementsToRemove = [
                '.right-sidebar-wrap',
                '.fixed-author-header',
                '.opus-module-bottom',
            ];
        }
        else if (isT) {
            elementsToRemove = [
                '.sidebar-wrap',
            ];
        }

        const mainReplyBox = document.querySelector('.main-reply-box');
        if (mainReplyBox) {
            // 移除
            mainReplyBox.remove();
        }

        // 删除元素
        elementsToRemove.forEach(function(selector) {
            var element = document.querySelector(selector);
            if (element) {
                element.remove();
            }
        });
        console.log('删除剩余元素完毕');
    }

    // 点击最新按钮
    function clickLastedButton() {
        const lastedButton = document.querySelector('.time-sort');
        if (lastedButton) {
            lastedButton.click();
            console.log('已点击最新按钮');
        }
    }

    // 开始自动跳转到底部
    async function startAutoScrollToBottom() {
        document.documentElement.style.scrollBehavior = 'auto'; // 禁用平滑滚动

        let lastScrollHeight = document.body.scrollHeight;
        let lastUpdateTime = Date.now(); // 记录上次页面变化时间

        while (isCommentLoading) {
            // 判断页面是否加载完成
            const isPageLoaded = monitorPageLoad(lastScrollHeight, lastUpdateTime);

            if (isPageLoaded === 'case1') { // 页面加载完毕,退出循环
                isCommentLoading = false;
                break;
            } else if (isPageLoaded === 'case2') { // 页面加载失败,退出函数
                isCommentLoading = false;
                throw new Error('滚动加载评论区失败'); // 抛出错误
                return;
            } else if (isPageLoaded === 'case3') { // 页面正在加载

            }

            scrollToBottom(); // 跳转到底部
            await new Promise(resolve => setTimeout(resolve, scrollInterval)); // 等待一定时间后再继续检查

            // 如果页面高度发生变化,更新上次变化的时间
            if (document.body.scrollHeight !== lastScrollHeight) {
                lastScrollHeight = document.body.scrollHeight;
                lastUpdateTime = Date.now(); // 更新最后的变化时间
            }
        }

        document.documentElement.style.scrollBehavior = 'smooth'; // 恢复平滑滚动
        console.log('评论区加载完毕');
    }

    // 跳转到页面底部
    function scrollToBottom() {
        window.scrollTo(0, document.body.scrollHeight);
    }

    // 判断是否加载完毕
    function monitorPageLoad(lastScrollHeight, lastUpdateTime) {
        const currentScrollHeight = document.body.scrollHeight;
        const anchorForLoading = document.querySelector('.anchor-for-loading');

        if (anchorForLoading) { // 加载文字存在
            // 加载文字完成
            if (anchorForLoading.textContent.trim() === anchorForLoadingText) {
                return 'case1'; // 加载完成
            }
            // 加载文字未完成,页面高度相同
            else if(currentScrollHeight === lastScrollHeight) {
                // 如果页面高度长时间没有变化,认为加载失败
                if (Date.now() - lastUpdateTime > scrollMaxIdleTime) {
                    console.log('页面加载停滞,认为加载失败');
                    return 'case2'; // 加载失败
                }
            }
        } else if(currentScrollHeight === lastScrollHeight) { // 加载文字不存在
            // 如果页面高度长时间没有变化,认为加载完成
            if (Date.now() - lastUpdateTime > scrollMaxIdleTime) {
                console.log('页面加载停滞,认为加载完成');
                return 'case1'; // 加载完成
            }
            return 'case3'; // 页面仍在加载
        }

        lastScrollHeight = currentScrollHeight; // 更新页面高度
        return 'case3'; // 页面仍在加载
    }

    // 展开二级回复
    async function clickViewMoreBtns() {
        // 获取按钮
        const viewMoreBtnList = document.querySelectorAll('.view-more-btn');
        for (const viewMoreBtn of viewMoreBtnList) {
            if (viewMoreBtn) {
                // 生成随机延迟时间
                const delay = Math.floor(Math.random() * (clickIntervalMax - clickIntervalMin + 1)) + clickIntervalMin;
                viewMoreBtn.click();
                await new Promise(resolve => setTimeout(resolve, delay));
            }
        }

        // 延迟后再次检查按钮
        await new Promise(resolve => setTimeout(() => {
            // 再次获取按钮
            const viewMoreBtnListRemain = document.querySelectorAll('.view-more-btn');
            if (viewMoreBtnListRemain.length > 0) {
                throw new Error('展开二级回复失败'); // 抛出错误
            }
            resolve();
        }, 500));

        console.log('展开二级回复完毕');
    }

    // 修改动态相册样式
    function modifyStyleAlbum() {
        // 检查是否存在 .horizontal-scroll-album__indicator
        const indicator = document.querySelector('.horizontal-scroll-album__indicator');
        if (!indicator) {
            return; // 如果没有找到,退出函数
        }

        // 获取所有缩略图
        const thumbnails = document.querySelectorAll('.horizontal-scroll-album__indicator__thumbnail');

        // 依次点击所有缩略图
        thumbnails.forEach((thumbnail, index) => {
            setTimeout(() => {
                // 点击缩略图
                thumbnail.click();
            }, index * 200); // 延迟200ms,避免过快点击
        });

        // 等待图片加载完成后,注入样式并等比缩放
        setTimeout(() => {
            const albumScreen = document.querySelector('.horizontal-scroll-album__screen');
            const images = document.querySelectorAll('.horizontal-scroll-album__pic');
            const imageElems = document.querySelectorAll('.horizontal-scroll-album__pic__img');
            const albumContent = document.querySelector('.horizontal-scroll-album__content');

            // 获取 horizontal-scroll-album__screen 容器的宽度
            const screenWidth = albumScreen ? albumScreen.offsetWidth : 0;
            if (screenWidth === 0) return; // 如果容器宽度为0,则退出

            const gap = 5; // 图片间隔
            // 计算去除间隔后的每张图片的宽度
            const imageWidth = (screenWidth - (images.length - 1) * gap) / images.length;

            // 使用 GM_addStyle 动态注入样式
            GM_addStyle(`
                .horizontal-scroll-album__screen {
                    transform: none !important;  /* 取消水平滚动 */
                    display: flex !important;    /* 使用 flex 布局排列图片 */
                    flex-wrap: nowrap !important; /* 禁用换行 */
                    overflow: hidden !important;  /* 隐藏溢出的部分 */
                }

                .horizontal-scroll-album__pic {
                    display: flex !important; /* 使用 flex 布局 */
                    justify-content: center !important;  /* 水平居中 */
                    align-items: center !important;  /* 垂直居中 */
                    margin-bottom: 0 !important; /* 清除图片间距 */
                    width: ${imageWidth}px !important; /* 设置每张图片的宽度 */
                    height: auto !important; /* 高度自动调整,保持比例 */
                    margin-right: ${gap}px !important; /* 设置图片之间的间隔 */
                }

                /* 修改 .horizontal-scroll-album__pic__img 的样式 */
                .horizontal-scroll-album__pic__img {
                    display: block !important; /* 确保图片显示为块级元素 */
                    width: 100% !important;  /* 确保图片宽度适应容器 */
                    height: auto !important; /* 高度自动调整,保持比例 */
                    object-fit: contain !important; /* 保持等比缩放 */
                }
            `);

            // 直接调整每张实际图片的尺寸
            imageElems.forEach(img => {
                // 选择实际的图片元素,并调整它们的尺寸
                const actualImage = img.querySelector('img');
                if (actualImage) {
                    // 清除图片的 width 和 height 属性,防止原始属性覆盖
                    actualImage.removeAttribute('width');
                    actualImage.removeAttribute('height');

                    // 强制设置图片的宽度和高度
                    actualImage.style.width = '100%'; // 强制设置图片宽度适应父容器
                    actualImage.style.height = 'auto'; // 高度按比例调整
                    actualImage.style.objectFit = 'contain'; // 保持等比缩放
                }
            });

            // 获取所有 .horizontal-scroll-album__pic__img 元素的实际高度
            let maxHeight = 0;
            imageElems.forEach((imgElem) => {
                const img = imgElem.querySelector('img');
                if (img) {
                    // 获取实际的高度
                    const actualHeight = img.offsetHeight;
                    if (actualHeight > maxHeight) {
                        maxHeight = actualHeight;
                    }
                }
            });

            // 如果找到了最大高度,设置 .horizontal-scroll-album__content 的高度
            if (maxHeight > 0 && albumContent) {
                albumContent.style.height = `${maxHeight}px`;
            }

            // 移除导航按钮
            const albumNav= document.querySelector('.horizontal-scroll-album__nav');
            if (albumNav) {
                albumNav.remove();
            }

            // 移除模糊背景
            const blurBgElements = document.querySelectorAll('.horizontal-scroll-album__pic__blurbg');
            blurBgElements.forEach((bg) => {
                bg.remove();
            });

            // 移除缩略图
            if (indicator) {
                indicator.remove();
            }
            console.log('修改相册样式完毕');
        }, thumbnails.length * 500 + 500); // 等待所有图片加载完成
    }

    // 修改样式
    function modifyStyle() {
        if (isVideo) {
            // 长标题换行
            const videoTitle = document.querySelector('.video-title');
            if (videoTitle) {
                videoTitle.style.whiteSpace = 'normal';
                videoTitle.style.flexShrink = 'initial';
                videoTitle.style.marginRight = '0px';
            }

            // 标题容器的高度根据内容自动调整
            const viewbox = document.querySelector('#viewbox_report');
            if (viewbox) {
                viewbox.style.height = 'auto'; // 设置父容器高度自适应
                viewbox.style.overflow = 'visible'; // 取消溢出隐藏,确保内容能完全显示
            }

            // 删除展开箭头
            const videoInfoTitleInner = document.querySelector('.video-info-title');
            if (videoInfoTitleInner) {
                // 获取该元素的所有1级子元素
                const childElements = videoInfoTitleInner.children;

                // 遍历所有子元素,删除注释节点
                Array.from(childElements).forEach(child => {
                    if (child.nodeType === Node.COMMENT_NODE || child.classList.contains('show-more') || child.classList.contains('overflow-panel')) {
                        child.remove(); // 删除注释节点
                    }
                });
            }

            GM_addStyle(`
				.video-container-v1 {
					min-width: 0px !important;
				}

                .left-container {
                    min-width: 0px !important;
                    max-width: 708px !important;
				}

				.basic-desc-info {
					height: auto !important;
				}

				.tag.not-btn-tag {
					display: block !important;
				}
            `);
        }
        else if (isOpus || isT) {
            if (isOpus) {
                GM_addStyle(`
                    .opus-module-title {
						padding: 10px 20px 0 20px !important;
					}

                    .opus-module-author {
						padding: 10px 20px !important;
					}

					.opus-module-content {
						padding: 0 20px !important;
					}
				`);
            }
            else if (isT) {
                GM_addStyle(`
					.bili-dyn-item{
						min-width: 0px !important;
					}
				`);
            }
            GM_addStyle(`
				#app {
					min-width: 0px !important;
				}

				.opus-detail{
					width: auto !important;
                    min-width: 0px !important;
					max-width: 708px !important;
				}
			`);
        }
        GM_addStyle(`
			.bili-tabs__header {
				padding: 0 !important;
			}

			.bili-tabs__nav__item.is-active {
				padding: 0 !important;
			}

			div.bili-comment-container {
				padding: 0 10px 0 0px !important;
			}

			.reply-navigation {
				margin: 20px 0 0 20px !important;
			}
		`);

        console.log('修改样式完毕');
    }

    // 创建一个带有文件名称的 <meta> 元素,供singlefile使用(需要在singlefile的文件名规则中获取这个元素)
    function addFilenameForSinglefile() {
        const metaTag = document.createElement('meta');

        // 设置属性
        metaTag.setAttribute('name', 'singlefile-filename');
        metaTag.setAttribute('content', singleFileName);

        // 将 <meta> 元素添加到 <head> 标签中
        document.head.appendChild(metaTag);
    }

    function end() {
        isScriptExecuting = false;
        //删除覆盖和提示
        removeOverlayAndMessage();
        // 跳转到页面底部
        scrollToBottom();

        console.log('脚本执行完毕');
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址