Biliplus Patch

修复biliplus的部分失效功能

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Biliplus Patch
// @namespace    http://tampermonkey.net/
// @version      1.0.6
// @description  修复biliplus的部分失效功能
// @author       META-USER
// @license      MIT
// @match        *://*.biliplus.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @icon         https://pro-cos-public-1304449511.cos.ap-shanghai.myqcloud.com/seewo-login/bppicon.png
// @connect      api.bilibili.com
// @connect      s.video.sina.com.cn
// @connect      api.ivideo.sina.com.cn
// @connect      interface.sina.cn
// @connect      s3.ivideo.sina.com.cn
// @connect      edge.ivideo.sina.com.cn
// @connect      h5vv.video.qq.com
// @connect      pbaccess.video.qq.com
// @connect      access.video.qq.com
// @connect      api.youku.com
// @run-at       document-idle
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/protobuf.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/flv.min.js
// ==/UserScript==

'use strict';

/* 工具函数 */
// 跨域get请求
function GM_get_request(url, callback, extra, customHeaders = {}, responseType = 'text') {
    let headers = {
        'Accept': '*/*',
        ...customHeaders
    };

    GM_xmlhttpRequest({
        method: 'GET',
        url: url,
        timeout: 10000,
        headers: headers,
        responseType: responseType,
        onload: function(response) {
            // 构建统一的响应对象
            const result = {
                status: response.status,
                statusText: response.statusText,
                headers: response.responseHeaders,
                finalUrl: response.finalUrl,
                response: response.response,
                responseText: response.responseText
            };

            callback(result, extra);
        },
        onerror: function(error) {
            callback({
                status: 0,
                statusText: 'Network Error',
                message: '网络错误'
            }, extra);
        },
        ontimeout: function() {
            callback({
                status: -1,
                statusText: 'Timeout',
                message: '请求超时'
            }, extra);
        }
    });
}
// 跨域get请求
function GM_getjson(url, callback, extra, customHeaders = {}) {
    let headers = {
        'Accept': 'application/json, text/plain, */*',
        ...customHeaders
    };
    GM_xmlhttpRequest({
        method: 'GET',
        url: url,
        timeout: 10000,
        headers: headers,
        responseType: 'json',
        onload: function(response) {
            if (response.status === 200) {
                callback(response.response, extra);
            } else {
                callback({
                    code: response.status,
                    message: `HTTP错误: ${response.status}`
                }, extra);
            }
        },
        onerror: function(error) {
            callback({
                code: -502,
                message: '网络错误'
            }, extra);
        },
        ontimeout: function() {
            callback({
                code: -1,
                message: '请求超时'
            }, extra);
        }
    });
}
// 跨域post请求
function GM_postjson(url, data, callback, extra, customHeaders = {}) {
    let headers = {
        'Accept': 'application/json, text/plain, */*',
        ...customHeaders
    };

    let postData;

    // 判断数据类型并设置相应的Content-Type
    if (typeof data === 'object' && !(data instanceof FormData)) {
        headers['Content-Type'] = 'application/json';
        postData = JSON.stringify(data);
    } else if (typeof data === 'string') {
        headers['Content-Type'] = 'application/x-www-form-urlencoded';
        postData = data;
    } else {
        // FormData或其他类型,不设置Content-Type(让浏览器自动设置)
        postData = data;
    }

    GM_xmlhttpRequest({
        method: 'POST',
        url: url,
        timeout: 10000,
        headers: headers,
        data: postData,
        responseType: 'json',
        onload: function(response) {
            if (response.status === 200 || response.status === 201) {
                if (extra !== undefined) {
                    callback(response.response, extra);
                } else {
                    callback(response.response);
                }
            } else {
                const error = {
                    code: response.status,
                    message: `HTTP错误: ${response.status}`
                };
                if (extra !== undefined) {
                    callback(error, extra);
                } else {
                    callback(error);
                }
            }
        },
        onerror: function(error) {
            const errorObj = {
                code: -502,
                message: '网络错误'
            };
            if (extra !== undefined) {
                callback(errorObj, extra);
            } else {
                callback(errorObj);
            }
        },
        ontimeout: function() {
            const errorObj = {
                code: -1,
                message: '请求超时'
            };
            if (extra !== undefined) {
                callback(errorObj, extra);
            } else {
                callback(errorObj);
            }
        }
    });
}

// 异步sleep配置
function sleep(sec) {
    return new Promise(resolve => setTimeout(resolve, sec * 1000));
}
/**
 * 将Unix时间戳转换为格式化的日期时间字符串
 * @param {number|string} timestamp - Unix时间戳(秒级)
 * @returns {string} 格式化后的日期时间字符串,格式:YYYY-MM-DD HH:mm:ss
 */
function formatTimestamp(timestamp) {
    // 将时间戳转换为毫秒
    const date = new Date(timestamp * 1000);

    // 获取各个时间部分
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');

    // 组合成目标格式
    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

// 辅助函数:格式化时长(秒转换为时分秒)
function formatDuration(seconds) {
    if (!seconds) return '0秒';

    const hours = Math.floor(seconds / 3600);
    const minutes = Math.floor((seconds % 3600) / 60);
    const secs = seconds % 60;

    const parts = [];
    if (hours > 0) parts.push(`${hours}小时`);
    if (minutes > 0) parts.push(`${minutes}分钟`);
    if (secs > 0 || parts.length === 0) parts.push(`${secs}秒`);

    return parts.join('');
}
/**
 * 获取今日日期
 * @returns {string} 格式化后的日期时间字符串,格式:YYYY-MM-DD
 */
function getTodayDate() {
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, '0');
    const day = String(today.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
}

// av号转bv号
function av2bv(aid) {
    const XOR_CODE = 23442827791579n;
    const MASK_CODE = 2251799813685247n;
    const MAX_AID = 1n << 51n;
    const BASE = 58n;

    const data = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf';

    const bytes = ['B', 'V', '1', '0', '0', '0', '0', '0', '0', '0', '0', '0'];
    let bvIndex = bytes.length - 1;
    let tmp = (MAX_AID | BigInt(aid)) ^ XOR_CODE;
    while (tmp > 0) {
        bytes[bvIndex] = data[Number(tmp % BigInt(BASE))];
        tmp = tmp / BASE;
        bvIndex -= 1;
    }
    [bytes[3], bytes[9]] = [bytes[9], bytes[3]];
    [bytes[4], bytes[7]] = [bytes[7], bytes[4]];
    return bytes.join('');
}
// bv号转av号
function bv2av(bvid) {
    const XOR_CODE = 23442827791579n;
    const MASK_CODE = 2251799813685247n;
    const MAX_AID = 1n << 51n;
    const BASE = 58n;

    const data = 'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf';

    const bvidArr = Array.from(bvid);
    [bvidArr[3], bvidArr[9]] = [bvidArr[9], bvidArr[3]];
    [bvidArr[4], bvidArr[7]] = [bvidArr[7], bvidArr[4]];
    bvidArr.splice(0, 3);
    const tmp = bvidArr.reduce((pre, bvidChar) => pre * BASE + BigInt(data.indexOf(bvidChar)), 0n);
    return Number((tmp & MASK_CODE) ^ XOR_CODE);
}

// 初始化脚本
function script_init() {
    //获取cid记录页数据
    // 有必要改改,可以用劫持之类的
    function reload_cid_record_data() {
        const currentPath = window.location.pathname;
        const targetPages = ['/all/video/'];
        const isTargetPage = targetPages.some(page => currentPath.startsWith(page));
        if (!isTargetPage) return;

        async function get_view_all_data() {
            // 正则匹配密钥参数
            let paramMatch = document.documentElement.outerHTML.match(/getjson\('\/api\/view_all\?([^']+)'/);

            if (paramMatch) {
                let queryString = paramMatch[1];
                // 重新请求以获取cid信息
                await getjson('/api/view_all?' + queryString, async json => {
                    window.view_all_data = json;
                });
            }

        }
        get_view_all_data();
    };
    
    // 执行
    reload_cid_record_data()

}


/* 主要功能 */

// 配置额外功能

/*
添加额外功能步骤:
注释内已标明步骤顺序,搜索步骤即可

 */
function add_extra_features() {
    // 初始化switches样式
    function switches_init() {
        // 默认开启功能
        // 配置额外功能网页存储默认开关状态 步骤2
        if (localStorage.add_snapshot === undefined) {
            localStorage.add_snapshot = 'on';
        };
        if (localStorage.add_externaldetail === undefined) {
            localStorage.add_externaldetail = 'on';
        };



        // 选项开关状态
        // 配置额外功能渲染默认开关状态 步骤3
        if (localStorage.random_cid == 'on') {
            document.getElementById('feature_random_cid').className = 'switch on'; // 开启样式
        } else {
            document.getElementById('feature_random_cid').className = 'switch'; // 关闭样式
        }
        if (localStorage.ban_history == 'on') {
            document.getElementById('feature_ban_history').className = 'switch on'; // 开启样式
        } else {
            document.getElementById('feature_ban_history').className = 'switch'; // 关闭样式
        }
        if (localStorage.add_snapshot == 'on') {
            document.getElementById('feature_add_snapshot').className = 'switch on'; // 开启样式
        } else {
            document.getElementById('feature_add_snapshot').className = 'switch'; // 关闭样式
        }
        if (localStorage.add_externaldetail == 'on') {
            document.getElementById('feature_add_externaldetail').className = 'switch on'; // 开启样式
        } else {
            document.getElementById('feature_add_externaldetail').className = 'switch'; // 关闭样式
        }
    }

    // 开关点击事件:长期记忆配置
    // 配置额外功能开关点击事件 步骤4
    const random_cid = function() {
        var d = document.getElementById('feature_random_cid');
        d.className = 'switch' + (localStorage.random_cid != 'on' ? ' on' : '');
        localStorage.random_cid = localStorage.random_cid != 'on' ? 'on' : 'off';

    }
    const ban_history = function() {
        var d = document.getElementById('feature_ban_history');
        d.className = 'switch' + (localStorage.ban_history != 'on' ? ' on' : '');
        localStorage.ban_history = localStorage.ban_history != 'on' ? 'on' : 'off';

    }
    const add_snapshot = function() {
        var d = document.getElementById('feature_add_snapshot');
        d.className = 'switch' + (localStorage.add_snapshot != 'on' ? ' on' : '');
        localStorage.add_snapshot = localStorage.add_snapshot != 'on' ? 'on' : 'off';

    }
    const add_externaldetail = function() {
        var d = document.getElementById('feature_add_externaldetail');
        d.className = 'switch' + (localStorage.add_externaldetail != 'on' ? ' on' : '');
        localStorage.add_externaldetail = localStorage.add_externaldetail != 'on' ? 'on' : 'off';

    }
    // 用于添加一个额外功能(参数:父容器,功能标题,开关id,开关点击事件,功能介绍)
    function create_feature_switch(feature_switches, title_text, switch_id, onclick, tip_text) {
        // 创建fieldset容器
        const fieldset = document.createElement('fieldset');
        fieldset.style.maxWidth = '725px';

        // 创建第一个div容器(包含标题和开关)
        const firstDiv = document.createElement('div');
        firstDiv.textContent = title_text;

        // 创建开关按钮
        const switchDiv = document.createElement('div');
        switchDiv.className = 'switch';
        switchDiv.id = switch_id;
        switchDiv.onclick = onclick;

        // 将开关添加到第一个div中
        firstDiv.appendChild(switchDiv);

        // 创建第二个div(提示文字)
        const secondDiv = document.createElement('div');
        secondDiv.textContent = tip_text;

        // 将所有元素添加到fieldset中
        fieldset.appendChild(firstDiv);
        fieldset.appendChild(secondDiv);

        feature_switches.appendChild(fieldset);
    }


    /* 容器配置 */

    // 创建内容容器
    function create_features_container() {
        // 创建features_container
        const features_container = document.createElement('div');
        features_container.id = "features_container";
        features_container.className = "container"
        features_container.style = "opacity:1;display:none;transition:none"

        // 在features_container内部创建背景
        const black_back = document.createElement('div');
        black_back.className = "black_back"
        black_back.style = "opacity:0;transition:0.5s"
        black_back.onclick = () => features(0); // 假设有features函数,与settings函数类似

        features_container.appendChild(black_back);

        // 创建侧边栏容器(类似settings中的样式)
        const sidebar = document.createElement('div');
        sidebar.style = "width:320px;height:100%;position:fixed;top:0;right:-320px;animation-duration:0.5s;background:#EFEFF4";

        // 创建关闭按钮容器
        const closeContainer = document.createElement('div');
        closeContainer.style = "position:absolute;top:0;left:0;padding:10px 15px;width:100%";

        const closeSpan = document.createElement('span');
        closeSpan.textContent = "< 关闭";
        closeSpan.style = "padding:5px;background:#CBCBC0;border-radius:5px;cursor:pointer";
        closeSpan.onclick = () => features(0); // 关闭功能

        closeContainer.appendChild(closeSpan);
        sidebar.appendChild(closeContainer);

        // 创建内容区域
        const contentDiv = document.createElement('div');
        contentDiv.id = "features_content";
        contentDiv.style = "position:absolute;top:40px;bottom:5px;right:5px;width:310px;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch";

        // 创建标题
        const titleDiv = document.createElement('div');
        titleDiv.className = "frametitle";
        titleDiv.textContent = "额外功能";

        const feature_switches = document.createElement('div');
        feature_switches.id = "feature_switches";
        // 创建额外功能 开始 步骤1
        // 重要!配置开关id和点击事件不要错
        create_feature_switch(feature_switches, "随机CID", "feature_random_cid", random_cid, "主页加载随机CID稿件");
        create_feature_switch(feature_switches, "不记录观看历史", "feature_ban_history", ban_history, "修复版html5播放器不记录观看历史(对原版播放器无效)");
        create_feature_switch(feature_switches, "视频快照查看", "feature_add_snapshot", add_snapshot, "CID历史记录页支持CID快照查看");
        create_feature_switch(feature_switches, "源详情查询", "feature_add_externaldetail", add_externaldetail, "CID历史记录页支持源详情查询(目前支持新浪源,优酷源,腾讯源,直传源)");
        // 创建额外功能 结束
        contentDiv.appendChild(titleDiv);
        contentDiv.appendChild(feature_switches);

        sidebar.appendChild(contentDiv);
        features_container.appendChild(sidebar);

        document.body.appendChild(features_container);

    }

    // 侧边栏内'额外功能'项目点击事件(参数:是否渲染内容容器(1:开启,0:关闭))
    const features = function(s) {
        var sc = document.getElementById('features_container'),
            bb = sc.childNodes[0],
            wf = sc.childNodes[1];

        if (s) {
            // 显示设置面板
            sc.style.display = 'block';
            bb.style.opacity = .7;
            bb.style.animationName = 'black_back-in';
            wf.style.right = 0;
            wf.style.animationName = 'right-slide-in';
        } else {
            // 隐藏设置面板
            bb.style.opacity = 0;
            bb.style.animationName = 'black_back-out';
            wf.style.right = '-320px';
            wf.style.animationName = 'right-slide-out';
            setTimeout(function() {
                sc.style.display = 'none';
            }, 500);
        }
    }
    // 在侧边栏添加'额外功能'项目
    function addExtraItem() {
        // 找到用户侧边栏容器
        const userSidebar = document.getElementById('usersidebar');
        if (!userSidebar) return;

        // 检查是否已经添加过项目
        if (document.getElementById('extra-sidebar-item')) {
            return;
        }

        // 创建项目
        const extraItem = document.createElement('div');
        extraItem.className = 'usersidebar_item';
        extraItem.id = 'extra-sidebar-item';

        // 创建内部容器
        const itemInner = document.createElement('div');
        itemInner.className = 'usersidebar_item_inner';
        itemInner.textContent = '额外功能';
        itemInner.style.cursor = 'pointer';

        // 添加点击事件
        itemInner.addEventListener('click', function() {
            features(1);
            usersidebar(0)
        });

        // 添加到侧边栏
        extraItem.appendChild(itemInner);

        // 找到"设置"项目,在其前面插入
        const settingsItem = userSidebar.querySelector('.usersidebar_item[onclick*="settings"]');
        if (settingsItem) {
            userSidebar.insertBefore(extraItem, settingsItem);
        } else {
            userSidebar.appendChild(extraItem);
        }
    }

    create_features_container();
    addExtraItem();
    // 先创建容器再初始化switches
    switches_init()

}

// 添加cid快照查看
function add_video_snapshot() {
    const currentPath = window.location.pathname;
    const targetPages = ['/all/video/'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));

    if (!isTargetPage) return;
    // 不启用此功能则退出
    if (localStorage.add_snapshot !== "on") return;

    const show_snapshot = function(cid) {
        const existingPlayer = document.getElementById('floatingImagePlayer');
        if (existingPlayer) existingPlayer.remove();

        let currentIndex = 0;
        let maxDetectedIndex = 0; // 已检测到的最大索引
        let isChecking = false; // 是否正在检测中
        let imageViewer = null; // 图片查看器引用

        // 检查单张图片是否存在
        const checkImageExists = (index) => {
            const imageUrl = index === 0 ?
                `https://i0.hdslb.com/bfs/videoshot/${cid}.jpg` :
                `https://i0.hdslb.com/bfs/videoshot/${cid}-${index}.jpg`;

            return new Promise((resolve) => {
                const testImg = new Image();
                testImg.onload = () => resolve({
                    index,
                    exists: true,
                    url: imageUrl
                });
                testImg.onerror = () => resolve({
                    index,
                    exists: false,
                    url: imageUrl
                });
                testImg.src = imageUrl;
            });
        };

        // 异步检测后续图片
        const checkNextImages = async () => {
            if (isChecking) return;
            isChecking = true;

            let nextIndex = maxDetectedIndex + 1;
            let foundNew = false;

            // 批量检测3张
            for (let i = 0; i < 3; i++) {
                const result = await checkImageExists(nextIndex + i);

                if (result.exists) {
                    maxDetectedIndex = result.index;
                    foundNew = true;

                } else {
                    // 图片不存在,停止检测
                    break;
                }
            }

            isChecking = false;

            // 如果检测到新图片,更新界面
            if (foundNew && imageViewer && imageViewer.updateNavButtons) {
                imageViewer.updateNavButtons();

                // 如果还有可能更多图片,继续检测
                if (!isChecking) {
                    setTimeout(checkNextImages, 100);
                }
            }
        };

        // 创建图片查看器
        const createImageViewer = () => {
            // 先检查第一张图片是否存在
            checkImageExists(0).then(firstResult => {
                if (!firstResult.exists) {
                    showError('暂无快照');
                    return;
                }

                maxDetectedIndex = 0; // 第一张存在

                const container = document.createElement('div');
                container.id = 'floatingImagePlayer';
                container.style.cssText = `
                    position: fixed;
                    top: 0;
                    left: 0;
                    width: 100vw;
                    height: 100vh;
                    background-color: rgba(0, 0, 0, 0.9);
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    flex-direction: column;
                    z-index: 9999;
                `;

                const closeBtn = document.createElement('button');
                closeBtn.textContent = '×';
                closeBtn.style.cssText = `
                    position: absolute;
                    top: 20px;
                    right: 20px;
                    background: transparent;
                    color: white;
                    border: none;
                    font-size: 30px;
                    cursor: pointer;
                    z-index: 10000;
                    padding: 10px;
                    line-height: 1;
                `;

                const imgContainer = document.createElement('div');
                imgContainer.style.cssText = `
                    max-width: 90vw;
                    max-height: 70vh;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    margin-bottom: 20px;
                `;

                // 创建错误消息元素
                const errorMsg = document.createElement('div');
                errorMsg.id = 'snapshotErrorMsg';
                errorMsg.style.cssText = `
                    color: #999;
                    font-size: 16px;
                    display: none;
                    text-align: center;
                `;

                const img = document.createElement('img');
                img.id = 'displayedImage';
                img.style.cssText = `
                    max-width: 100%;
                    max-height: 100%;
                    object-fit: contain;
                    display: none;
                `;
                img.alt = '视频快照';

                // 创建导航按钮容器
                const navContainer = document.createElement('div');
                navContainer.style.cssText = `
                    display: flex;
                    gap: 20px;
                    margin-top: 20px;
                    align-items: center;
                `;

                const prevBtn = document.createElement('button');
                prevBtn.id = 'prevSnapshotBtn';
                prevBtn.textContent = '上一页';
                prevBtn.style.cssText = `
                    padding: 10px 20px;
                    background-color: #00a1d6;
                    color: white;
                    border: none;
                    border-radius: 4px;
                    cursor: pointer;
                    font-size: 14px;
                    opacity: 0.5;
                    cursor: not-allowed;
                `;

                const nextBtn = document.createElement('button');
                nextBtn.id = 'nextSnapshotBtn';
                nextBtn.textContent = '下一页';
                nextBtn.style.cssText = `
                    padding: 10px 20px;
                    background-color: #00a1d6;
                    color: white;
                    border: none;
                    border-radius: 4px;
                    cursor: pointer;
                    font-size: 14px;
                    opacity: 0.5;
                    cursor: not-allowed;
                `;

                // 页码指示器
                const pageIndicator = document.createElement('span');
                pageIndicator.id = 'snapshotPageIndicator';
                pageIndicator.style.cssText = `
                    color: white;
                    font-size: 14px;
                    margin: 0 15px;
                    min-width: 60px;
                    text-align: center;
                `;

                // 加载提示(当检测下一页时显示)
                const loadingIndicator = document.createElement('span');
                loadingIndicator.id = 'snapshotLoadingIndicator';
                loadingIndicator.textContent = '检测中...';
                loadingIndicator.style.cssText = `
                    color: #aaa;
                    font-size: 12px;
                    margin-left: 10px;
                    display: none;
                `;

                // 更新导航按钮状态
                const updateNavButtons = () => {


                    // 上一页按钮状态
                    const hasPrev = currentIndex > 0;
                    prevBtn.disabled = !hasPrev;
                    prevBtn.style.opacity = hasPrev ? '1' : '0.5';
                    prevBtn.style.cursor = hasPrev ? 'pointer' : 'not-allowed';

                    // 下一页按钮状态
                    const hasNext = currentIndex < maxDetectedIndex;
                    nextBtn.disabled = !hasNext;
                    nextBtn.style.opacity = hasNext ? '1' : '0.5';
                    nextBtn.style.cursor = hasNext ? 'pointer' : 'not-allowed';

                    // 更新页码显示
                    pageIndicator.textContent = `${currentIndex + 1} / ${maxDetectedIndex + 1}`;

                    // 如果当前是最后一张且正在检测下一页,显示加载提示
                    if (currentIndex === maxDetectedIndex && isChecking) {
                        loadingIndicator.style.display = 'inline';
                    } else {
                        loadingIndicator.style.display = 'none';
                    }


                };

                // 显示图片
                const displayImage = (index) => {
                    const imageUrl = index === 0 ?
                        `https://i0.hdslb.com/bfs/videoshot/${cid}.jpg` :
                        `https://i0.hdslb.com/bfs/videoshot/${cid}-${index}.jpg`;



                    img.onload = () => {
                        img.style.display = 'block';
                        errorMsg.style.display = 'none';

                    };

                    img.onerror = () => {
                        img.style.display = 'none';
                        errorMsg.style.display = 'block';
                        errorMsg.textContent = '图片加载失败';

                    };

                    img.src = imageUrl;
                    currentIndex = index;
                    updateNavButtons();

                    // 如果显示的是最后一张,开始检测更多图片
                    if (index === maxDetectedIndex && !isChecking) {

                        checkNextImages();
                    }
                };

                // 按钮事件
                prevBtn.onclick = () => {
                    if (currentIndex > 0) {
                        displayImage(currentIndex - 1);
                    }
                };

                nextBtn.onclick = () => {
                    if (currentIndex < maxDetectedIndex) {
                        displayImage(currentIndex + 1);
                    }
                };

                // 键盘导航
                const escHandler = (e) => {
                    if (e.key === 'Escape') container.remove();
                    if (e.key === 'ArrowLeft' && currentIndex > 0) displayImage(currentIndex - 1);
                    if (e.key === 'ArrowRight' && currentIndex < maxDetectedIndex) displayImage(currentIndex + 1);
                };

                // 关闭按钮事件
                closeBtn.onclick = () => container.remove();
                container.onclick = (e) => {
                    if (e.target === container) container.remove();
                };

                // 组装元素
                navContainer.appendChild(prevBtn);
                navContainer.appendChild(pageIndicator);
                navContainer.appendChild(nextBtn);
                navContainer.appendChild(loadingIndicator);

                imgContainer.appendChild(img);
                imgContainer.appendChild(errorMsg);

                container.appendChild(closeBtn);
                container.appendChild(imgContainer);
                container.appendChild(navContainer);

                document.body.appendChild(container);
                document.addEventListener('keydown', escHandler);

                // 清理事件监听器
                const originalRemove = container.remove;
                container.remove = function() {
                    document.removeEventListener('keydown', escHandler);
                    originalRemove.call(this);
                };

                // 显示第一张图片
                displayImage(0);

                // 创建imageViewer对象以便外部访问
                imageViewer = {
                    container,
                    close: () => container.remove(),
                    updateNavButtons,
                    displayImage
                };

                // 开始检测后续图片

                checkNextImages();

                return imageViewer;
            });
        };

        // 显示错误信息
        const showError = (message) => {
            const container = document.createElement('div');
            container.id = 'floatingImagePlayer';
            container.style.cssText = `
                position: fixed;
                top: 0;
                left: 0;
                width: 100vw;
                height: 100vh;
                background-color: rgba(0, 0, 0, 0.9);
                display: flex;
                align-items: center;
                justify-content: center;
                z-index: 9999;
            `;

            const errorMsg = document.createElement('div');
            errorMsg.textContent = message;
            errorMsg.style.cssText = `
                color: #999;
                font-size: 18px;
                padding: 20px;
                background-color: rgba(255, 255, 255, 0.1);
                border-radius: 8px;
            `;

            const closeBtn = document.createElement('button');
            closeBtn.textContent = '×';
            closeBtn.style.cssText = `
                position: absolute;
                top: 20px;
                right: 20px;
                background: transparent;
                color: white;
                border: none;
                font-size: 30px;
                cursor: pointer;
                z-index: 10000;
                padding: 10px;
                line-height: 1;
            `;

            closeBtn.onclick = () => container.remove();
            container.onclick = (e) => {
                if (e.target === container) container.remove();
            };

            container.appendChild(closeBtn);
            container.appendChild(errorMsg);
            document.body.appendChild(container);
        };

        // 创建查看器
        createImageViewer();
    };

    function create_snapshot_item(cid) {
        const cid_item = document.getElementById('cid_' + cid)
        if (cid_item) {
            const snapshot_item = document.createElement('div');
            snapshot_item.className = "solidbox pointer";
            snapshot_item.onclick = () => show_snapshot(cid);
            snapshot_item.textContent = "查看快照";
            cid_item.parentNode.insertBefore(snapshot_item, cid_item);
        }
    };

    const timer = setInterval(function() {
        if (window.view_all_data) {
            const json = window.view_all_data
            if (json.code === 0) {
                json.data.parts.forEach(part => {
                    create_snapshot_item(part.cid);
                })
            }
            clearInterval(timer);
        }
    }, 200);
}

function add_video_detail() {
    const currentPath = window.location.pathname;
    const targetPages = ['/all/video/'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));

    if (!isTargetPage) return;
    // 不启用此功能则退出
    if (localStorage.add_externaldetail !== "on") return;

    function get_externaldetail(cid, type, vid) {
        const default_json = {
            "code": -1,
            "message": `暂不支持${type}视频源`,
            "data": {}
        };
        const video_json = {
            "code": 0,
            "message": "获取成功",
            "data": {}
        };

        switch (type) {
            case "sina":
                // 新浪视频信息获取
                return new Promise((resolve, reject) => {
                    getSinaVideoInfo(vid, resolve);
                });
            case "qq":
                // 腾讯视频信息获取
                return new Promise((resolve, reject) => {
                    getQQVideoInfo(vid, resolve);
                });
            case "youku":
                // 优酷视频信息获取
                return new Promise((resolve, reject) => {
                    getYoukuVideoInfo(vid, resolve);
                });
            case "vupload":
                // 直传视频信息获取
                return new Promise((resolve, reject) => {
                    getBillibiliVideoInfo(cid, resolve);
                });
            default:
                return Promise.resolve(default_json);
        }

        // 新浪视频信息获取
        function getSinaVideoInfo(vid, resolve) {
            GM_getjson('https://s.video.sina.com.cn/video/getvideoidbyvid?vid=' + vid, function(json) {
                if (json.code !== 1) {
                    getSinaVideoInfoBackup(vid, resolve, json.message, 0);
                    return;
                }

                const sina_video_id = json.data.video_id;

                GM_getjson('http://api.ivideo.sina.com.cn/public/video/play?appname=sinaplayer_pc&tags=sinaplayer_pc&applt=web&appver=V11220.210521.03&player=all&video_id=' + sina_video_id, function(json) {
                    if (json.code !== 1) {
                        getSinaVideoInfoBackup(vid, resolve, json.Message, sina_video_id);
                        return;
                    }

                    // 通过此数据中的videos获取ipad_id
                    const mp4Video = json.data.videos.find(video => video.type === 'mp4');
                    let ipad_vid = 0;

                    if (mp4Video) {
                        ipad_vid = mp4Video.file_id;
                    }

                    // 配置要返回的数据
                    video_json.data.ids = {
                        "vid": vid,
                        "video_id": sina_video_id,
                        "ipad_vid": ipad_vid
                    };
                    video_json.data.title = json.data.title;
                    video_json.data.link = `http://video.sina.com.cn/view/${sina_video_id}.html`;
                    video_json.data.cover = json.data.image;
                    video_json.data.created = formatTimestamp(json.data.create_time);
                    video_json.data.description = json.data.description;
                    video_json.data.duration = Math.round(json.data.length / 1000);
                    video_json.data.state = "正常";

                    resolve(video_json);
                });
            });
        }

        function getSinaVideoInfoBackup(vid, resolve, errMessage, sina_video_id) {
            GM_getjson('https://interface.sina.cn/video/wap/videoinfo.d.json?vid=' + vid, function(json) {
                if (json.data.title == undefined) {
                    default_json.message = errMessage;
                    resolve(default_json);
                    return;
                }

                // 通过此数据中的videos获取ipad_id

                let ipad_vid = 0;
                ipad_vid = json.data.mp4vid;
                // 配置要返回的数据
                video_json.data.ids = {
                    "vid": vid,
                    "video_id": sina_video_id,
                    "ipad_vid": ipad_vid
                };
                video_json.data.title = json.data.title;
                video_json.data.link = `http://video.sina.com.cn/view/${sina_video_id}.html`;
                video_json.data.cover = json.data.image;

                video_json.data.description = json.data.description;
                video_json.data.duration = Math.round(json.data.timeLength / 1000);
                video_json.data.state = "正常";

                resolve(video_json);

            });
        }

        // 腾讯视频信息获取
        function getQQVideoInfo(vid, resolve) {
            GM_postjson('https://pbaccess.video.qq.com/trpc.universal_backend_service.page_server_rpc.PageServer/GetPageData', {
                "page_params": {
                    "vid": vid,
                    "page_type": "video_detail"
                }
            }, function(pageData) {
                if (pageData.ret !== 0) {
                    default_json.message = pageData.msg;
                    resolve(default_json);
                    return;
                }

                // 初始化视频数据
                video_json.data.ids = {
                    "vid": vid
                };
                video_json.data.link = `https://v.qq.com/x/page/${vid}.html`;
                video_json.data.cover = `https://puui.qpic.cn/vpic_cover/${vid}/${vid}_hz.jpg`;

                // 提取页面数据中的视频信息
                if (pageData.data.module_list_datas[0]?.module_datas[0]?.item_data_lists?.item_datas[0]?.item_params) {
                    const video_item = pageData.data.module_list_datas[0].module_datas[0].item_data_lists.item_datas[0].item_params;

                    video_json.data.title = video_item.title;
                    video_json.data.created = video_item.detail_info.match(/\d{4}年\d{1,2}月\d{1,2}日/)[0];
                    video_json.data.description = video_item.video_description;
                }

                // 提取播放数据中的视频信息
                let play_item = null;
                if (pageData.data.module_list_datas.length > 1) {
                    play_item = pageData.data.module_list_datas[1]?.module_datas[0]?.item_data_lists?.item_datas[0]?.item_params;
                }

                if (play_item && play_item.vid === vid) {
                    if (play_item.title) video_json.data.title = play_item.title;
                    if (play_item.duration) video_json.data.duration = play_item.duration;
                    if (play_item.date) video_json.data.created = play_item.date;
                }

                // 获取分享信息
                getQQShareInfo(vid, video_json, resolve);
            }, null, {
                "Cookie": "video_appid=3000002; vversion_name=8.9.16.0",
                "referer": "https://servicewechat.com"
            });
        }

        // 获取腾讯视频分享信息
        function getQQShareInfo(vid, video_json, resolve) {
            GM_postjson('https://access.video.qq.com/tinyapp/share_info?raw=1&vappid=11333374&vsecret=45ce5b9d91f29688f832ad435ea227cf719a29571257d447', {
                "dataKey": "vid=" + vid,
                "scene": 1
            }, function(shareData) {
                if (shareData.ret === 0 && shareData.data.shareItem) {
                    const video_item = shareData.data.shareItem;

                    if (video_item.shareTitle) video_json.data.title = video_item.shareTitle;
                    if (video_item.totalTime) video_json.data.duration = video_item.totalTime;
                    if (video_item.shareImgUrl) video_json.data.cover = video_item.shareImgUrl;
                }

                // 获取视频状态信息
                getQQVideoStatus(vid, video_json, resolve);
            });
        }

        // 获取腾讯视频状态信息
        function getQQVideoStatus(vid, video_json, resolve) {
            GM_getjson('https://h5vv.video.qq.com/getinfo?otype=ojson&vid=' + vid, function(infoData) {
                if (infoData) {
                    video_json.data.state = infoData.exem !== 0 ? infoData.msg : "正常";
                }

                resolve(video_json);
            });
        }
        // 获取优酷数字ID
        function getYoukuIdByVid(vid) {
            return atob(vid.slice(1)) / 4
        };
        // 获取优酷视频信息
        function getYoukuVideoInfo(vid, resolve) {
            const stateToChinese = {
                "normal": '正常',
                "encoding": '转码中',
                "fail": '转码失败',
                "in_review": '审核中',
                "limited": '分级'
            };
            const youku_id = getYoukuIdByVid(vid)
            GM_getjson('https://api.youku.com/videos/show.json?client_id=f4b0da916cc86fe5&video_id=' + youku_id, function(json) {
                if (json.error) {
                    default_json.message = json.error.description;
                    resolve(default_json);
                    return;
                }
                video_json.data.ids = {
                    "vid": vid,
                    "youku_id": youku_id
                };
                video_json.data.title = json.title;
                video_json.data.link = `http://v.youku.com/v_show/id_${vid}.html`;
                video_json.data.cover = json.thumbnail;
                video_json.data.created = json.created;
                video_json.data.description = json.description;
                video_json.data.duration = Math.round(json.duration);
                video_json.data.state = stateToChinese[json.state];
                video_json.data.nickname = json.user.name

                resolve(video_json);



            });
        }

        function getBillibiliVideoInfo(cid, resolve) {
            GM_getjson('https://www.biliplus.com/api/cidinfo?cid=' + cid, function(json) {
                if (json.code !== 0) {
                    default_json.message = json.message;
                    resolve(default_json);
                    return;
                }
                const aid = json.data.aid;
                const bvid = av2bv(aid);
                video_json.data.ids = {
                    "aid": aid,
                    "bvid": bvid,
                    "cid": cid
                };
                video_json.data.title = json.data.title;
                video_json.data.link = `https://www.bilibili.com/video/av${aid}`;
                video_json.data.cover = json.data.cover;
                video_json.data.nickname = json.data.author;
                getBilibiliShareInfo(aid, video_json, resolve);

            });
        }

        function getBilibiliShareInfo(aid, video_json, resolve) {
            GM_postjson('https://api.bilibili.com/x/share/click', `build=1&buvid=1&oid=${aid}&platform=1&share_channel=MARK_POINT&share_id=main.ugc-video-detail.0.0.pv&share_mode=1`, function(shareData) {
                if (shareData.code === 0) {
                    const video_item = shareData.data;

                    if (video_item.title) video_json.data.title = video_item.title;
                    if (video_item.picture) video_json.data.cover = video_item.picture;
                }

                // 获取视频状态信息
                resolve(video_json);
            });
        }

    }

    const show_externaldetail = function(cid, type, vid) {
        const existingPlayer = document.getElementById('floatingExternalDetail');
        if (existingPlayer) existingPlayer.remove();

        // 创建主容器 - 改为亮色背景
        const container = document.createElement('div');
        container.id = 'floatingExternalDetail';
        container.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100vw;
        height: 100vh;
        background-color: rgba(0, 0, 0, 0.7); /* 半透明遮罩层 */
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 9999;
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    `;

        // 内容容器 - 改为亮色主题(白灰色)
        const contentContainer = document.createElement('div');
        contentContainer.style.cssText = `
        background: #f8f9fa; /* 主背景改为浅灰色 */
        border-radius: 12px;
        width: 90%;
        max-width: 800px;
        max-height: 90vh;
        overflow-y: auto;
        padding: 30px;
        box-sizing: border-box;
        box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
        color: #333; /* 文字颜色改为深色 */
        position: relative; /* 为关闭按钮提供定位上下文 */
    `;

        // 关闭按钮 - 移到容器内部右上角
        const closeBtn = document.createElement('button');
        closeBtn.textContent = '×';
        closeBtn.style.cssText = `
        position: absolute;
        top: 15px;
        right: 15px;
        background: #f0f0f0; /* 按钮背景改为浅灰色 */
        color: #666; /* 按钮颜色改为灰色 */
        border: none;
        font-size: 24px;
        cursor: pointer;
        z-index: 10000;
        padding: 5px 10px;
        line-height: 1;
        width: 32px;
        height: 32px;
        border-radius: 50%;
        transition: all 0.3s;
        display: flex;
        align-items: center;
        justify-content: center;
    `;
        closeBtn.onmouseenter = () => {
            closeBtn.style.backgroundColor = '#e0e0e0';
            closeBtn.style.color = '#333';
        };
        closeBtn.onmouseleave = () => {
            closeBtn.style.backgroundColor = '#f0f0f0';
            closeBtn.style.color = '#666';
        };

        // 加载状态 - 改为深色文字
        const loadingDiv = document.createElement('div');
        loadingDiv.style.cssText = `
        text-align: center;
        padding: 40px;
        color: #666;
        font-size: 16px;
    `;
        loadingDiv.textContent = '加载中...';
        contentContainer.appendChild(loadingDiv);

        // 组装容器
        contentContainer.appendChild(closeBtn); // 关闭按钮放在内容容器内部
        container.appendChild(contentContainer);
        document.body.appendChild(container);

        // 事件处理
        closeBtn.onclick = () => container.remove();
        container.onclick = (e) => {
            if (e.target === container) container.remove();
        };

        const escHandler = (e) => {
            if (e.key === 'Escape') container.remove();
        };
        document.addEventListener('keydown', escHandler);

        // 清理事件监听器
        container.addEventListener('remove', () => {
            document.removeEventListener('keydown', escHandler);
        });

        // 获取视频详情数据
        get_externaldetail(cid, type, vid).then(response => {
            if (response.code !== 0) {
                loadingDiv.innerHTML = `<div style="color: #dc3545; text-align: center;">${response.message}</div>`;
                return;
            }

            const data = response.data;

            // 清空加载状态
            contentContainer.innerHTML = '';

            // 重新添加关闭按钮
            contentContainer.appendChild(closeBtn);

            // 1. 封面 - 修复加载失败显示问题
            if (data.cover) {
                const coverContainer = document.createElement('div');
                coverContainer.style.cssText = `
                margin-bottom: 25px;
                border-radius: 8px;
                overflow: hidden;
                display: flex;
                justify-content: center;
                background: #e9ecef; /* 封面背景改为浅灰色 */
                min-height: 200px;
                position: relative; /* 为错误提示提供定位上下文 */
            `;

                const coverImg = document.createElement('img');
                coverImg.style.cssText = `
                max-width: 100%;
                max-height: 300px;
                object-fit: contain;
                display: block;
            `;
                coverImg.alt = '视频封面';
                coverImg.src = data.cover;

                const coverError = document.createElement('div');
                coverError.textContent = '封面加载失败';
                coverError.style.cssText = `
                color: #999;
                font-size: 14px;
                display: none; /* 默认隐藏,只有加载失败时才显示 */
                align-items: center;
                justify-content: center;
                height: 200px;
                position: absolute;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background: #e9ecef;
            `;

                coverImg.onerror = () => {
                    coverImg.style.display = 'none';
                    coverError.style.display = 'flex';
                };

                coverContainer.appendChild(coverImg);
                coverContainer.appendChild(coverError);
                contentContainer.appendChild(coverContainer);
            }

            // 创建信息项辅助函数 - 改为亮色主题样式
            const createInfoItem = (label, value, isLink = false) => {
                const item = document.createElement('div');
                item.style.cssText = `
                margin-bottom: 15px;
                padding-bottom: 15px;
                border-bottom: 1px solid rgba(0, 0, 0, 0.1); /* 边框颜色改为深色透明 */
            `;

                const labelSpan = document.createElement('div');
                labelSpan.textContent = label + ':';
                labelSpan.style.cssText = `
                font-size: 14px;
                color: #666; /* 标签颜色改为深灰色 */
                margin-bottom: 5px;
                font-weight: 500;
            `;

                const valueSpan = document.createElement('div');
                if (isLink) {
                    const link = document.createElement('a');
                    link.href = value;
                    link.textContent = value;
                    link.target = '_blank';
                    link.style.cssText = `
                    color: #007bff; /* 链接颜色改为蓝色 */
                    text-decoration: none;
                    word-break: break-all;
                `;
                    link.onmouseenter = () => link.style.textDecoration = 'underline';
                    link.onmouseleave = () => link.style.textDecoration = 'none';
                    valueSpan.appendChild(link);
                } else {
                    valueSpan.textContent = value || '无';
                    valueSpan.style.cssText = `
                    font-size: 16px;
                    word-break: break-all;
                    line-height: 1.5;
                    color: #333; /* 值颜色改为深色 */
                `;
                }

                item.appendChild(labelSpan);
                item.appendChild(valueSpan);
                return item;
            };

            // 2. ID信息(动态渲染所有ids)- 改为亮色主题
            if (data.ids && Object.keys(data.ids).length > 0) {
                const idsItem = document.createElement('div');
                idsItem.style.cssText = `
                margin-bottom: 15px;
                padding-bottom: 15px;
                border-bottom: 1px solid rgba(0, 0, 0, 0.1);
            `;

                const idsLabel = document.createElement('div');
                idsLabel.textContent = 'ID信息:';
                idsLabel.style.cssText = `
                font-size: 14px;
                color: #666;
                margin-bottom: 8px;
                font-weight: 500;
            `;

                const idsContainer = document.createElement('div');
                idsContainer.style.cssText = `
                display: flex;
                flex-wrap: wrap;
                gap: 10px;
            `;

                Object.entries(data.ids).forEach(([key, value]) => {
                    const idBadge = document.createElement('div');
                    idBadge.style.cssText = `
                    background: rgba(0, 123, 255, 0.1); /* 改为浅蓝色背景 */
                    padding: 5px 10px;
                    border-radius: 4px;
                    font-size: 14px;
                    display: flex;
                    flex-direction: column;
                `;

                    const keySpan = document.createElement('span');
                    keySpan.textContent = key;
                    keySpan.style.cssText = `
                    color: #007bff; /* 改为蓝色 */
                    font-weight: 500;
                    margin-bottom: 2px;
                `;

                    const valueSpan = document.createElement('span');
                    valueSpan.textContent = value;
                    valueSpan.style.cssText = `
                    color: #333; /* 改为深色 */
                `;

                    idBadge.appendChild(keySpan);
                    idBadge.appendChild(valueSpan);
                    idsContainer.appendChild(idBadge);
                });

                idsItem.appendChild(idsLabel);
                idsItem.appendChild(idsContainer);
                contentContainer.appendChild(idsItem);
            }

            // 3. 标题
            if (data.title) {
                contentContainer.appendChild(createInfoItem('标题', data.title));
            }

            // 4. 简介
            if (data.description) {
                const descItem = createInfoItem('简介', data.description);
                descItem.lastChild.style.whiteSpace = 'pre-wrap';
                contentContainer.appendChild(descItem);
            }

            // 5. 上传
            if (data.created) {
                contentContainer.appendChild(createInfoItem('上传', data.created));
            }

            // 6. 视频时长
            if (data.duration) {
                const durationStr = formatDuration(data.duration);
                contentContainer.appendChild(createInfoItem('时长', durationStr));
            }

            // 7. 用户名
            if (data.nickname) {
                contentContainer.appendChild(createInfoItem('用户', data.nickname));
            }

            // 8. 视频状态
            if (data.state) {
                const stateItem = createInfoItem('状态', data.state);
                const stateValue = stateItem.lastChild;

                // 根据状态添加颜色
                if (typeof data.state === 'string') {
                    const stateLower = data.state.toLowerCase();
                    if (stateLower.includes('正常') || stateLower.includes('成功')) {
                        stateValue.style.color = '#28a745'; /* 成功绿色 */
                    } else if (stateLower.includes('失败') || stateLower.includes('错误') || stateLower.includes('分级') || stateLower.includes('不合规') || stateLower.includes('下线')) {
                        stateValue.style.color = '#dc3545'; /* 错误红色 */
                    } else if (stateLower.includes('审核') || stateLower.includes('等待') || stateLower.includes('处理')) {
                        stateValue.style.color = '#ffc107'; /* 警告黄色 */
                    }
                }
                contentContainer.appendChild(stateItem);
            }

            // 9. 视频页地址
            if (data.link) {
                contentContainer.appendChild(createInfoItem('视频页面', data.link, true));
            }

            // 如果没有数据
            if (contentContainer.children.length === 1) { // 只有关闭按钮
                const emptyMsg = document.createElement('div');
                emptyMsg.textContent = '暂无视频详情信息';
                emptyMsg.style.cssText = `
                text-align: center;
                color: #666;
                padding: 40px;
                font-size: 16px;
            `;
                contentContainer.appendChild(emptyMsg);
            }

        }).catch(error => {
            loadingDiv.innerHTML = `<div style="color: #dc3545; text-align: center;">请求失败: ${error.message}</div>`;
        });



        return {
            close: () => container.remove()
        };
    };


    function create_externaldetail_item(cid, type, vid) {
        const cid_item = document.getElementById('cid_' + cid)
        if (cid_item) {
            const externaldetail_item = document.createElement('div');
            externaldetail_item.className = "solidbox pointer";
            externaldetail_item.onclick = () => show_externaldetail(cid, type, vid);
            externaldetail_item.textContent = "源详情";
            cid_item.parentNode.insertBefore(externaldetail_item, cid_item);
        }
    };
    const timer = setInterval(function() {
        if (window.view_all_data) {
            const json = window.view_all_data
            if (json.code === 0) {
                json.data.parts.forEach(part => {
                    create_externaldetail_item(part.cid, part.type, part.vid);
                })
            }
            clearInterval(timer);
        }
    }, 200);

}
// 添加历史记录详情
function add_history_detail() {

    const currentPath = window.location.pathname;
    const targetPages = ['/me/history'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));

    if (!isTargetPage) return;
    
    unsafeWindow.show_history_detail = function(video_json) {
        console.log('show_history_detail called', video_json); // 添加这行
        try {
            const decodedStr = decodeURIComponent(video_json);
            console.log('decodedStr', decodedStr); // 添加这行
            const videoData = JSON.parse(decodedStr);
            console.log('videoData', videoData); // 添加这行

            const aid = videoData.aid;
            const history_item = gEle('history_item_' + aid);
            const original_item = history_item.innerHTML;

            // 辅助函数:安全获取嵌套属性
            const getNested = (obj, path, defaultValue = '-') => {
                return path.split('.').reduce((o, key) => (o && o[key] !== undefined) ? o[key] : defaultValue, obj);
            };

            // 格式化时长 (秒 -> mm:ss)
            const formatDuration = (seconds) => {
                if (!seconds && seconds !== 0) return '-';
                const mins = Math.floor(seconds / 60);
                const secs = seconds % 60;
                return `${mins}:${secs.toString().padStart(2, '0')}`;
            };
            // 格式化数字 (千分位)
            const formatNumber = (num) => {
                if (num === undefined || num === null) return '-';
                return num.toLocaleString();
            };

            // 过滤html
            function escapeHtml(str) {
                if (!str) return '';
                return str.replace(/[&<>]/g, function(m) {
                    if (m === '&') return '&amp;';
                    if (m === '<') return '&lt;';
                    if (m === '>') return '&gt;';
                    return m;
                }).replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, function(c) {
                    return c;
                });
            }
            // 状态映射表
            const VIDEO_STATUS_MAP = {
                0: '开放浏览',
                1: '橙色通过',
                '-1': '待审',
                '-2': '被打回',
                '-3': '网警锁定',
                '-4': '被锁定',
                '-5': '管理员锁定',
                '-6': '修复待审',
                '-7': '暂缓审核',
                '-8': '补档待审',
                '-9': '等待转码',
                '-10': '延迟审核',
                '-11': '视频源待修',
                '-12': '转储失败',
                '-13': '允许评论待审',
                '-14': '临时回收站',
                '-15': '分发中',
                '-16': '转码失败',
                '-20': '创建未提交',
                '-30': '创建已提交',
                '-40': '定时发布',
                '-50': '仅UP主可见',
                '-100': '用户删除'
            };


            // 权限标识映射表
            const VIDEO_RIGHTS_MAP = {
                bp: '允许承包',
                elec: '支持充电',
                download: '允许下载',
                movie: '电影',
                pay: 'PGC付费',
                hd5: '高码率',
                no_reprint: '禁止转载',
                autoplay: '自动播放',
                ugc_pay: 'UGC付费',
                is_cooperation: '联合投稿',
                ugc_pay_preview: 'UGC付费预览',
                no_background: '无背景',
                clean_mode: '清洁模式',
                is_stein_gate: '互动视频',
                is_360: '全景视频',
                no_share: '禁止分享',
                arc_pay: '稿件付费',
                free_watch: '免费观看'
            };

            // 获取状态文本
            const getVideoStatusText = (type) => {
                return VIDEO_STATUS_MAP[type] || '未知状态';
            };
            // 获取标识文本
            const getVideoRightsText = (right) => {
                return VIDEO_RIGHTS_MAP[right] || '未知标识';
            };

            // 构建完整数据HTML
            const html = `
        <div class="video-detail-container" style="background: #EFEFF4; border-radius: 12px; overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; margin: 12px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.08);">
            <!-- 封面图区域 -->
            <div style="padding-left: var(--outer-padding, 50px); padding-right: var(--outer-padding, 50px);">
                <div style="display: flex; justify-content: center; align-items: center;">
                    <a href="/video/av${aid}/" style="display: block; text-decoration: none;">
                        <div style="position: relative; background: #1a1a2e; max-width: 100%; width: auto; height: auto;">
                            <img src="${videoData.pic || ''}" style="width: 100%; height: auto; object-fit: cover; display: block;" onerror="this.src='https://placehold.co/800x450/2c3e50/ffffff?text=No+Image'">
                            <div style="position: absolute; bottom: 12px; right: 12px; background: rgba(0,0,0,0.7); color: white; padding: 4px 8px; border-radius: 6px; font-size: 13px; font-weight: 500;">${formatDuration(videoData.duration)}</div>
                            ${videoData.progress !== undefined && videoData.progress > 0 ? `<div style="position: absolute; bottom: 0; left: 0; right: 0; height: 3px; background: rgba(255,255,255,0.3);"><div style="width: ${(videoData.progress / videoData.duration * 100)}%; height: 100%; background: #1E90FF;"></div></div>` : ''}
                        </div>
                    </a>
                </div>
            </div>
            
            <style>
                /* 电脑填充 */
                @media (min-width: 768px) {
                    :root {
                        --outer-padding: 250px;
                    }
                }
                
                /* 手机填充 */
                @media (max-width: 767px) {
                    :root {
                        --outer-padding: 20px;
                    }
                }
            </style>
            
            <!-- 内容区域 -->
            <div style="padding: 20px;">
                <!-- 标题行 -->
                <div style="margin-bottom: 16px;">
                    <h2 style="font-size: 20px; font-weight: 600; margin: 0 0 8px 0; line-height: 1.3; color: #18191c;">${escapeHtml(videoData.title || '无标题')}</h2>
                    <div style="display: flex; flex-wrap: wrap; gap: 12px; align-items: center; font-size: 13px; color: #6d757a;">
                        <span>${escapeHtml(videoData.tname || videoData.tnamev2 || '-')}</span>
                        <span>${formatTimestamp(videoData.pubdate)}</span>
                    </div>
                </div>
                
                <!-- UP主信息区域 - 头像、名字、UID合并显示 -->
                <a href="/space/${getNested(videoData, 'owner.mid', '')}/" style="text-decoration: none; display: inline-block; margin-bottom: 20px;">
                    <div style="display: flex; align-items: center; gap: 10px; background: rgba(30,144,255,0.08); padding: 8px 16px; border-radius: 40px; width: fit-content;">
                        <img src="${getNested(videoData, 'owner.face', '')}" style="width: 32px; height: 32px; border-radius: 50%; object-fit: cover;" onerror="this.src='https://placehold.co/32x32/cccccc/ffffff?text=?'">
                        <div>
                            <span style="font-weight: 600; color: #1E90FF;">${escapeHtml(getNested(videoData, 'owner.name', '-'))}</span>
                            <span style="font-size: 12px; color: #8e9aaf; margin-left: 8px;">UID: ${getNested(videoData, 'owner.mid', '-')}</span>
                        </div>
                    </div>
                </a>
                
                <!-- 统计数据卡片区 -->
                <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: 12px; background: #ffffff; border-radius: 16px; padding: 16px; margin-bottom: 20px;">
                    <div style="text-align: center;"><div style="font-size: 18px; font-weight: 700; color: #1E90FF;">${formatNumber(getNested(videoData, 'stat.view', 0))}</div><div style="font-size: 12px; color: #6c757d;">播放</div></div>
                    <div style="text-align: center;"><div style="font-size: 18px; font-weight: 700; color: #1E90FF;">${formatNumber(getNested(videoData, 'stat.danmaku', 0))}</div><div style="font-size: 12px; color: #6c757d;">弹幕</div></div>
                    <div style="text-align: center;"><div style="font-size: 18px; font-weight: 700; color: #1E90FF;">${formatNumber(getNested(videoData, 'stat.reply', 0))}</div><div style="font-size: 12px; color: #6c757d;">评论</div></div>
                    <div style="text-align: center;"><div style="font-size: 18px; font-weight: 700; color: #1E90FF;">${formatNumber(getNested(videoData, 'stat.like', 0))}</div><div style="font-size: 12px; color: #6c757d;">点赞</div></div>
                    <div style="text-align: center;"><div style="font-size: 18px; font-weight: 700; color: #1E90FF;">${formatNumber(getNested(videoData, 'stat.coin', 0))}</div><div style="font-size: 12px; color: #6c757d;">硬币</div></div>
                    <div style="text-align: center;"><div style="font-size: 18px; font-weight: 700; color: #1E90FF;">${formatNumber(getNested(videoData, 'stat.favorite', 0))}</div><div style="font-size: 12px; color: #6c757d;">收藏</div></div>
                </div>
                
                <!-- 完整详细信息 -->
                <div style="margin-bottom: 16px; background: #ffffff; border-radius: 12px; padding: 16px; font-size: 13px;">
                    <div style="font-weight: 600; margin-bottom: 12px; color: #1E90FF;">视频信息</div>
                    <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px;">
                        <div><strong>AV号:</strong> ${videoData.aid || '-'}</div>
                        <div><strong>BV号:</strong> ${videoData.bvid || '-'}</div>
                        <div><strong>CID:</strong> ${videoData.cid || '-'}</div>
                        <div><strong>视频分P:</strong> ${videoData.page ? `P${videoData.page.page} - ${escapeHtml(videoData.page.part || '-')}` : (videoData.videos > 1 ? `${videoData.videos}P` : '单P')}</div>
                        <div><strong>分区:</strong> ${videoData.tname} (${videoData.tid})</div>
                        <div><strong>发布时间:</strong> ${formatTimestamp(videoData.pubdate)}</div>
                        <div><strong>创建时间:</strong> ${formatTimestamp(videoData.ctime)}</div>
                        <div><strong>获取时间:</strong> ${formatTimestamp(videoData.view_at)}</div>
                        <div><strong>视频时长:</strong> ${formatDuration(videoData.duration)}</div>
                        <div><strong>视频尺寸:</strong> ${getNested(videoData, 'dimension.width', '-')}x${getNested(videoData, 'dimension.height', '-')}</div>
                        <div><strong>发布地点:</strong> ${videoData.pub_location || '-'}</div>
                        <div><strong>动态内容:</strong> ${videoData.dynamic ? escapeHtml(videoData.dynamic).substring(0, 80) + (videoData.dynamic.length > 80 ? '...' : '') : '-'}</div>
                        <div><strong>版权类型:</strong> ${videoData.copyright === 1 ? '原创' : (videoData.copyright === 2 ? '转载' : '-')}</div>
                        <div><strong>视频状态:</strong> ${getVideoStatusText(videoData.state)}[${videoData.state}]</div>
                    </div>
                    
                    <!-- rights 权限信息 -->
                    <div style="margin-top: 16px; border-top: 1px solid #e5e6e8; padding-top: 12px;">
                        <strong style="display: block; margin-bottom: 8px;">权限标识</strong>
                        <div style="display: flex; flex-wrap: wrap; gap: 8px;">
                            ${videoData.rights ? Object.entries(videoData.rights).map(([k, v]) => v ? `<span style="background: #EFEFF4; padding: 4px 10px; border-radius: 20px; font-size: 12px;">${getVideoRightsText(k)}</span>` : '').join('') : '-'}
                        </div>
                    </div>
                    
                    <!-- 视频描述 -->
                    <div style="margin-top: 16px; border-top: 1px solid #e5e6e8; padding-top: 12px;">
                        <strong>视频简介</strong>
                        <div style="margin-top: 8px; white-space: pre-wrap; line-height: 1.5; background: #EFEFF4; padding: 12px; border-radius: 10px; font-size: 13px;">${escapeHtml(videoData.desc || '无简介')}</div>
                    </div>
                </div>
                
                <!-- 快捷操作 -->
                <div style="display: flex; gap: 12px; justify-content: flex-end; border-top: 1px solid #e5e6e8; padding-top: 16px;">
                    <a href="/video/av${aid}/" style="background: #1E90FF; color: white; text-decoration: none; padding: 8px 20px; border-radius: 24px; font-size: 14px; font-weight: 500; display: inline-block;">本站页面</a>
                    <button id="restore-btn-${aid}" style="background: #1E90FF; border: none; padding: 8px 20px; border-radius: 24px; font-size: 14px; cursor: pointer; color: #ffffff;">收起扩展</button>
                </div>
            </div>
        </div>
    `;

            // 设置内容
            history_item.innerHTML = html;

            // 绑定恢复按钮事件
            const restoreBtn = document.getElementById(`restore-btn-${aid}`);
            if (restoreBtn) {
                restoreBtn.addEventListener('click', function(e) {
                    e.stopPropagation();
                    history_item.innerHTML = original_item;
                });
            }
        } catch (e) {
            console.error('Error:', e);
        }
    };
    
    // 覆盖原来的渲染逻辑
    printDynamic = function(json, page) {
        var dynamic_inter = [],
            time;
        scrollLoading = false;
        if (json.data) {
            //app feed
            json.data.forEach(function(i) {
                if (i.bangumi == undefined) {
                    var dis = (i.state != 0) ? ' disable' : '';
                    dynamic_inter.push('<hr><div id="history_item_' + i.aid + '"><table width="100%" border="0"><tr><td width="25%" align="center" class="title user"><a href="/space/' + i.owner.mid + '/" target="_blank"><img _src="' + i.owner.face + '" class="face_small" nolink src="' + blankImg + '"><b>' + i.owner.name + '</b></a></td><td width="75%" align="center" class="title"><b>' + i.title + '</b></td></tr></table><table width="100%" border="0"><tr><td rowspan="5" style="vertical-align:top"><img width="120" _src="' + i.pic + '@120w.jpg" original-src="' + i.pic + '" src="' + blankImg_8_5 + '"></td></tr><tr><td colspan="2" style="word-break:break-word" class="checktextheight pretext"><div>' + i.desc + '</div></td></tr><tr><td colspan="2" style="color:#666"><b> 观看于 <span class="hoveritem"><span datetime="' + i.view_at * 1e3 + '" class="timeago normal"></span><span class="hover">' + new Date(i.view_at * 1e3).toLocaleString(undefined, {
                        hour12: false
                    }) + '</span></span> </b>|<b> 播放:' + (i.stat.view || 0) + ' </b>|<b> 收藏:' + (i.stat.favorite || 0) + ' </b>|<b> 评论:' + (i.stat.reply || 0) + ' </b>|<b> 弹幕:' + (i.stat.danmaku || 0) + '</b>' + ((i.state == 0) ? '' : ('<br><br>该视频可能无法正常获取,状态码:[' + i.state + ']' + (videoStatus[i.state] || ''))) + '</td></tr><tr><td width="33%" align="center" class="button' + dis + '"><a href="/video/av' + i.aid + '/"><b>视频详情</b></a></td><td width="33%" align="center" class="button' + dis + '"><a href="https://www.bilibili.com/video/av' + i.aid + '/" target="_blank"><b>主站地址</b></a></td><td width="33%" align="center" class="button" style="color:#ffffff ;"><a onclick="show_history_detail(\'' + encodeURIComponent(JSON.stringify(i)).replace(/'/g, "\\'") + '\')" target="_blank"><b>扩展信息</b></a></td></tr></table></div>');
                } else {
                    dynamic_inter.push('<hr><div id="history_item_' + i.aid + '"><table width="100%" border="0"><tr><td width="25%" align="center" class="title bangumi"><b>哔哩哔哩番剧</b></td><td width="75%" align="center" class="title bangumi"><b><a href="/bangumi/i/' + i.bangumi.season.season_id + '" target="_blank">' + i.title + '</a></b></td></tr></table><table width="100%" border="0"><tr><td rowspan="5" style="vertical-align:top"><img width="120" _src="' + i.pic + '@120w.jpg" original-src="' + i.pic + '" src="' + blankImg_8_5 + '"></td></tr><tr><td colspan="2" style="word-break:break-word" class="checktextheight pretext">' + i.desc + '\n' + i.bangumi.long_title + '</td></tr><tr><td colspan="2" style="color:#666"><b> 观看于 <span class="hoveritem"><span datetime="' + i.view_at * 1e3 + '" class="timeago normal"></span><span class="hover">' + new Date(i.view_at * 1e3).toLocaleString(undefined, {
                        hour12: false
                    }) + '</span></span> </b>|<b> 播放:' + (i.stat.view || 0) + ' </b>|<b> 弹幕:' + (i.stat.danmaku || 0) + '</b></td></tr><tr><td width="50%" align="center" class="button bangumi"><a href="/video/av' + i.aid + '/"><b>视频详情</b></a></td><td width="50%" align="center" class="button bangumi"><a href="https://bangumi.bilibili.com/anime/' + i.bangumi.season.season_id + '" target="_blank"><b>主站地址</b></a></td></tr></table></div>');
                }
            });

        }
        if (page == 1) {
            gEle('list').innerHTML = '';
        }
        gEle('list').appendChild(_('div', {
            id: 'dyn_page_' + page
        })).innerHTML = dynamic_inter.join('');
        timeagoRun();
        if (dynamic_inter.length != 0) {
            gEle('footer').innerHTML = '<div style="display:inline-block;border-radius:5px;border:1px solid #AAA;background:#DDD;padding:8px 20px;cursor:pointer" onclick="loadPage(' + (page + 1) + ')">加载更多</div>';
        } else {
            scrollLoading = true;
            gEle('footer').textContent = '没有更多啦~'
        }
        img_lazyload();
        textAutohide();
    }
    

}

function add_history_custome() {

    const currentPath = window.location.pathname;
    const targetPages = ['/me/history'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));

    if (!isTargetPage) return;

    function create_input_container() {
        const contentContainer = document.getElementById('content');
        if (!contentContainer) {
            return;
        }

        // 获取id为list的容器
        const listContainer = document.getElementById('list');
        if (!listContainer) {
            return;
        }

        // 检查是否已经添加过该UI,避免重复添加
        if (document.getElementById('av-input-container')) {
            return;
        }

        // 创建容器div,用于包裹输入框和按钮
        const inputContainer = document.createElement('div');
        inputContainer.id = 'av-input-container';
        inputContainer.style.marginBottom = '10px';
        inputContainer.style.padding = '8px';
        inputContainer.style.backgroundColor = '#EFEFF4';
        inputContainer.style.border = '1px solid #ddd';
        inputContainer.style.borderRadius = '4px';
        inputContainer.style.display = 'flex';
        inputContainer.style.alignItems = 'center';
        inputContainer.style.gap = '10px';

        // 创建输入框
        const inputBox = document.createElement('input');
        inputBox.type = 'text';
        inputBox.id = 'av-input';
        inputBox.placeholder = '请输入AV号或BV号';
        inputBox.style.padding = '6px 10px';
        inputBox.style.border = '1px solid #ccc';
        inputBox.style.borderRadius = '4px';
        inputBox.style.flex = '1';
        inputBox.style.fontSize = '14px';

        // 创建按钮
        const submitBtn = document.createElement('button');
        submitBtn.id = 'av-submit-btn';
        submitBtn.textContent = '新增';
        submitBtn.style.padding = '6px 12px';
        submitBtn.style.backgroundColor = '#1E90FF';
        submitBtn.style.color = 'white';
        submitBtn.style.border = 'none';
        submitBtn.style.borderRadius = '4px';
        submitBtn.style.cursor = 'pointer';
        submitBtn.style.fontSize = '14px';

        // 点击事件处理函数
        function handleClick() {
            unsafeWindow.createUpdateNotice("正在添加至历史记录……", "00F");
            let input = inputBox.value.trim();

            // 验证是否为空
            if (input === '') {
                unsafeWindow.createUpdateNotice('添加错误:输入为空', 'F00');
                return;
            }

            let aid = null;

            // 纯数字av号
            if (/^\d+$/.test(input)) {
                aid = input;
            }
            // 标准av号
            else if (/^av\d+$/i.test(input)) {
                aid = input.substring(2);
            }
            // 标准BV号
            else if (/^BV[A-Za-z0-9]+$/.test(input)) {
                try {
                    aid = bv2av(input);
                    if (isNaN(aid) || aid <= 0) {
                        throw new Error('Invalid BV number');
                    }
                    
                } catch (e) {
                    unsafeWindow.createUpdateNotice('转换失败:请检查BV号是否正确', 'F00');
                    return;
                }
            }
            // url
            else {
                // 匹配视频URL和短链接
                let urlMatch = input.match(/(?:bilibili\.com\/video\/|b23\.tv\/)(av\d+|BV[A-Za-z0-9]+)/i);
                if (urlMatch) {
                    let id = urlMatch[1];
                    if (id.toLowerCase().startsWith('av')) {
                        aid = id.substring(2);
                    } else if (id.toLowerCase().startsWith('bv')) {
                        try {
                            aid = bv2av(id);
                            if (isNaN(aid) || aid <= 0) {
                                throw new Error('Invalid BV number');
                            }
                        } catch (e) {
                            unsafeWindow.createUpdateNotice('转换失败:请检查BV号是否正确', 'F00');
                            return;
                        }
                    }
                } else {
                    unsafeWindow.createUpdateNotice('添加错误:请输入正确的视频ID或链接', 'F00');
                    return;
                }
            }

            // 调用添加历史记录 API
            getjson("/api/history_add?aid=" + aid, function(json) {
                if (json.code == 0) {
                    unsafeWindow.createUpdateNotice('添加成功', '0C0');
                    loadPage(1);
                } else {
                    unsafeWindow.createUpdateNotice('添加失败:未知错误', 'F00');
                }
            });

            // 清空输入框
            inputBox.value = '';
        }

        // 绑定点击事件
        submitBtn.addEventListener('click', handleClick);

        // 可选:按回车键也能触发
        inputBox.addEventListener('keypress', function(event) {
            if (event.key === 'Enter') {
                event.preventDefault();
                handleClick();
            }
        });

        // 将输入框和按钮添加到容器
        inputContainer.appendChild(inputBox);
        inputContainer.appendChild(submitBtn);

        // 在list容器上方插入新创建的元素
        contentContainer.insertBefore(inputContainer, listContainer);

    }
    create_input_container()
}
// 修复随机视频获取
function fix_index_random_video() {
    // 只在主页执行
    const currentPath = window.location.pathname;
    const isTargetPage = currentPath === "/";
    const hasQuery = window.location.search !== "";


    if (!isTargetPage || hasQuery) return;

    /* 修复随机aid视频*/

    // 原函数为random()
    function random_fix(json) {
        document.getElementById('random-id')
            .parentNode.href = '/video/av' + json.aid + '/';
        document.getElementById('random-pic')
            .setAttribute('_src', json.pic.replace(/https?:/, 'https:') + '@120w.jpg');
        document.getElementById('random-id')
            .textContent = 'AV' + json.aid;
        document.getElementById('random-title')
            .textContent = json.title;
        document.getElementById('random-up')
            .parentNode.href = '/space/' + json.mid + '/';
        document.getElementById('random-up')
            .textContent = 'UP: ' + json.author;
        img_lazyload();
    }
    // 用bp的view接口随机获取一个av号一千万以内的稿件
    async function get_random_aid() {
        const aid = Math.floor(Math.random() * 10000000) + 1;
        await getjson('/api/view?id=' + aid, async json => {
            if (json.code === undefined) { // 没有code则代表获取的是有效稿件数据
                random_fix(json);
            } else {
                await sleep(1); // 简单缓解被拉黑导致-503错误
                get_random_aid();
            }
        });
    }
    // 替换刷新按钮点击事件
    function replace_reload_onlick() {
        // 获取borderbox对应的div标签
        const box = document.querySelector('div.borderbox');
        if (box) {
            // 找出div中的onclick元素
            const hasOnclick = Array.from(
                box.querySelectorAll('[onclick]')
            );
            // 重新给点击事件赋值
            hasOnclick.forEach(el => {
                el.onclick = get_random_aid;
            });
        }
    }

    /* 配置随机cid功能 */


    function create_random_cid_item() {
        const content = document.getElementById("content");
        // 创建外层容器
        const containerDiv = document.createElement('div');
        containerDiv.className = 'borderbox';
        containerDiv.style.cssText = 'margin:5px 0;width:305px;position:relative';

        // 创建图片元素
        const img = document.createElement('img');
        img.id = 'random-cid-pic';
        img.style.cssText = 'width:120px;display:inline-block';
        img.onerror = function() {
            this.src = blankImg;
        };

        // 创建文本信息容器
        const textSpan = document.createElement('span');
        textSpan.style.cssText = 'display:inline-block;width:185px;vertical-align:top;white-space:pre;overflow:hidden;text-overflow:ellipsis;line-height:1.5em';

        // 创建第一个链接(视频信息)
        const videoLink = document.createElement('a');
        videoLink.target = '_blank';

        // 创建视频ID显示
        const idSpan = document.createElement('span');
        idSpan.id = 'random-cid-id';
        idSpan.style.color = '#666';
        idSpan.textContent = 'AVxxxxx-CIDxxxxx';

        // 创建视频标题显示
        const titleSpan = document.createElement('span');
        titleSpan.id = 'random-cid-title';
        titleSpan.textContent = '加载随机CID中';

        // 创建换行
        const br1 = document.createElement('br');

        // 将ID和标题添加到第一个链接中
        videoLink.appendChild(idSpan);
        videoLink.appendChild(br1);
        videoLink.appendChild(titleSpan);

        // 创建第二个链接(UP主信息)
        const upLink = document.createElement('a');
        upLink.target = '_blank';

        // 创建UP主显示
        const upSpan = document.createElement('span');
        upSpan.id = 'random-cid-up';
        upSpan.style.color = '#999';
        upSpan.textContent = 'UP: xxxx';

        // 将UP信息添加到第二个链接中
        upLink.appendChild(upSpan);

        // 创建换行
        const br2 = document.createElement('br');

        // 将两个链接添加到文本容器中
        textSpan.appendChild(videoLink);
        textSpan.appendChild(br2);
        textSpan.appendChild(upLink);

        // 创建刷新按钮
        const reloadSpan = document.createElement('span');
        reloadSpan.style.cssText = 'position:absolute;padding:5px;right:0;bottom:0;cursor:pointer';
        reloadSpan.textContent = 'Reload';
        reloadSpan.onclick = function() {
            get_random_cid();
        };

        // 将元素组装到容器中
        containerDiv.appendChild(img);
        containerDiv.appendChild(textSpan);
        containerDiv.appendChild(reloadSpan);

        const normal_container = document.getElementById("normal_container");
        if (normal_container) {
            content.insertBefore(containerDiv, normal_container);
        } else {
            content.appendChild(containerDiv);
        }
    }

    function random_cid(json) {
        const data = json.data
        document.getElementById('random-cid-id')
            .parentNode.href = '/all/video/av' + data.aid + '/';
        document.getElementById('random-cid-pic')
            .setAttribute('_src', data.cover.replace(/https?:/, 'https:') + '@120w.jpg');
        document.getElementById('random-cid-id')
            .textContent = 'AV' + data.aid + '-' + 'CID' + data.cid;
        if (data.title == "") {
            document.getElementById('random-cid-title')
                .textContent = data.subtitle;
        } else {
            document.getElementById('random-cid-title')
                .textContent = data.title;
        }

        document.getElementById('random-cid-up')
            .parentNode.href = '/space/' + data.mid + '/';
        document.getElementById('random-cid-up')
            .textContent = 'UP: ' + data.author;
        img_lazyload();
    }
    async function get_random_cid() {
        // 4000000以内cid大多为非直传源
        const cid = Math.floor(Math.random() * 4000000) + 1;
        await getjson('/api/cidinfo?cid=' + cid, async json => {
            if (json.code === 0) { // code为0代表有效数据
                random_cid(json);
            } else {
                await sleep(1); // 简单缓解被拉黑导致-503错误
                get_random_cid();
            }
        });
    }

    // 执行
    replace_reload_onlick();
    get_random_aid();

    if (localStorage.random_cid == 'on') { // 启用'额外功能' => '随机CID'
        create_random_cid_item();
        get_random_cid();
    }
}

// 修复用户信息获取
function fix_space_userinfo() {
    // 只在space页面执行
    const currentPath = window.location.pathname;
    const targetPages = ['/space/'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));

    if (!isTargetPage) return;

    function userinfo_fix(json) {
        if (json.code == 0) {
            var card = json.data.card;
            document.getElementById('userinfo').innerHTML = '<img style="width:128px" _src="' + card.face + '"><br/><br/><b style="word-break:break-all">' + card.sign + '</b><br/><br/>关注:' + (card.attention | 0) + '<br/>粉丝:' + card.fans + '<br/>投稿数:<span id="article">' + json.data.archive_count + '</span><br><a href="http://space.bilibili.com/' + card.mid + '" target="_blank"><div class="solidbox">UP主空间</div></a>';
            document.getElementById('header').childNodes[0].innerHTML = card.name;
            titletext = card.name + ' - UP主 - BiliPlus - ( ゜- ゜)つロ 乾杯~';
            title(0);
            imgClick();
            img_lazyload();
        } else {
            document.getElementById('userinfo').innerHTML = '<div class="borderbox pink">修复用户信息失败:[' + json.code + '] ' + json.message + '</div>';
        }
    }

    function get_userinfo_data() {
        GM_getjson('https://api.bilibili.com/x/web-interface/card?mid=' + attention.mid, function(json) {
            if (json.code === 0) {
                userinfo_fix(json);
            }
        });
    }
    const timer = setInterval(function() {
        const targetElement = document.getElementById("userinfo");
        if (targetElement && targetElement.innerHTML.includes("获取用户信息失败")) {

            get_userinfo_data();
            clearInterval(timer);
        }
    }, 200);
}

function fix_space_user_video() {
    // 只在space页面执行
    const currentPath = window.location.pathname;
    const targetPages = ['/space/'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));

    if (!isTargetPage) return;



    function printPage_fix(json, page) {

        isLoading = false;
        window.page = page;
        var str = '',
            i = 0,
            current, count = document.getElementById('article'),
            pagetmp = page - 2,
            mid = attention.mid;
        for (; i < json.data.archives.length; i++) {

            current = json.data.archives[i];

            str += '<hr><table width="100%" border="0"><tr><td width="15%" align="center" class="title">' + "视频" + '</td><td width="85%" align="center" class="title"><b>' + current.title + '</b></td></tr></table><table width="100%" border="0"><tr><td rowspan="5" style="vertical-align:top"><img width="120" _src="' + current.pic + '@120w.jpg" original-src="' + current.pic + '" style="float:left"/></td></tr><tr><td colspan="2" style="word-break:break-all" class="checktextheight pretext"><div>' + current.bvid + '</div></td></tr><tr><td colspan="2" style="color:#666"><b> 发布于 <span datetime="' + new Date(Number(current.pubdate) * 1000).toISOString() + ' +0800' + '" class="timeago normal"></span><span class="hover">' + new Date(Number(current.pubdate) * 1000).toLocaleString(undefined, {
                hour12: false
            }) + '</span></span></b>|<b> 播放:' + current.stat.view + ' </b>|<b> 收藏:' + current.stat.favorite + ' </b>|<b> 评论:' + current.stat.reply + ' </b>|<b> 弹幕:' + current.stat.danmaku + ' </b>|<b> 硬币:' + current.stat.coin + '</b></td></tr><tr><td width="50%" align="center" class="button"><a href="/video/av' + current.aid + '/"><b>视频详情</b></a></td><td width="50%" align="center" class="button"><a href="http://www.bilibili.com/video/av' + current.aid + '/" target="_blank"><b>前往主站播放</b></a></td></tr></table>';

        }
        article = json.data.page.count;
        if (count != null)
            count.innerHTML = article;
        document.getElementById('list').innerHTML = str;
        str = ''
        pages = Math.floor(json.data.page.count / 20) + 1
        if (pages == 0)
            str = '<div class="solidbox"><b>0/0</b></div>';
        else {
            if (page > 1)
                str += '<a data-page="1"><div id="first" class="solidbox"><b>&lt;&lt;</b></div></a><a data-page="' + (page - 1) + '"><div id="previous" class="solidbox"><b>&lt;</b></div></a> '
            for (i = 0; i < 5; i++, pagetmp++) {
                if (pagetmp == page)
                    str += '<div class="solidbox"><b>' + pagetmp + '/' + pages + '</b></div> ';
                else if ((pagetmp > 0) && (pagetmp < ((pages | 0) + 1)))
                    str += '<a data-page="' + pagetmp + '"><div class="solidbox">' + pagetmp + '</div></a> ';
            }
            if (page < pages)
                str += '<a data-page="' + (page + 1) + '"><div id="next" class="solidbox"><b>&gt;</b></div></a><a data-page="' + pages + '"><div id="last" class="solidbox"><b>&gt;&gt;</b></div></a>';
        }
        document.getElementById('footer').innerHTML = str;
        Array.from(document.getElementById('footer').querySelectorAll('a[data-page]')).find(function(i) {
            var page = i.getAttribute('data-page');
            i.setAttribute('onclick', 'loadPage_fix(' + page + ');return false');
            i.href = '/space/' + mid + '/' + page;
            i.removeAttribute('data-page');
        })
        imgClick();
        img_lazyload();
        appLinkClick();
        textAutohide();
        timeagoRun();
    }

    function loadPage_fix(page) {
        if (isLoading) return;
        if (page != window.page)
            history.pushState({}, page, '/space/' + attention.mid + '/' + page);
        isLoading = true;
        GM_getjson('https://api.bilibili.com/x/space/arc/list?ps=20&mid=' + attention.mid + '&pn=' + page, printPage_fix, page)
        document.getElementById('list').innerHTML = '<div class="borderbox pink">修复加载中...</div>';
        GA_Log(location.href, '');
    }
    loadPage_fix(page);
}

function fix_video_user_video() {

    const currentPath = window.location.pathname;
    const targetPages = ['/video/'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));

    if (!isTargetPage) return;

    // 点击视频卡片跳转
    var loadVideoByAid = function(e) {
        clearInterval(timer);
        e.preventDefault();
        ajaxLoad(this.getAttribute("data-aid"));
    };

    // 点击分页按钮加载对应页
    var loadUpVideoPage = function(e) {
        // 清理timer
        clearInterval(timer);
        e.preventDefault();
        load_fix(0 | this.getAttribute("data-page"));
    };

    // 用正则获取mid
    function get_mid() {
        // 获取包含UID的链接元素,优先从 #content 容器内查找
        const contentContainer = document.querySelector('#content');
        let link = null;

        if (contentContainer) {
            link = contentContainer.querySelector('a[href*="/space/"]');
        }



        if (link) {
            const href = link.getAttribute('href');
            const midMatch = href.match(/\/space\/(\d+)/);
            if (midMatch && midMatch[1]) {
                const mid = midMatch[1];
                console.log(mid);
                return mid;
            }
        }

        return null;
    }

    function printPage_fix(json, page, mid) {
        // 重点标记,此处变量名混淆由Ai对抗


        var contentElement = document.getElementById("uplist_content"),
            startPage = page - 2;

        if (null != contentElement) {
            // 清空现有内容

            Array.from(contentElement.children).forEach(function(child) {
                child.remove()
            });

            if (!json.data.archives) {
                return
            }

            // 添加视频列表项

            json.data.archives.forEach(function(video) {

                contentElement.appendChild(_("a", {
                    href: "/video/av" + video.aid + "/",
                    "data-aid": video.aid,
                    event: {
                        click: loadVideoByAid
                    }
                }, [
                    _("div", {
                        className: "borderbox",
                        style: {
                            width: "calc(100% - 16px)"
                        }
                    }, [
                        _("table", {}, [
                            _("tbody", {}, [
                                _("tr", {}, [
                                    _("td", {}, [
                                        _("img", {
                                            src: blankImg,
                                            _src: video.pic,
                                            style: {
                                                width: "120px"
                                            }
                                        })
                                    ]),
                                    _("td", {}, [
                                        _("div", {}, [
                                            _("text", video.title)
                                        ])
                                    ])
                                ])
                            ])
                        ])
                    ])
                ]))
            });

            var pages = Math.floor(json.data.page.count / 20) + 1

            // 创建分页元素
            var paginationElements = [];

            // 添加第一页链接(<<)
            if (page > 1) {
                paginationElements.push(_("a", {
                    href: "/space/" + mid + "/",
                    "data-page": 1,
                    event: {
                        click: loadUpVideoPage
                    }
                }, [
                    _("div", {
                        className: "solidbox"
                    }, [
                        _("text", "<<")
                    ])
                ]));
            }

            // 添加页码链接(显示5个页码)
            for (var i = 0; i < 5; i++, startPage++) {
                if (page == startPage) {
                    // 当前页显示为"页码/总页数"
                    paginationElements.push(_("div", {
                        className: "solidbox"
                    }, [
                        _("text", startPage + "/" + pages)
                    ]));
                } else if (startPage > 0 && startPage < (0 | pages) + 1) {
                    // 其他有效页码
                    paginationElements.push(_("a", {
                        href: "/space/" + mid + "/" + startPage,
                        "data-page": startPage,
                        event: {
                            click: loadUpVideoPage
                        }
                    }, [
                        _("div", {
                            className: "solidbox"
                        }, [
                            _("text", startPage)
                        ])
                    ]));
                }
            }

            // 添加最后一页链接(>>)
            if (page < (0 | pages)) {
                paginationElements.push(_("a", {
                    href: "/space/" + mid + "/" + pages,
                    "data-page": pages,
                    event: {
                        click: loadUpVideoPage
                    }
                }, [
                    _("div", {
                        className: "solidbox"
                    }, [
                        _("text", ">>")
                    ])
                ]));
            }

            // 将分页添加到内容容器
            contentElement.appendChild(_("div", {
                className: "footer_video"
            }, paginationElements));

            // 停止dots计时器并启动图片懒加载
            dots.stopTimer();
            img_lazyload();
        }
    };

    function load_fix(page) {
        const targetElement = document.getElementById("uplist_content");
        if (targetElement == null) {
            return
        }
        const mid = get_mid()
        document.getElementById("uplist_content").innerHTML = '<div id="dots_container" style="overflow:hidden;width:100%;height:30px"></div>', dots.config.height = "30px", dots.config.width = document.getElementById(dots.config.id).offsetWidth + "px", dots.runTimer(), GM_getjson('https://api.bilibili.com/x/space/arc/list?ps=20&mid=' + mid + '&pn=' + page, printPage_fix, page)
    };


    // 重点标记,这里分页还有bug,循环检测可能会导致新页面被第一页覆盖load_fix(1);
    // 目前应对策略是用户点击分页或视频卡片后清理timer(代表页面修复成功而不是被原页面覆盖)

    // 2026.03.21 才发现这里一直误用了attention.mid,attention对象根本没在视频页面里初始化,关键是我的浏览器竟然成功获取到mid了,这怎么搞的,赛博闹鬼?

    const timer = setInterval(function() {


        const targetElement = document.getElementById("uplist_content");

        // 条件:页面已创建uplist_content并且(uplist_content含有视频卡片 或 uplist_content含有分页容器)
        // 分页容器检查防止up主无投稿
        const hasVideoCard = targetElement && (targetElement.querySelector("a[data-aid]") || targetElement.querySelector(".footer_video"));
        // console.log(targetElement)
        if (!hasVideoCard) {

            load_fix(1);


        }
    }, 200);




}
// 修复html5播放器
// 重点标记,此函数需完善
function fix_video_h5play() {
    // 强制加载在线播放按钮
    const enablePlayback = localStorage.getItem('enablePlayback');
    if (enablePlayback !== 'on') {
        localStorage.setItem('enablePlayback', 'on');
    }

    const currentPath = window.location.pathname;
    const targetPages = ['/video/', '/all/video/'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));
    if (!isTargetPage) return;

    /* 配置h5视频播放器 */
    // 尝试基于原播放器修复,结果失败

    // 添加至历史记录
    var history_add = function(cid) {
        if (localStorage.ban_history !== "on") {
            getjson("/api/history_add?aid=" + av + "&cid=" + cid, function() {});
        }
    };

    h5jump = function(partIndex) {
        var videoType = items[partIndex - 1][0],
            partTitle = items[partIndex - 1][1],
            cid = items[partIndex - 1][2],
            videoId = items[partIndex - 1][3]

        // 验证视频类型
        if ("none" == videoType || ["vupload", "movie", "bangumi"].indexOf(videoType) == -1 && "" == videoId) {
            return false;
        }
        // 处理视频类型转换
        "letv" == videoType && (videoType = "vupload", videoId = "vupload_" + cid);
        "vupload" == videoType && "" == videoId && (videoId = "vupload_" + cid);
        history_add(cid); // 添加到历史记录

        // 如果播放器已存在,先移除并清理资源
        const existingPlayer = document.getElementById('floatingVideoPlayer');
        if (existingPlayer) {
            // 清理播放器资源
            cleanupVideoPlayer();
            existingPlayer.remove();
        }

        // 创建新的播放器容器
        let containerElement = document.body.appendChild(document.createElement("div"));
        containerElement.outerHTML = `
        <div id="floatingVideoPlayer" style="
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 900px;
            max-width: 90vw;
            height: 550px;
            max-height: 80vh;
            background-color: #EFEFF4;
            border-radius: 12px;
            box-shadow: 0 10px 50px rgba(0,0,0,0.5);
            z-index: 99999;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
        ">
            <!-- 播放器头部 -->
            <div style="
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 15px 20px;
                background-color: #EFEFF4;
                border-bottom: 1px solid rgba(255,255,255,0.1);
            ">
                <!-- 标题 -->
                <div style="color: black; font-size: 16px; font-weight: bold; max-width: 80%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
                ${partTitle} VID:${videoId}
                </div>

                <!-- 关闭按钮 -->
                <div id="closeVideoPlayer" style="
                    width: 36px;
                    height: 36px;
                    background-color: rgba(0,0,0,0.1);
                    border-radius: 50%;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    cursor: pointer;
                    transition: all 0.2s;
                    flex-shrink: 0;
                " onmouseover="this.style.backgroundColor='rgba(255,255,255,0.2)';this.style.transform='rotate(90deg)';"
                onmouseout="this.style.backgroundColor='rgba(255,255,255,0.1)';this.style.transform='rotate(0deg)';">
                    <span style="color: white; font-size: 24px; font-weight: bold; line-height: 1;">×</span>
                </div>
            </div>

            <!-- 视频容器 -->
            <div id="videoContainer" style="
                flex: 1;
                display: flex;
                align-items: center;
                justify-content: center;
                background-color: #000;
                position: relative;
                overflow: hidden;
            ">
                <div id="videoLoading" style="
                    color: white;
                    font-size: 16px;
                    text-align: center;
                ">
                    视频加载中...
                </div>
            </div>

            <!-- 新增:视频源选择菜单 -->
            <div id="videoSourceMenu" style="
                background-color: #2c2c2e;
                color: white;
                max-height: 200px;
                overflow: hidden;
                transition: max-height 0.3s ease;
                border-top: 1px solid rgba(255,255,255,0.1);
            ">
                <!-- 折叠菜单头部 -->
                <div id="videoSourceHeader" style="
                    padding: 10px 20px;
                    background-color: #3a3a3c;
                    cursor: pointer;
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    font-size: 14px;
                    font-weight: bold;
                ">
                    <span>视频源切换</span>
                    <span id="menuArrow" style="transition: transform 0.3s;">▼</span>
                </div>

                <!-- 视频源列表 -->
                <div id="videoSourceList" style="
                    max-height: 150px;
                    overflow-y: auto;
                    padding: 0;
                ">
                    <!-- 视频源项将通过JavaScript动态添加 -->
                </div>
            </div>
        </div>
    `;

        // 添加事件监听器
        const playerElement = document.getElementById('floatingVideoPlayer');
        const closeBtn = document.getElementById('closeVideoPlayer');

        // 关闭按钮事件 - 彻底清理资源
        closeBtn.addEventListener('click', function() {
            cleanupVideoPlayer(); // 清理所有播放资源
            playerElement.remove(); // 移除播放器
            document.removeEventListener('keydown', closeOnEsc); // 移除ESC事件监听
        });

        // 添加ESC键关闭功能
        const closeOnEsc = function(e) {
            if (e.key === 'Escape') {
                closeBtn.click();
            }
        };
        document.addEventListener('keydown', closeOnEsc);

        // 获取视频URL并创建播放器
        get_video_url(cid, videoType, videoId).then(videoUrls => {
            if (!videoUrls || videoUrls.length === 0) {
                showError('未获取到视频源');
                return;
            }

            // 将视频源存储到全局变量
            window.videoUrls = videoUrls;

            // 初始化视频源菜单
            initVideoSourceMenu(videoUrls);

            // 按flv → hlv → mp4的顺序尝试视频源
            tryVideoSourcesInOrder(videoUrls);
        }).catch(error => {
            showError('获取视频源失败');
        });

        // 初始化视频源菜单的函数
        function initVideoSourceMenu(videoUrls) {
            const videoSourceHeader = document.getElementById('videoSourceHeader');
            const videoSourceList = document.getElementById('videoSourceList');
            const menuArrow = document.getElementById('menuArrow');

            // 清空列表
            videoSourceList.innerHTML = '';

            // 添加视频源项
            videoUrls.forEach((url, index) => {
                const sourceItem = document.createElement('div');
                sourceItem.style.cssText = `
                    padding: 10px 20px;
                    border-bottom: 1px solid rgba(255,255,255,0.05);
                    cursor: pointer;
                    font-size: 12px;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                    transition: background-color 0.2s;
                `;

                // 显示简化的URL
                const urlObj = new URL(url);
                const displayText = `源${index + 1}: ${urlObj.hostname}${urlObj.pathname.substring(urlObj.pathname.lastIndexOf('.'))}`;
                sourceItem.textContent = displayText;
                sourceItem.title = url; // 鼠标悬停显示完整URL

                // 点击切换视频源
                sourceItem.addEventListener('click', function() {
                    // 移除其他项的选中状态
                    document.querySelectorAll('#videoSourceList > div').forEach(item => {
                        item.style.backgroundColor = '';
                        item.style.color = 'white';
                    });

                    // 设置当前项为选中状态
                    this.style.backgroundColor = 'rgba(0, 122, 255, 0.3)';
                    this.style.color = '#007AFF';

                    // 切换到选中的视频源
                    switchVideoSource(url);
                });

                videoSourceList.appendChild(sourceItem);
            });

            // 折叠/展开功能
            let isMenuExpanded = false;
            const videoSourceMenu = document.getElementById('videoSourceMenu');

            videoSourceHeader.addEventListener('click', function() {
                isMenuExpanded = !isMenuExpanded;

                if (isMenuExpanded) {
                    videoSourceMenu.style.maxHeight = '200px';
                    menuArrow.style.transform = 'rotate(180deg)';
                } else {
                    videoSourceMenu.style.maxHeight = '40px'; // 只显示标题的高度
                    menuArrow.style.transform = 'rotate(0deg)';
                }
            });

            // 默认折叠
            videoSourceMenu.style.maxHeight = '40px';
        }

        // 清理所有视频播放资源的函数
        function cleanupVideoPlayer() {
            // 停止并销毁FLV播放器
            if (window.flvPlayer) {
                try {
                    window.flvPlayer.pause();
                    if (window.flvPlayer.unload) window.flvPlayer.unload();
                    if (window.flvPlayer.detachMediaElement) window.flvPlayer.detachMediaElement();
                    window.flvPlayer.destroy();
                } catch (e) {
                    console.error('销毁FLV播放器失败:', e);
                }
                window.flvPlayer = null;
            }

            // 停止并移除所有video元素
            const videos = document.getElementsByTagName('video');
            for (let video of videos) {
                try {
                    video.pause();
                    video.src = ''; // 清空src
                    video.load(); // 重新加载以释放资源
                    video.removeAttribute('src');
                } catch (e) {
                    console.error('停止视频失败:', e);
                }
            }

            // 清空视频容器
            const videoContainer = document.getElementById('videoContainer');
            if (videoContainer) {
                videoContainer.innerHTML = '';
            }
        }

        // 切换视频源的函数
        function switchVideoSource(videoUrl) {
            // 清理当前播放资源
            cleanupVideoPlayer();

            // 显示加载提示
            const videoContainer = document.getElementById('videoContainer');
            if (videoContainer) {
                videoContainer.innerHTML = `
                    <div id="videoLoading" style="
                        color: white;
                        font-size: 16px;
                        text-align: center;
                    ">
                        正在切换视频源...
                    </div>
                `;
            }

            // 延迟一小段时间确保资源释放完毕,然后创建新播放器
            setTimeout(() => {
                createVideoPlayer(videoUrl);
            }, 100);
        }

        // 按flv → hlv → mp4顺序尝试视频源的函数
        function tryVideoSourcesInOrder(videoUrls) {
            // 分离不同类型的视频源
            const flvUrls = [];
            const hlvUrls = [];
            const mp4Urls = [];
            const otherUrls = [];

            // 分类视频源
            videoUrls.forEach(url => {
                const lowerUrl = url.toLowerCase();
                if (lowerUrl.includes('.flv')) {
                    flvUrls.push(url);
                } else if (lowerUrl.includes('.hlv')) {
                    hlvUrls.push(url);
                } else if (lowerUrl.includes('.mp4')) {
                    mp4Urls.push(url);
                } else {
                    otherUrls.push(url);
                }
            });

            // 按顺序创建数组:flv -> hlv -> mp4 -> 其他
            const orderedUrls = [...flvUrls, ...hlvUrls, ...mp4Urls, ...otherUrls];

            if (orderedUrls.length === 0) {
                showError('没有可用的视频源');
                return;
            }

            // 尝试第一个视频源
            createVideoPlayer(orderedUrls[0]);

            // 设置第一个视频源为选中状态
            setTimeout(() => {
                if (document.querySelector('#videoSourceList')) {
                    const sourceItems = document.querySelectorAll('#videoSourceList > div');
                    if (sourceItems.length > 0) {
                        // 找到第一个视频源对应的菜单项
                        const firstSourceUrl = orderedUrls[0];
                        for (let i = 0; i < videoUrls.length; i++) {
                            if (videoUrls[i] === firstSourceUrl) {
                                // 移除其他项的选中状态
                                sourceItems.forEach(item => {
                                    item.style.backgroundColor = '';
                                    item.style.color = 'white';
                                });

                                // 设置当前项为选中状态
                                sourceItems[i].style.backgroundColor = 'rgba(0, 122, 255, 0.3)';
                                sourceItems[i].style.color = '#007AFF';
                                break;
                            }
                        }
                    }
                }
            }, 100);
        }

        // 创建视频播放器的函数 - 支持FLV格式
        function createVideoPlayer(videoUrl) {
            const videoContainer = document.getElementById('videoContainer');
            if (!videoContainer) return;

            // 再次确保容器被清空
            videoContainer.innerHTML = '';

            // 检测视频格式
            const isFLV = videoUrl.toLowerCase().includes('.flv') || videoUrl.toLowerCase().includes('.hlv');
            const isMP4 = videoUrl.toLowerCase().includes('.mp4');

            if (isFLV) {
                // 使用flv.js播放FLV格式
                loadFLVPlayer(videoUrl);
            } else {
                // 使用原生video元素播放其他格式
                loadNativePlayer(videoUrl);
            }
        }

        // 加载FLV播放器
        function loadFLVPlayer(videoUrl) {
            // 检查flv.js是否已加载
            if (typeof flvjs === 'undefined') {
                showError('无法加载FLV播放器库');
                return;
            }

            if (!flvjs.isSupported()) {
                showError('您的浏览器不支持FLV播放');
                return;
            }

            const videoContainer = document.getElementById('videoContainer');
            if (!videoContainer) return;

            videoContainer.innerHTML = '';

            const videoElement = document.createElement('video');
            videoElement.id = 'flvVideoElement';
            videoElement.style.width = '100%';
            videoElement.style.height = '100%';
            videoElement.controls = true;
            videoElement.autoplay = true; // 自动播放

            videoContainer.appendChild(videoElement);

            // 确保销毁旧的FLV播放器
            if (window.flvPlayer) {
                try {
                    window.flvPlayer.pause();
                    window.flvPlayer.destroy();
                } catch (e) {}
                window.flvPlayer = null;
            }

            window.flvPlayer = flvjs.createPlayer({
                type: 'flv',
                url: videoUrl,
                isLive: false,
                enableWorker: true,
                lazyLoadMaxDuration: 3 * 60,
                seekType: 'range'
            });

            window.flvPlayer.attachMediaElement(videoElement);
            window.flvPlayer.load();

            // 添加错误处理
            window.flvPlayer.on(flvjs.Events.ERROR, (errorType, errorDetail) => {
                showError('视频源播放失败,请切换其他视频源');
            });

            window.flvPlayer.play().catch(error => {
                showError('视频源播放失败,请切换其他视频源');
            });
        }

        // 加载原生播放器
        function loadNativePlayer(videoUrl) {
            const videoContainer = document.getElementById('videoContainer');
            if (!videoContainer) return;

            videoContainer.innerHTML = '';

            const videoElement = document.createElement('video');
            videoElement.id = 'nativeVideoElement';
            videoElement.style.width = '100%';
            videoElement.style.height = '100%';
            videoElement.controls = true;
            videoElement.autoplay = true;

            videoElement.src = videoUrl;

            // 添加错误处理
            videoElement.addEventListener('error', function() {
                showError('视频源播放失败,请切换其他视频源');
            });

            videoElement.addEventListener('loadeddata', function() {
                // 视频加载成功,尝试播放
                videoElement.play().catch(error => {
                    showError('视频源播放失败,请切换其他视频源');
                });
            });

            videoContainer.appendChild(videoElement);
        }

        // 显示错误信息
        function showError(message) {
            const videoContainer = document.getElementById('videoContainer');
            if (videoContainer) {
                videoContainer.innerHTML = `
                    <div style="color: white; text-align: center; padding: 20px;">
                        <div style="font-size: 24px; margin-bottom: 10px;">⚠️</div>
                        <div>${message}</div>
                    </div>
                `;
            }
        }
    };

    // 异步获取视频URL
    function get_video_url(cid, videoType, videoId) {
        return new Promise((resolve, reject) => {
            switch (videoType) {
                case "sina":
                    getSinaVideoUrls(videoId).then(resolve).catch(reject);
                    break;
                case "vupload":
                    getBilibiliVideoUrls(cid).then(resolve).catch(reject);
                    break;
                default:
                    resolve([]);
            }
        });
    }

    // 获取新浪视频URLs
    function getSinaVideoUrls(videoId) {
        return new Promise((resolve) => {
            // 先尝试获取视频ID
            GM_getjson('https://s.video.sina.com.cn/video/getvideoidbyvid?vid=' + videoId, function(json) {
                if (json.code === 1) {
                    var sina_video_id = json.data.video_id;
                    // 获取视频播放信息
                    GM_getjson('http://api.ivideo.sina.com.cn/public/video/play?appname=sinaplayer_pc&tags=sinaplayer_pc&applt=web&appver=V11220.210521.03&player=all&video_id=' + sina_video_id, function(playJson) {
                        const videoUrls = [];

                        // 如果有可用的视频URL,添加到数组
                        if (playJson.code === 1 && playJson.data && playJson.data.videos) {
                            playJson.data.videos.forEach(video => {
                                if (video.dispatch_result && video.dispatch_result.url) {
                                    videoUrls.push(video.dispatch_result.url);
                                }
                            });
                        } else {
                            // 如果code不为1,使用备份方法
                            getSinaBackupVideoUrls(videoId).then(backupUrls => {
                                // 合并备份的URL和默认URL
                                backupUrls.forEach(url => videoUrls.push(url));
                                videoUrls.push("https://s3.ivideo.sina.com.cn/" + videoId + ".flv");
                                videoUrls.push("https://s3.ivideo.sina.com.cn/" + videoId + ".hlv");
                                resolve(videoUrls);
                            });
                            return;
                        }

                        // 始终添加默认的flv和hlv地址
                        videoUrls.push("https://s3.ivideo.sina.com.cn/" + videoId + ".flv");
                        videoUrls.push("https://s3.ivideo.sina.com.cn/" + videoId + ".hlv");

                        resolve(videoUrls);
                    });
                } else {
                    // 如果获取视频ID失败,使用备份方法
                    getSinaBackupVideoUrls(videoId).then(backupUrls => {
                        const videoUrls = [];
                        // 添加备份URL
                        backupUrls.forEach(url => videoUrls.push(url));
                        // 始终添加默认的flv和hlv地址
                        videoUrls.push("https://s3.ivideo.sina.com.cn/" + videoId + ".flv");
                        videoUrls.push("https://s3.ivideo.sina.com.cn/" + videoId + ".hlv");
                        resolve(videoUrls);
                    });
                }
            });
        });
    }

    // 备份方法函数
    function getSinaBackupVideoUrls(videoId) {
        return new Promise((resolve) => {
            GM_getjson('https://interface.sina.cn/video/wap/videoinfo.d.json?vid=' + videoId, function(backupJson) {
                const backupUrls = [];
                // 如果有可用的mp4视频URL,添加到数组
                if (backupJson.code === 1 && backupJson.data && backupJson.data.mp4vid) {
                    const videoUrl = "https://edge.v.iask.com.sinacloud.net/" + backupJson.data.mp4vid + ".mp4";
                    backupUrls.push(videoUrl);
                }
                resolve(backupUrls);
            });
        });
    }

    function getBilibiliVideoUrls(cid) {
        return new Promise((resolve) => {
            const aid = window.view_all_data.data.aid || window.view_all_data.data.id
            GM_getjson('https://api.bilibili.com/x/player/wbi/playurl?gaia_source=external-link&platform=html5&avid=' + aid + '&cid=' + cid, function(json) {
                const videoUrls = [];
                // 如果有可用的mp4视频URL,添加到数组
                if (json.code === 0 && json.data) {
                    const videoUrl = json.data.durl[0].url;
                    videoUrls.push(videoUrl);
                }
                resolve(videoUrls);
            });
        });
    }
}

function fix_full_danmaku() {
    const currentPath = window.location.pathname;
    const targetPages = ['/open/moepus.powered.full-danmaku.php'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));

    if (!isTargetPage) return;


    // 新的全弹幕获取页布局
    function new_full_danmaku() {
        // 获取参数cid(如果有)
        const cid = location.hash.slice(1);
        // 清空body
        document.body.textContent = '';

        // 设置页面基本样式
        document.body.style.cssText = `
        font-family: 'Microsoft YaHei', Arial, sans-serif;
        max-width: 800px;
        margin: 0 auto;
        padding: 20px;
        background-color: #f5f5f5;
        min-height: 100vh;
        box-sizing: border-box;
    `;

        // 创建主容器
        const container = document.createElement('div');
        container.style.cssText = `
        background: white;
        border-radius: 10px;
        padding: 25px;
        box-shadow: 0 2px 10px rgba(0,0,0,0.1);
    `;

        // 创建标题
        const title = document.createElement('h1');
        title.textContent = '全弹幕下载';
        title.style.cssText = `
        text-align: center;
        color: #333;
        margin-top: 0;
        margin-bottom: 30px;
        padding-bottom: 15px;
        border-bottom: 2px solid #e8e8e8;
    `;
        container.appendChild(title);

        // 第一部分:CID输入区域
        const cidSection = document.createElement('div');
        cidSection.style.cssText = `
        background: #f9f9f9;
        padding: 20px;
        border-radius: 8px;
        margin-bottom: 20px;
        border: 1px solid #e0e0e0;
    `;

        const cidLabel = document.createElement('label');
        cidLabel.textContent = '视频CID:';
        cidLabel.style.cssText = `
        display: block;
        margin-bottom: 10px;
        font-weight: bold;
        color: #555;
    `;
        cidSection.appendChild(cidLabel);

        const cidInputContainer = document.createElement('div');
        cidInputContainer.style.cssText = `
        display: flex;
        gap: 10px;
        align-items: center;
    `;

        const cidInput = document.createElement('input');
        cidInput.type = 'text';
        cidInput.placeholder = '请输入视频CID(纯数字)';
        cidInput.value = cid || '';
        cidInput.style.cssText = `
            flex: 1;
            min-width: 0;
            padding: 12px 15px;
            border: 2px solid #ddd;
            border-radius: 6px;
            font-size: 16px;
            transition: border-color 0.3s;
            box-sizing: border-box;
        `;

        // 限制只能输入数字
        cidInput.addEventListener('input', function(e) {
            this.value = this.value.replace(/[^\d]/g, '');
        });

        const getButton = document.createElement('button');
        getButton.textContent = '获取';
        getButton.style.cssText = `
            padding: 12px 25px;
            background: linear-gradient(135deg, #00a1d6, #0089b4);
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 16px;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            white-space: nowrap;
            flex-shrink: 0;
            box-sizing: border-box;
        `;

        // 按钮悬停效果
        getButton.addEventListener('mouseenter', function() {
            this.style.background = 'linear-gradient(135deg, #0089b4, #00729c)';
            this.style.transform = 'translateY(-2px)';
            this.style.boxShadow = '0 4px 8px rgba(0, 161, 214, 0.3)';
        });

        getButton.addEventListener('mouseleave', function() {
            this.style.background = 'linear-gradient(135deg, #00a1d6, #0089b4)';
            this.style.transform = 'translateY(0)';
            this.style.boxShadow = 'none';
        });

        // 第二部分:参数设置区域
        const paramsSection = document.createElement('div');
        paramsSection.style.cssText = `
        background: #f9f9f9;
        padding: 20px;
        border-radius: 8px;
        margin-bottom: 20px;
        border: 1px solid #e0e0e0;
    `;

        const paramsTitle = document.createElement('h3');
        paramsTitle.textContent = '参数设置';
        paramsTitle.style.cssText = `
        margin-top: 0;
        margin-bottom: 15px;
        color: #555;
    `;
        paramsSection.appendChild(paramsTitle);

        const paramsGrid = document.createElement('div');
        paramsGrid.style.cssText = `
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 15px;
    `;

        // 输入框
        const paramInputContainer = document.createElement('div');
        const paramInputLabel = document.createElement('label');
        paramInputLabel.textContent = 'B站Cookie:';
        paramInputLabel.style.cssText = `
        display: block;
        margin-bottom: 5px;
        color: #666;
    `;
        paramInputContainer.appendChild(paramInputLabel);

        const paramInput = document.createElement('input');
        paramInput.type = 'text';
        paramInput.placeholder = '输入B站Cookie';
        paramInput.style.cssText = `
        width: 100%;
        padding: 10px;
        border: 2px solid #ddd;
        border-radius: 6px;
        font-size: 14px;
        box-sizing: border-box;
    `;
        paramInputContainer.appendChild(paramInput);

        // 获取功能点击事件
        getButton.addEventListener('click', function() {
            if (cidInput.value.trim() === '' || paramInput.value.trim() === '') {
                alert('请确保CID和哔哩哔哩Cookie均已填写');
                cidInput.focus();
                return;
            }
            get_full_danmaku(cidInput.value.trim());
        });

        cidInputContainer.appendChild(cidInput);
        cidInputContainer.appendChild(getButton);
        cidSection.appendChild(cidInputContainer);

        // 拖动条
        const sliderContainer = document.createElement('div');
        const sliderLabel = document.createElement('label');
        sliderLabel.textContent = '请求间隔:';
        sliderLabel.style.cssText = `
        display: block;
        margin-bottom: 5px;
        color: #666;
    `;
        sliderContainer.appendChild(sliderLabel);

        const sliderValue = document.createElement('span');
        sliderValue.textContent = '3.5';
        sliderValue.style.cssText = `
        display: inline-block;
        margin-left: 10px;
        font-weight: bold;
        color: #00a1d6;
        min-width: 30px;
    `;

        const slider = document.createElement('input');
        slider.type = 'range';
        slider.min = '2.5';
        slider.max = '10';
        slider.step = '0.1';
        slider.value = '3.5';
        slider.style.cssText = `
        width: 100%;
        height: 6px;
        border-radius: 3px;
        background: #ddd;
        outline: none;
        -webkit-appearance: none;
    `;

        // 自定义滑块样式
        slider.style.background = `linear-gradient(to right, #00a1d6 0%, #00a1d6 ${(slider.value - 2.5) * 100 / 7.5}%, #ddd ${(slider.value - 2.5) * 100 / 7.5}%, #ddd 100%)`;

        slider.addEventListener('input', function() {
            sliderValue.textContent = parseFloat(this.value).toFixed(1);
            this.style.background = `linear-gradient(to right, #00a1d6 0%, #00a1d6 ${(this.value - 2.5) * 100 / 7.5}%, #ddd ${(this.value - 2.5) * 100 / 7.5}%, #ddd 100%)`;
        });

        slider.addEventListener('change', function() {
            sliderValue.textContent = parseFloat(this.value).toFixed(1);
        });

        const sliderWrapper = document.createElement('div');
        sliderWrapper.style.cssText = `
        display: flex;
        align-items: center;
        gap: 10px;
    `;
        sliderWrapper.appendChild(slider);
        sliderWrapper.appendChild(sliderValue);
        sliderContainer.appendChild(sliderWrapper);

        paramsGrid.appendChild(paramInputContainer);
        paramsGrid.appendChild(sliderContainer);
        paramsSection.appendChild(paramsGrid);

        // 第三部分:下载按钮(默认隐藏)
        const downloadSection = document.createElement('div');
        downloadSection.style.cssText = `
        margin-bottom: 20px;
        display: none;
    `;

        const downloadButton = document.createElement('button');
        downloadButton.textContent = '下载全弹幕XML文件';
        downloadButton.style.cssText = `
        width: 100%;
        padding: 15px;
        background: linear-gradient(135deg, #4CAF50, #45a049);
        color: white;
        border: none;
        border-radius: 8px;
        font-size: 16px;
        font-weight: bold;
        cursor: pointer;
        transition: all 0.3s ease;
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 10px;
    `;

        // 下载按钮悬停效果
        downloadButton.addEventListener('mouseenter', function() {
            this.style.background = 'linear-gradient(135deg, #45a049, #3d8b40)';
            this.style.transform = 'translateY(-2px)';
            this.style.boxShadow = '0 4px 8px rgba(76, 175, 80, 0.3)';
        });

        downloadButton.addEventListener('mouseleave', function() {
            this.style.background = 'linear-gradient(135deg, #4CAF50, #45a049)';
            this.style.transform = 'translateY(0)';
            this.style.boxShadow = 'none';
        });

        downloadSection.appendChild(downloadButton);

        // 第四部分:信息输出面板
        const infoPanel = document.createElement('div');
        infoPanel.style.cssText = `
        background: #f9f9f9;
        border: 1px solid #e0e0e0;
        border-radius: 8px;
        padding: 20px;
        min-height: 200px;
        max-height: 400px;
        overflow-y: auto;
        font-family: 'Consolas', 'Monaco', monospace;
        font-size: 14px;
        line-height: 1.5;
        color: #333;
    `;

        const infoTitle = document.createElement('h3');
        infoTitle.textContent = '信息输出';
        infoTitle.style.cssText = `
        margin-top: 0;
        margin-bottom: 15px;
        color: #555;
        display: flex;
        justify-content: space-between;
        align-items: center;
    `;
        infoPanel.appendChild(infoTitle);

        const infoContent = document.createElement('div');
        infoContent.id = 'info-output';
        infoContent.style.cssText = `
        white-space: pre-wrap;
        word-break: break-all;
    `;
        infoPanel.appendChild(infoContent);

        // 将所有部分添加到容器
        container.appendChild(cidSection);
        container.appendChild(paramsSection);
        container.appendChild(downloadSection);
        container.appendChild(infoPanel);

        // 将容器添加到body
        document.body.appendChild(container);

        // 暴露一些元素给外部使用
        window.danmakuPage = {
            cidInput,
            getButton,
            paramInput,
            slider,
            sliderValue,
            downloadSection,
            downloadButton,
            infoContent,

            // 显示下载按钮
            showDownloadButton: function() {
                downloadSection.style.display = 'block';
            },

            // 隐藏下载按钮
            hideDownloadButton: function() {
                downloadSection.style.display = 'none';
            },

            // 添加信息到输出面板
            addInfo: function(message, type = 'info') {
                const colors = {
                    info: '#333',
                    success: '#4CAF50',
                    error: '#f44336',
                    warning: '#ff9800'
                };

                const messageElement = document.createElement('div');
                messageElement.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
                messageElement.style.cssText = `
                margin-bottom: 5px;
                color: ${colors[type] || colors.info};
                border-left: 3px solid ${colors[type] || colors.info};
                padding-left: 10px;
            `;

                infoContent.appendChild(messageElement);
                infoPanel.scrollTop = infoPanel.scrollHeight;
            },

            // 清空信息面板
            clearInfo: function() {
                infoContent.textContent = '';
            }
        };

        // 如果URL中有CID参数,自动聚焦到输入框
        if (cid) {
            cidInput.focus();
        }
    }

    /**
     * 获取全弹幕数据的主函数
     * @param {string} cid - 视频CID
     */
    async function get_full_danmaku(cid) {
        // 参数验证
        if (!cid || typeof cid !== 'string' || cid.trim() === '') {
            if (window.danmakuPage) {
                window.danmakuPage.addInfo('错误:CID不能为空', 'error');
            } else {
                alert('错误:CID不能为空');
            }
            return;
        }

        // 只允许数字
        if (!/^\d+$/.test(cid)) {
            if (window.danmakuPage) {
                window.danmakuPage.addInfo('错误:CID只能包含数字', 'error');
            } else {
                alert('错误:CID只能包含数字');
            }
            return;
        }

        // 获取页面中的参数值
        const paramValue = window.danmakuPage?.paramInput?.value || '';
        const sliderValue = parseFloat(window.danmakuPage?.slider?.value || 3);

        try {
            // 显示开始信息
            window.danmakuPage.clearInfo();
            window.danmakuPage.addInfo(`开始获取弹幕数据...`, 'info');
            window.danmakuPage.addInfo(`CID: ${cid}`, 'info');
            window.danmakuPage.hideDownloadButton();

            // 等待Cookie检查
            const username = await new Promise((resolve, reject) => {
                checkCookie(paramValue, (error, username) => {
                    if (error) {
                        reject(error);
                    } else {
                        resolve(username);
                    }
                });
            });

            window.danmakuPage.addInfo(`鉴权成功: ${username}`, 'success');

            // 初始化proto相关
            proto_init();
            // 初始化全局弹幕数据列表
            window.danmakuData = [];

            let currentDate = getTodayDate(); // 从今日日期开始获取
            let lastRequestedDate = null; // 上一次请求的日期
            let hasMoreData = true;
            let isRateLimited = false; // 是否被风控
            let consecutiveEmptyDays = 0; // 连续空数据天数

            while (hasMoreData && !isRateLimited) {
                try {
                    // 记录当前请求的日期
                    lastRequestedDate = currentDate;

                    // 获取弹幕数据
                    const responseData = await fetchDanmakuAsync(cid, currentDate, paramValue);

                    // 检查是否被风控(返回HTML内容)
                    if (responseData === null) {
                        window.danmakuPage.addInfo(`请求过快,已被风控!请调整请求间隔后重试`, 'error');
                        isRateLimited = true;
                        hasMoreData = false;
                        break;
                    }

                    if (responseData && responseData.length > 0) {
                        consecutiveEmptyDays = 0; // 重置连续空数据计数器
                        window.danmakuPage.addInfo(`获取${currentDate}数据成功,共${responseData.length}条弹幕`, 'success');

                        // 解码并合并弹幕数据
                        decodeAndMergeDanmakuData(responseData);

                        // 找到最早的弹幕时间
                        if (window.danmakuData.length > 0) {
                            const earliestDanmaku = window.danmakuData.reduce((earliest, current) => {
                                return current.ctime < earliest.ctime ? current : earliest;
                            }, window.danmakuData[0]);

                            // 获取最早弹幕的日期
                            const earliestDate = formatTimestampToDate(earliestDanmaku.ctime);

                            // 只有当最早日期和当前请求日期相同时,才向前推一天
                            if (earliestDate === currentDate) {
                                // 日期相同,向前推一天
                                const dateObj = new Date(currentDate);
                                dateObj.setDate(dateObj.getDate() - 1);
                                currentDate = dateObj.toISOString().split('T')[0];
                                window.danmakuPage.addInfo(`最早弹幕日期与请求日期相同,向前推一天:${currentDate}`, 'info');
                            } else {
                                // 日期不同,使用最早弹幕的日期
                                currentDate = earliestDate;
                                window.danmakuPage.addInfo(`最早弹幕日期:${currentDate},继续获取该日期数据`, 'info');
                            }
                        }
                    } else {
                        consecutiveEmptyDays++;
                        window.danmakuPage.addInfo(`获取${currentDate}数据为空,该日期无弹幕`, 'warning');

                        // 日期为空,向前推一天
                        const dateObj = new Date(currentDate);
                        dateObj.setDate(dateObj.getDate() - 1);
                        currentDate = dateObj.toISOString().split('T')[0];

                        // 如果连续获取到空数据超过1次就停止
                        if (consecutiveEmptyDays >= 1) {
                            window.danmakuPage.addInfo(`已连续获取${consecutiveEmptyDays}天空数据,停止获取`, 'info');
                            hasMoreData = false;
                        }
                    }

                    // 延迟,避免请求过快
                    await new Promise(resolve => setTimeout(resolve, sliderValue * 1000));

                } catch (error) {
                    window.danmakuPage.addInfo(`获取${currentDate}数据失败: ${error.message}`, 'error');
                    hasMoreData = false;
                }
            }

            // 获取完成后显示下载按钮
            if (window.danmakuData.length > 0 && !isRateLimited) {
                window.danmakuPage.showDownloadButton();
                window.danmakuPage.addInfo(`弹幕获取完成!共获取${window.danmakuData.length}条弹幕`, 'success');

                // 为下载按钮绑定事件 - 修复:使用闭包避免变量冲突
                const downloadButton = window.danmakuPage.downloadButton;
                const currentCid = cid; // 保存当前cid
                downloadButton.onclick = function() {
                    downloadDanmakuXML(currentCid, `danmaku_${currentCid}.xml`);
                };
            } else if (isRateLimited) {
                window.danmakuPage.addInfo('获取中断:请求过快被风控,请调整请求间隔后重试', 'error');
            } else {
                window.danmakuPage.addInfo('未获取到任何弹幕数据', 'warning');
            }

        } catch (error) {
            window.danmakuPage.addInfo(`获取失败: ${error.message}`, 'error');
        }
    }

    // 异步版本的fetchDanmaku
    function fetchDanmakuAsync(cid, date, cookie) {
        return new Promise((resolve, reject) => {
            GM_get_request("https://api.bilibili.com/x/v2/dm/web/history/seg.so?type=1&oid=" + cid + "&date=" + date,
                function(response) {
                    try {
                        // 检查响应内容是否为HTML(风控检测)
                        if (response.responseText && (
                                response.responseText.includes('<!DOCTYPE') ||
                                response.responseText.includes('<html') ||
                                response.responseText.includes('Access Denied') ||
                                response.responseText.includes('rate limit') ||
                                response.responseText.includes('Just a moment') ||
                                response.responseText.includes('验证')
                            )) {
                            resolve(null); // 返回null表示被风控
                        }

                        // 尝试解析JSON(如果是错误信息)
                        const json = JSON.parse(response.responseText);
                        reject(new Error(json.message || 'API返回错误'));
                    } catch (e) {
                        // 不是JSON,检查是否为二进制数据
                        if (response.response instanceof ArrayBuffer || response.response instanceof Uint8Array) {
                            // 检查响应是否为空
                            if (response.response.byteLength === 0) {
                                resolve([]); // 返回空数组表示无数据
                            } else {
                                // 解码数据
                                try {
                                    const uint8Array = new Uint8Array(response.response);
                                    const decodedMessage = window.DmSegMobileReply.decode(uint8Array);
                                    resolve(decodedMessage.elems || []);
                                } catch (decodeError) {
                                    reject(new Error('解码失败: ' + decodeError.message));
                                }
                            }
                        } else {
                            resolve([]); // 其他情况也返回空数组
                        }
                    }
                },
                null, {
                    'Cookie': cookie
                },
                "arraybuffer"
            );
        });
    }

    // 检查cookie
    function checkCookie(cookie, callback) {
        GM_getjson("https://api.bilibili.com/x/web-interface/nav",
            (json) => {
                if (json.code !== 0) {
                    callback("非法Cookie");
                } else {
                    callback(null, json.data.uname);
                }
            },
            (error) => {
                callback("网络请求失败");
            }, {
                'Cookie': cookie
            }
        );
    }

    // 时间戳转日期字符串(YYYY-MM-DD)
    function formatTimestampToDate(timestamp) {
        const date = new Date(timestamp * 1000);
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0');
        const day = String(date.getDate()).padStart(2, '0');
        return `${year}-${month}-${day}`;
    }

    // 初始化proto工具
    function proto_init() {
        const PROTO_DEFINITION = `
        syntax = "proto3";
        package bilibili.community.service.dm.v1;

        // 弹幕条目
        message DanmakuElem {
            int64 id = 1;           // 弹幕ID
            int32 progress = 2;     // 弹幕出现位置(ms)
            int32 mode = 3;         // 弹幕类型
            int32 fontsize = 4;     // 弹幕字号
            uint32 color = 5;       // 弹幕颜色
            string midHash = 6;     // 发送者mid hash
            string content = 7;     // 弹幕正文
            int64 ctime = 8;        // 发送时间(这是你需要的)
            int32 weight = 9;       // 权重
            string action = 10;     // 动作
            int32 pool = 11;        // 弹幕池
            string idStr = 12;      // 弹幕ID字符串
            int32 attr = 13;        // 弹幕属性位
        }

        // 分段弹幕响应
        message DmSegMobileReply {
            repeated DanmakuElem elems = 1;  // 弹幕列表
            int32 state = 2;                  // 是否已关闭弹幕
        }`;

        window.danmakuPage.addInfo(`正在初始化弹幕解码工具`, 'info');
        try {
            // 使用protobuf.js 8.0.0加载proto定义
            const root = protobuf.parse(PROTO_DEFINITION).root;

            // 获取消息类型
            window.DmSegMobileReply = root.lookupType("bilibili.community.service.dm.v1.DmSegMobileReply");
            window.DanmakuElem = root.lookupType("bilibili.community.service.dm.v1.DanmakuElem");
            window.danmakuPage.addInfo('解码工具加载成功!', 'success');

        } catch (error) {
            window.danmakuPage.addInfo(`解码工具加载失败: ${error.message}`, 'error');
        }
    }

    // 解码并合并弹幕数据
    function decodeAndMergeDanmakuData(danmakuElems) {
        if (!danmakuElems || danmakuElems.length === 0) return;

        const newDanmaku = [];
        for (const elem of danmakuElems) {
            const danmakuItem = {
                id: elem.id || elem.idStr || '',
                progress: elem.progress || 0,
                mode: elem.mode || 1,
                fontsize: elem.fontsize || 25,
                color: elem.color || 0xFFFFFF,
                midHash: elem.midHash || '',
                content: elem.content || '',
                ctime: elem.ctime || 0,
            };
            newDanmaku.push(danmakuItem);
        }

        // 合并到全局数据
        window.danmakuData = window.danmakuData.concat(newDanmaku);

        // 去重和排序
        const uniqueDanmakuData = [];
        const idSet = new Set();

        for (const item of window.danmakuData) {
            const itemId = item.id || '';
            if (!idSet.has(itemId)) {
                idSet.add(itemId);
                uniqueDanmakuData.push(item);
            }
        }

        window.danmakuData = uniqueDanmakuData.sort((a, b) => a.ctime - b.ctime);
        window.danmakuPage.addInfo(`去重后已获取${window.danmakuData.length}条弹幕`, 'success');
    }

    // XML下载函数
    function downloadDanmakuXML(cid, filename) {
        try {
            if (!window.danmakuData || window.danmakuData.length === 0) {
                window.danmakuPage.addInfo('错误:没有弹幕数据可下载', 'error');
                return;
            }

            window.danmakuPage.addInfo(`开始生成XML文件...`, 'info');

            // 按照 id 去重
            const seenIds = new Set();
            const uniqueDanmaku = [];
            for (const dm of window.danmakuData) {
                const dmId = dm.id || "";
                if (!seenIds.has(dmId)) {
                    seenIds.add(dmId);
                    uniqueDanmaku.push(dm);
                }
            }

            // 创建XML文档
            const doc = document.implementation.createDocument(null, "i", null);
            const root = doc.documentElement;

            // 添加固定元素
            const addElement = (parent, tagName, text) => {
                const elem = doc.createElement(tagName);
                elem.textContent = String(text);
                parent.appendChild(elem);
            };

            addElement(root, "chatserver", "chat.bilibili.com");
            addElement(root, "chatid", cid);
            addElement(root, "mission", "0");
            addElement(root, "maxlimit", "0");
            addElement(root, "state", "0");
            addElement(root, "real_name", "0");
            addElement(root, "source", "k-v");

            // 添加弹幕数据
            uniqueDanmaku.forEach(dm => {
                // 计算progress(秒)
                const progress = dm.progress ? (dm.progress / 1000).toString() : "0";
                const mode = dm.mode || 1;
                const fontsize = dm.fontsize || 25;
                const color = dm.color || 16777215;
                const ctime = dm.ctime || 0;
                const midHash = dm.midHash || "";
                const id = dm.id || "";
                const content = dm.content || "";

                // 构造属性字符串
                const attrStr = `${progress},${mode},${fontsize},${color},${ctime},0,${midHash},${id}`;

                // 创建弹幕元素
                const dElem = doc.createElement("d");
                dElem.setAttribute("p", attrStr);
                dElem.textContent = content;
                root.appendChild(dElem);
            });

            // 生成XML字符串
            const xmlSerializer = new XMLSerializer();
            let xmlString = xmlSerializer.serializeToString(doc);

            // 添加XML声明
            xmlString = '<?xml version="1.0" encoding="UTF-8"?>\n' + xmlString;

            // 创建下载
            const blob = new Blob([xmlString], {
                type: 'text/xml;charset=utf-8'
            });
            const url = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = url;
            link.download = filename;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(url);

            window.danmakuPage.addInfo(`XML文件下载完成: ${filename} (${uniqueDanmaku.length}条弹幕)`, 'success');

        } catch (error) {
            window.danmakuPage.addInfo(`下载失败: ${error.message}`, 'error');
        }
    }

    new_full_danmaku();
}

function cover_video_refresh() {
    const currentPath = window.location.pathname;
    const targetPages = ['/video/'];
    const isTargetPage = targetPages.some(page => currentPath.startsWith(page));

    if (!isTargetPage) return;

    // ========== 获取 aid ==========
    function getAid() {
        return av
    }

    // ========== 调用 B 站 API ==========
    function checkVideoAlive(aid) {
        const video_state_dict = {
            0: "正常稿件",
            1: "退回或锁定",
            2: "番剧重定向",
            3: "测试稿件",
            4: "正常普通会员视频",
            5: "锁定普通会员视频",
            9: "UP主自删",
            13: "自删普通会员视频",
            16: "正常互动视频",
            17: "锁定互动视频",
            25: "自删互动视频"
        };
        GM_xmlhttpRequest({
            method: 'GET',
            url: `https://api.bilibili.com/x/v3/fav/resource/infos?resources=${aid}:2`,
            onload: (resp) => {
                try {
                    const json = JSON.parse(resp.responseText);
                    if (json.code === 0 && json.data != null) {
                        if (json.data.length == 0) {
                            unsafeWindow.createUpdateNotice('仅UP主个人可见', 'F00');
                        } else {
                            videoData = json.data[0]
                            attr = videoData.attr
                            state_desc = video_state_dict[attr]
                            if (attr == 0) {
                                unsafeWindow.createUpdateNotice('检查成功:状态正常', '0C0')
                            } else {
                                unsafeWindow.createUpdateNotice('检查成功:' + state_desc, 'F00')
                            }

                        }

                    }
                } catch (e) {
                    console.error('解析响应失败', e);
                    unsafeWindow.createUpdateNotice('检查失败:啥都木有', 'F00');
                }
            },
            onerror: () => {
                unsafeWindow.createUpdateNotice('请求错误', 'F00');
            }
        });
    }

    // ========== 新的刷新函数 ==========
    function newRefresh() {
        const aid = getAid();
        if (!aid) {
            unsafeWindow.createUpdateNotice('检查失败:无法获取aid', 'F00');
            return;
        }
        // 先显示正在刷新(蓝色)
        unsafeWindow.createUpdateNotice("正在检查状态……", "00F");
        // 调用 API 检测
        checkVideoAlive(aid);
    }

    // ========== 覆盖刷新按钮 ==========
    function overrideRefreshButton() {
        // 覆盖全局 refresh 函数
        unsafeWindow.refresh = newRefresh;

        // 同时修改按钮的 onclick 属性
        const refreshLink = document.querySelector('a[onclick="refresh()"]');
        if (refreshLink) {
            refreshLink.removeAttribute('onclick');
            refreshLink.textContent = '检查状态';
            refreshLink.addEventListener('click', (e) => {
                e.preventDefault();
                newRefresh();
            });
        }
    }
    overrideRefreshButton()
}
// 页面加载完成后执行
(function() {
    'use strict';
    // 初始化脚本
    script_init();
    // 额外功能
    add_extra_features();
    add_video_snapshot();
    add_video_detail();
    add_history_detail();
    add_history_custome();
    // 修复功能
    fix_index_random_video();
    fix_space_userinfo();
    fix_space_user_video();
    fix_video_user_video();
    fix_video_h5play();
    fix_full_danmaku();
    // 覆盖功能
    cover_video_refresh();
})();