bilibili favlist backup

automatically backup info of videos in favlist

// ==UserScript==
// @name              bilibili favlist backup
// @name:zh-CN        哔哩哔哩(B站|Bilibili)收藏夹Fix (备份视频信息)
// @name:zh-TW        哔哩哔哩(B站|Bilibili)收藏夹Fix (备份视频信息)
// @namespace         http://tampermonkey.net/
// @version           16
// @description       automatically backup info of videos in favlist
// @description:zh-CN 自动备份视频信息至本地和第三方网站, 失效视频信息回显
// @description:zh-TW 自动备份视频信息至本地和第三方网站, 失效视频信息回显
// @author            YTB0710
// @match             https://space.bilibili.com/*
// @connect           bbdownloader.com
// @connect           bilibili.com
// @connect           biliplus.com
// @connect           jiji.moe
// @connect           jijidown.com
// @connect           xbeibeix.com
// @grant             GM_openInTab
// @grant             GM_setValue
// @grant             GM_getValue
// @grant             GM_deleteValue
// @grant             GM_listValues
// @grant             GM_getValues
// @grant             GM_xmlhttpRequest
// ==/UserScript==

(function () {
    'use strict';

    const updates = '更新内容:<br>' +
        '新增: 设置获取数据的最小更新间隔的功能';

    const version = 16;

    const favlistURLRegex = /https:\/\/space\.bilibili\.com\/\d+\/favlist.*/;
    const localeTimeStringRegex = /^\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}$/;
    const getFidFromURLRegex = /fid=(\d+)/;
    const getFtypeFromURLRegex = /ftype=(\w+)/;
    const getUIDFromURLRegex = /https:\/\/space\.bilibili\.com\/(\d+)/;
    const getBVFromURLRegex = /video\/(BV\w{10})/;
    const getHttpsFromURLRegex = /^https?:\/\//;
    const getJsonFromBiliplusRegex = /window\.addEventListener\('DOMContentLoaded',function\(\){view\((.+)\);}\);/;
    const getFilenameFromURLRegex = /[^/]+(?:\.[a-zA-Z0-9]+)$/;
    const getAvifFromURLRegex = /@.*/;

    // let AVBVs;
    // let fidOfAVBVs;
    let onFavlistPage = false;
    let enableAutoNextPage = false;
    let enableDebug = false;
    let newFreshSpace;
    let classAppendNewFreshSpace;
    let pageSize;
    // let mutations_count = 0;
    // let mutation_count = 0;
    let firstTimeMain = true;
    let divMessage;
    let divMessageHeightFixed = false;
    let order = 'mtime';
    const activeControllers = new Set();

    const sortedKeys = [
        'BV',
        'AV',
        'title',
        'intro',
        'cover',
        'upperUID',
        'upperName',
        'upperAvatar',
        'timeUpload',
        'timePublish',
        'timeFavorite',
        'dynamic',
        'pages',
        'api',
        'apiExtra',
        'biliplus',
        'jijidown',
        'jijidownExtra',
        'xbeibeix',
        // 'preferredTitle',
        // 'preferredCover',
    ];

    const settings = GM_getValue('settings', {
        version: 0,
        processNormal: true,
        processDisabled: true,
        enableGetFromApi: true,
        enableGetFromApiExtra: false,
        enableGetFromBiliplus: true,
        enableGetFromJijidown: false,
        enableGetFromJijidownExtra: false,
        enableGetFromXbeibeix: false,
        defaultFavlistFid: null,
        defaultUID: null,
        getFromJijidownURL: 'www.jijidown.com',
        getFromXbeibeixURL: 'xbeibeix.com',
        displayAdvancedControls: false,
        advancedDisableUpdateGetFromApi: false,
        advancedDisableUpdateGetFromApiExtra: false,
        advancedDisableUpdateGetFromBiliplus: true,
        advancedDisableUpdateGetFromJijidown: true,
        advancedDisableUpdateGetFromJijidownExtra: true,
        advancedDisableUpdateGetFromXbeibeix: true,
        advancedIntervalGetFromApi: 5,
        advancedIntervalGetFromApiExtra: 5,
        advancedIntervalGetFromBiliplus: 10,
        advancedIntervalGetFromJijidown: 10,
        advancedIntervalGetFromJijidownExtra: 10,
        advancedIntervalGetFromXbeibeix: 10,
        advancedIntervalAutoNextPage: 5,
    });

    ///////////////////////////////////////////////////////////////////////////////////
    // enableDebug = true;
    // settings.processNormal = false;
    // settings.processDisabled = false;
    // settings.enableGetFromApi = false;
    // settings.enableGetFromBiliplus = false;
    // v9
    if (typeof settings.defaultFavlistFid === 'string') {
        settings.defaultFavlistFid = parseInt(settings.defaultFavlistFid, 10);
        GM_setValue('settings', settings);
    }
    // v10
    if (settings.hasOwnProperty('enableGetFromJiji')) {
        settings.enableGetFromJijidown = settings.enableGetFromJiji;
        delete settings.enableGetFromJiji;
        GM_setValue('settings', settings);
    }
    // v10
    if (settings.hasOwnProperty('enableGetFromBbdownloader')) {
        settings.enableGetFromXbeibeix = settings.enableGetFromBbdownloader;
        delete settings.enableGetFromBbdownloader;
        GM_setValue('settings', settings);
    }
    // v10
    if (!settings.hasOwnProperty('getFromJijidownURL')) {
        settings.getFromJijidownURL = 'www.jijidown.com';
        GM_setValue('settings', settings);
    }
    // v10
    if (!settings.hasOwnProperty('getFromXbeibeixURL')) {
        settings.getFromXbeibeixURL = 'xbeibeix.com';
        GM_setValue('settings', settings);
    }
    // v13
    if (settings.hasOwnProperty('enableDebug')) {
        delete settings.enableDebug;
        GM_setValue('settings', settings);
    }
    // v14
    if (!settings.hasOwnProperty('enableGetFromApiExtra')) {
        settings.enableGetFromApiExtra = false;
        GM_setValue('settings', settings);
    }
    // v14
    if (!settings.hasOwnProperty('enableGetFromJijidownExtra')) {
        settings.enableGetFromJijidownExtra = false;
        GM_setValue('settings', settings);
    }
    // v16
    if (!settings.enableGetFromApi && settings.enableGetFromApiExtra) {
        settings.enableGetFromApiExtra = false;
        GM_setValue('settings', settings);
    }
    // v16
    if (!settings.hasOwnProperty('displayAdvancedControls')) {
        settings.displayAdvancedControls = false;
        settings.advancedDisableUpdateGetFromApi = false;
        settings.advancedDisableUpdateGetFromApiExtra = false;
        settings.advancedDisableUpdateGetFromBiliplus = true;
        settings.advancedDisableUpdateGetFromJijidown = true;
        settings.advancedDisableUpdateGetFromJijidownExtra = true;
        settings.advancedDisableUpdateGetFromXbeibeix = true;
        settings.advancedIntervalGetFromApi = 5;
        settings.advancedIntervalGetFromApiExtra = 5;
        settings.advancedIntervalGetFromBiliplus = 10;
        settings.advancedIntervalGetFromJijidown = 10;
        settings.advancedIntervalGetFromJijidownExtra = 10;
        settings.advancedIntervalGetFromXbeibeix = 10;
        settings.advancedIntervalAutoNextPage = 5;
        GM_setValue('settings', settings);
    }
    ///////////////////////////////////////////////////////////////////////////////////

    const favlistObserver = new MutationObserver(async (_mutations, observer) => {
        if (enableDebug) console.debug('callback favlistObserver');
        if (document.querySelector('div.items')) {
            if (enableDebug) console.debug('disconnect favlistObserver');
            observer.disconnect();
            newFreshSpace = true;
            classAppendNewFreshSpace = '-newFreshSpace';
            pageSize = window.innerWidth < 1760 ? 40 : 36;
            initControls();
            if (!firstTimeMain) {
                await delay(200);
                main();
            }
            if (enableDebug) console.debug('observe itemsObserver');
            itemsObserver.observe(document.querySelector('div.items'), { childList: true, attributes: false, characterData: false });
            if (enableDebug) console.debug('observe bodyChildListObserver');
            bodyChildListObserver.observe(document.body, { childList: true, attributes: false, characterData: false });
            if (enableDebug) console.debug('observe radioFilterObserver');
            radioFilterObserver.observe(document.querySelector('div.fav-list-header-filter__left > div'), { subtree: true, characterData: false, attributeFilter: ['class'] });
            if (enableDebug) console.debug('observe headerFilterLeftChildListObserver');
            headerFilterLeftChildListObserver.observe(document.querySelector('div.fav-list-header-filter__left'), { childList: true, attributes: false, characterData: false });
            return;
        }
        if (document.querySelector('div.fav-content.section')) {
            if (enableDebug) console.debug('disconnect favlistObserver');
            observer.disconnect();
            newFreshSpace = false;
            classAppendNewFreshSpace = '';
            pageSize = 20;
            initControls();
            if (enableDebug) console.debug('observe favContentSectionObserver');
            favContentSectionObserver.observe(document.querySelector('div.fav-content.section'), { characterData: false, attributeFilter: ['class'] });
            return;
        }
    });

    // const itemsObserver = new MutationObserver(async (mutations) => {
    const itemsObserver = new MutationObserver(async () => {
        abortActiveControllers();
        if (enableDebug) console.debug('callback itemsObserver');
        await delay(200);
        // mainNewFreshSpace();
        // mainNewFreshSpace(mutations);
        main();
    });

    const bodyChildListObserver = new MutationObserver(mutations => {
        if (enableDebug) console.debug('callback bodyChildListObserver');
        if (enableDebug) console.debug(mutations);
        for (const mutation of mutations) {
            for (const addedNode of mutation.addedNodes) {
                if (addedNode.nodeType === 1 && addedNode.classList.contains('bili-card-dropdown-popper')) {
                    appendDropdowns(addedNode);
                    // return;
                }
                // if (addedNode.nodeType === 1 && addedNode.classList.contains('vui_toast--wrapper')) {
                //     abortActiveControllers();
                //     if (enableDebug) console.debug('disconncet itemsObserver');
                //     itemsObserver.disconnect();
                //     // return;
                // }
            }
            // for (const removedNode of mutation.removedNodes) {
            //     if (removedNode.nodeType === 1 && removedNode.classList.contains('vui_toast--wrapper')) {
            //         abortActiveControllers();
            //         // mainNewFreshSpace();
            //         main();
            //         if (enableDebug) console.debug('observe itemsObserver');
            //         itemsObserver.observe(document.querySelector('div.items'), { childList: true, attributes: false, characterData: false });
            //         // return;
            //     }
            // }
        }
    });

    const radioFilterObserver = new MutationObserver(mutations => {
        if (enableDebug) console.debug('callback radioFilterObserver');
        if (enableDebug) console.debug(mutations);
        for (const mutation of mutations) {
            if (mutation.target.classList.contains('radio-filter__item--active')) {
                const orderText = mutation.target.innerText;
                if (orderText.includes('收藏')) {
                    order = 'mtime';
                } else if (orderText.includes('播放')) {
                    order = 'view';
                } else if (orderText.includes('投稿')) {
                    order = 'pubtime';
                } else {
                    addMessage('无法确定各个视频的排序方式, 请反馈该问题', false, true);
                }
                if (enableDebug) console.log(`order: ${order}`);
            }
        }
    });

    const headerFilterLeftChildListObserver = new MutationObserver(mutations => {
        if (enableDebug) console.debug('callback headerFilterLeftChildListObserver');
        if (enableDebug) console.debug(mutations);
        for (const mutation of mutations) {
            for (const addedNode of mutation.addedNodes) {
                if (addedNode.nodeType === 1 && addedNode.classList.contains('radio-filter')) {
                    order = 'mtime';
                    if (enableDebug) console.log(`order: ${order}`);
                    if (enableDebug) console.debug('observe radioFilterObserver');
                    radioFilterObserver.observe(addedNode, { subtree: true, characterData: false, attributeFilter: ['class'] });
                }
            }
            for (const removedNode of mutation.removedNodes) {
                if (removedNode.nodeType === 1 && removedNode.classList.contains('radio-filter')) {
                    if (enableDebug) console.debug('disconncet radioFilterObserver');
                    radioFilterObserver.disconnect();
                }
            }
        }
    });

    const favContentSectionObserver = new MutationObserver(mutations => {
        if (enableDebug) console.debug('callback favContentSectionObserver');
        for (const mutation of mutations) {
            if (!mutation.target.classList.contains('loading')) {
                abortActiveControllers();
                main();
                return;
            }
        }
    });

    checkURL();

    const originalPushState = history.pushState;
    history.pushState = function (...args) {
        originalPushState.apply(this, args);
        checkURL();
    };

    const originalReplaceState = history.replaceState;
    history.replaceState = function (...args) {
        originalReplaceState.apply(this, args);
        checkURL();
    };

    window.addEventListener('popstate', checkURL);

    function checkURL() {
        if (enableDebug) console.debug('checkURL');
        if (favlistURLRegex.test(location.href)) {
            if (!onFavlistPage) {
                onFavlistPage = true;
                if (enableDebug) console.debug('observe favlistObserver');
                favlistObserver.observe(document.body, { subtree: true, childList: true, attributes: false, characterData: false });
            }
        } else {
            if (onFavlistPage) {
                abortActiveControllers();
                onFavlistPage = false;
                if (enableDebug) console.debug('disconnect favlistObserver');
                favlistObserver.disconnect();
                if (enableDebug) console.debug('disconncet itemsObserver');
                itemsObserver.disconnect();
                if (enableDebug) console.debug('disconncet bodyChildListObserver');
                bodyChildListObserver.disconnect();
                if (enableDebug) console.debug('disconncet radioFilterObserver');
                radioFilterObserver.disconnect();
                if (enableDebug) console.debug('disconncet headerFilterLeftChildListObserver');
                headerFilterLeftChildListObserver.disconnect();
                if (enableDebug) console.debug('disconncet favContentSectionObserver');
                favContentSectionObserver.disconnect();
            }
        }
    }

    async function main() {

        if (enableDebug) console.log('============main============');

        let controller;
        firstTimeMain = false;

        try {

            controller = new AbortController();
            activeControllers.add(controller);

            let fid;
            const getFidFromURLMatch = location.href.match(getFidFromURLRegex);
            if (newFreshSpace) {
                if (getFidFromURLMatch) {
                    fid = parseInt(getFidFromURLMatch[1], 10);
                } else if (settings.defaultFavlistFid) {
                    fid = settings.defaultFavlistFid;
                } else {
                    throw ['无法获取当前收藏夹的fid, 刷新页面可能有帮助'];
                }
                const getFtypeFromURLMatch = location.href.match(getFtypeFromURLRegex);
                if (getFtypeFromURLMatch) {
                    if (getFtypeFromURLMatch[1] !== 'create') {
                        if (enableDebug) console.log('不处理特殊收藏夹');
                        return;
                    }
                    if (!settings.defaultFavlistFid && !document.querySelector('div.vui_sidebar-item--active').parentNode.getAttribute('id')) {
                        settings.defaultFavlistFid = fid;
                        GM_setValue('settings', settings);
                    }
                } else if (!document.querySelector('div.vui_sidebar-item--active').parentNode.getAttribute('id') && fid !== settings.defaultFavlistFid) {
                    if (enableDebug) console.log('不处理特殊收藏夹');
                    return;
                }

            } else {
                if (getFidFromURLMatch) {
                    fid = parseInt(getFidFromURLMatch[1], 10);
                    if (fid !== parseInt(document.querySelector('.fav-item.cur').getAttribute('fid'), 10)) {
                        if (enableDebug) console.log('不处理特殊收藏夹');
                        return;
                    }
                } else {
                    fid = parseInt(document.querySelector('.fav-item.cur').getAttribute('fid'), 10);
                    if (!fid) {
                        if (enableDebug) console.log('不处理特殊收藏夹');
                        return;
                    }
                }
            }

            let pageNumber;
            if (newFreshSpace) {
                const pagenation = document.querySelector('button.vui_pagenation--btn-num.vui_button--active');
                if (!pagenation) {
                    pageNumber = 1;
                } else {
                    pageNumber = parseInt(pagenation.innerText, 10);
                }
            } else {
                pageNumber = parseInt(document.querySelector('li.be-pager-item-active > a').innerText, 10);
            }

            if (!settings.defaultUID) {
                settings.defaultUID = parseInt(location.href.match(getUIDFromURLRegex)[1], 10);
                GM_setValue('settings', settings);
            }

            const videos = document.querySelectorAll(newFreshSpace ? 'div.items__item' : 'li.small-item');

            // if (fid !== fidOfAVBVs || !AVBVs) {
            //     if (controller.signal.aborted) {
            //         throw new DOMException('', 'AbortError');
            //     }
            //     const response = await new Promise((resolve, reject) => {
            //         GM.xmlHttpRequest({
            //             method: 'GET',
            //             url: `https://api.bilibili.com/x/v3/fav/resource/ids?media_id=${fid}&platform=web`,
            //             timeout: 5000,
            //             responseType: 'json',
            //             onload: (res) => resolve(res),
            //             onerror: (res) => reject(['请求失败', 'api.bilibili.com/x/v3/fav/resource/ids', res.error]),
            //             ontimeout: () => reject(['请求超时', 'api.bilibili.com/x/v3/fav/resource/ids'])
            //         });
            //     });
            //     if (enableDebug) console.log(`获取新的AVBVs, fid: ${fid}`);
            //     fidOfAVBVs = fid;
            //     AVBVs = response.response.data;
            // }

            // const clonedAVBVs = structuredClone(AVBVs);

            const apiDetails = {};

            for (const [index, video] of videos.entries()) {

                let as;
                const AVBVTitle = {
                    AV: null,
                    BV: null,
                    title: null
                };

                try {

                    if (controller.signal.aborted) {
                        throw new DOMException('', 'AbortError');
                    }

                    if (video.querySelector(newFreshSpace ? 'div.bili-cover-card__tags' : 'div.ogv-corner-tag')) {
                        if (enableDebug) console.log('不处理特殊视频');
                        continue;
                    }

                    let disabled = false;
                    if (newFreshSpace) {
                        if (!video.querySelector('div.bili-cover-card__stats')) {
                            disabled = true;
                        }
                    } else {
                        if (video.classList.contains('disabled')) {
                            disabled = true;
                        }
                    }

                    if (!settings.processNormal && !disabled) {
                        continue;
                    }
                    if (!settings.processDisabled && disabled) {
                        continue;
                    }

                    as = video.querySelectorAll('a');

                    const divTitleNewFreshSpace = video.querySelector('div.bili-video-card__title');

                    if (controller.signal.aborted) {
                        throw new DOMException('', 'AbortError');
                    }

                    if (newFreshSpace) {
                        const getBVFromURLMatch = as[0].getAttribute('href').match(getBVFromURLRegex);
                        if (!getBVFromURLMatch) {
                            throw ['无法获取该视频的BV号, 请检查是否有其他脚本或插件修改了该视频封面和标题的链接地址, 并将其关闭'];
                        }
                        AVBVTitle.BV = getBVFromURLMatch[1];
                    } else {
                        AVBVTitle.BV = video.getAttribute('data-aid');
                    }

                    // const target = clonedAVBVs.find(el => el.bvid === AVBVTitle.BV);
                    // if (target) {
                    //     AVBVTitle.AV = target.id;
                    // }

                    AVBVTitle.title = as[1].innerText;

                    if (enableDebug) console.log('========video========');
                    if (enableDebug) console.log(`收藏夹fid: ${fid}`);
                    if (enableDebug) console.log(`位置: 第${pageNumber}页的第${index + 1}个`);
                    if (enableDebug) consoleAVBVTitle('log', AVBVTitle);

                    let spanFavTime;
                    let divTCABJX;

                    if (newFreshSpace) {
                        const divSubtitle = document.createElement('div');
                        divSubtitle.classList.add('bili-video-card__subtitle');
                        video.querySelector('div.bili-video-card__details').appendChild(divSubtitle);
                        spanFavTime = document.createElement('span');
                        spanFavTime.textContent = '投稿于:';
                        divSubtitle.appendChild(spanFavTime);

                        divTCABJX = document.createElement('div');
                        divTCABJX.style.marginLeft = 'auto';
                        divTCABJX.style.display = 'block';
                        divSubtitle.appendChild(divTCABJX);

                    } else {
                        const divMetaPubdate = video.querySelector('div.meta.pubdate');
                        const metaText = divMetaPubdate.innerText;
                        divMetaPubdate.innerHTML = null;

                        spanFavTime = document.createElement('span');
                        spanFavTime.textContent = metaText.replace(': ', ':');
                        spanFavTime.style.width = 'auto';
                        spanFavTime.style.lineHeight = '16px';
                        divMetaPubdate.appendChild(spanFavTime);

                        // divTCABJX = document.createElement('div');
                        // divTCABJX.style.marginLeft = 'auto';
                        // // divTCABJX.style.display = 'block';
                        // divMetaPubdate.appendChild(divTCABJX);

                        divTCABJX = divMetaPubdate;
                    }

                    const spanX = document.createElement('span');
                    spanX.classList.add('backup-spanTCABJX' + classAppendNewFreshSpace);
                    spanX.textContent = 'X';
                    if (!newFreshSpace) {
                        // spanX.style.marginRight = '11px';
                        spanX.style.marginRight = '9px';
                        spanX.style.lineHeight = '16px';
                    }
                    spanX.addEventListener('click', () => {
                        try {
                            GM_openInTab(`https://${settings.getFromXbeibeixURL}/video/${AVBVTitle.BV}`, { active: true, insert: false, setParent: true });
                        } catch (error) {
                            catchUnknownError(error);
                        }
                    });
                    divTCABJX.appendChild(spanX);

                    const spanJ = document.createElement('span');
                    spanJ.classList.add('backup-spanTCABJX' + classAppendNewFreshSpace);
                    spanJ.textContent = 'J';
                    spanJ.style.marginRight = '3px';
                    if (!newFreshSpace) {
                        spanJ.style.lineHeight = '16px';
                    }
                    spanJ.addEventListener('click', () => {
                        try {
                            GM_openInTab(`https://${settings.getFromJijidownURL}/video/${AVBVTitle.BV}`, { active: true, insert: false, setParent: true });
                            if (enableDebug) {
                                GM_openInTab(`https://${settings.getFromJijidownURL}/api/v1/video_bv/get_info?id=${AVBVTitle.BV.slice(2)}`, { insert: false, setParent: true });
                                GM_openInTab(`https://${settings.getFromJijidownURL}/api/v1/video_bv/get_download_info?id=${AVBVTitle.BV.slice(2)}`, { insert: false, setParent: true });
                            }
                        } catch (error) {
                            catchUnknownError(error);
                        }
                    });
                    divTCABJX.appendChild(spanJ);

                    const spanB = document.createElement('span');
                    spanB.classList.add('backup-spanTCABJX' + classAppendNewFreshSpace);
                    spanB.textContent = 'B';
                    spanB.style.marginRight = '3px';
                    if (!newFreshSpace) {
                        spanB.style.lineHeight = '16px';
                    }
                    spanB.addEventListener('click', () => {
                        try {
                            GM_openInTab(`https://www.biliplus.com/video/${AVBVTitle.BV}`, { active: true, insert: false, setParent: true });
                            if (enableDebug) {
                                if (AVBVTitle.AV) {
                                    GM_openInTab(`https://www.biliplus.com/api/view?id=${AVBVTitle.AV}`, { insert: false, setParent: true });
                                } else {
                                    GM_openInTab(`https://www.biliplus.com/api/view?id=${AVBVTitle.BV}`, { insert: false, setParent: true });
                                }
                            }
                        } catch (error) {
                            catchUnknownError(error);
                        }
                    });
                    divTCABJX.appendChild(spanB);

                    const spanA = document.createElement('span');
                    spanA.classList.add('backup-spanTCABJX' + classAppendNewFreshSpace);
                    spanA.textContent = 'A';
                    spanA.style.marginRight = '3px';
                    if (!newFreshSpace) {
                        spanA.style.lineHeight = '16px';
                    }
                    spanA.addEventListener('click', async () => {
                        try {
                            GM_openInTab(`https://api.bilibili.com/x/web-interface/view?bvid=${AVBVTitle.BV}`, { active: true, insert: false, setParent: true });
                            if (enableDebug) {
                                GM_openInTab(`https://api.bilibili.com/x/web-interface/archive/desc?bvid=${AVBVTitle.BV}`, { insert: false, setParent: true });
                                if (AVBVTitle.AV) {
                                    GM_openInTab(`https://api.bilibili.com/x/v3/fav/resource/infos?resources=${AVBVTitle.AV}%3A2&platform=web&folder_id=${fid}`, { insert: false, setParent: true });
                                }
                                GM_openInTab(await appendParamsForGetFromApi(fid, ((pageNumber - 1) * pageSize + index + 1), 1), { insert: false, setParent: true });
                            }
                        } catch (error) {
                            catchUnknownError(error);
                        }
                    });
                    divTCABJX.appendChild(spanA);

                    const backup = GM_getValue(AVBVTitle.BV, {
                        BV: null,
                        AV: null,
                        title: null,
                        intro: null,
                        cover: null,
                        upperUID: null,
                        upperName: null,
                        upperAvatar: null,
                        timeUpload: null,
                        timePublish: null,
                        timeFavorite: null,
                        dynamic: null,
                        pages: null,
                        api: null,
                        apiExtra: null,
                        biliplus: null,
                        jijidown: null,
                        jijidownExtra: null,
                        xbeibeix: null,
                        // preferredTitle: null,
                        // preferredCover: null,
                    });

                    if (!backup.BV) {
                        backup.BV = AVBVTitle.BV;
                        // backup.AV = AVBVTitle.AV;
                        GM_setValue(AVBVTitle.BV, backup);
                    }

                    AVBVTitle.AV = backup.AV;

                    if (updateTimeFavoriteInBackup(backup, undefined, fid)) {
                        GM_setValue(AVBVTitle.BV, backup);
                    }

                    ///////////////////////////////////////////////////////////////////////////////////
                    // v9
                    if (backup.timeFavorite) {
                        let modified = false;
                        backup.timeFavorite.forEach(el => {
                            if (typeof el.fid === 'string') {
                                el.fid = parseInt(el.fid, 10);
                                modified = true;
                            }
                        });
                        if (modified) {
                            GM_setValue(AVBVTitle.BV, backup);
                        }
                    }
                    // v9
                    if (backup.timeUpload && typeof backup.timeUpload === 'object') {
                        if (backup.timeUpload.length === 1) {
                            backup.timeUpload = backup.timeUpload[0].value;
                        } else {
                            backup.timeUpload = null;
                        }
                        GM_setValue(AVBVTitle.BV, backup);
                    }
                    // v9
                    if (backup.timePublish && typeof backup.timePublish === 'object') {
                        if (backup.timePublish.length === 1) {
                            backup.timePublish = backup.timePublish[0].value;
                        } else {
                            backup.timePublish = null;
                        }
                        GM_setValue(AVBVTitle.BV, backup);
                    }
                    // v10
                    if (backup.hasOwnProperty('jiji')) {
                        backup.jijidown = backup.jiji;
                        delete backup.jiji;
                        GM_setValue(AVBVTitle.BV, backup);
                    }
                    // v10
                    if (backup.hasOwnProperty('bbdownloader')) {
                        backup.xbeibeix = backup.bbdownloader;
                        delete backup.bbdownloader;
                        GM_setValue(AVBVTitle.BV, backup);
                    }
                    // v12
                    ['cover', 'upperAvatar'].forEach(key => {
                        if (backup[key] && backup[key].length > 1) {
                            const tempBackup = {};
                            backup[key].forEach(el => {
                                updateArrayDataInBackup(tempBackup, key, el.value, el.ts, el.from);
                            });
                            backup[key] = tempBackup[key];
                            GM_setValue(AVBVTitle.BV, backup);
                        }
                    });
                    // v14
                    if (backup.hasOwnProperty('firstFrame')) {
                        delete backup.firstFrame;
                        GM_setValue(AVBVTitle.BV, backup);
                    }
                    // v16
                    if (backup.intro) {
                        const tempBackup = { intro: null };
                        backup.intro.forEach(el => {
                            updateArrayDataInBackup(tempBackup, 'intro', el.value, el.ts, el.from);
                        });
                        backup.intro = tempBackup.intro;
                        GM_setValue(AVBVTitle.BV, backup);
                    }
                    ///////////////////////////////////////////////////////////////////////////////////

                    const functions = [];

                    try {

                        if (newFreshSpace) {
                            if (backup.timePublish) {
                                spanFavTime.textContent = `投稿于:${formatTsTimePublish(backup.timePublish * 1000)}`;
                                spanFavTime.setAttribute('title', new Date(backup.timePublish * 1000).toLocaleString());
                            }

                        } else {
                            if (backup.timeFavorite) {
                                const target = backup.timeFavorite.find(el => el.fid === fid);
                                if (target) {
                                    spanFavTime.textContent = `收藏于:${formatTsTimeFavorite(new Date(target.value * 1000))}`;
                                    spanFavTime.setAttribute('title', new Date(target.value * 1000).toLocaleString());
                                }
                            }
                        }

                        if (settings.enableGetFromApi) {
                            if (!backup.api || (!settings.advancedDisableUpdateGetFromApi && getCurrentTs() - backup.api.ts > 3600 * settings.advancedIntervalGetFromApi)) {
                                const skip = await getFromApi(AVBVTitle, backup, spanA, apiDetails, fid, pageNumber, disabled, spanFavTime);
                                if (skip) {
                                    continue;
                                }

                            } else {
                                spanA.style.color = backup.api.value ? '#00ff00' : '#ff0000';
                                if (apiDetails.value) {
                                    const apiDetail = apiDetails.value.find(el => el.bvid === AVBVTitle.BV);
                                    if (apiDetail) {
                                        if (updateTimeFavoriteInBackup(backup, apiDetail.fav_time, fid)) {
                                            GM_setValue(AVBVTitle.BV, backup);
                                        }
                                    }
                                }
                            }
                        }

                        if (settings.enableGetFromApiExtra) {
                            if (!backup.apiExtra || (!settings.advancedDisableUpdateGetFromApiExtra && getCurrentTs() - backup.apiExtra.ts > 3600 * 24 * settings.advancedIntervalGetFromApiExtra)) {
                                await getFromApiExtra(AVBVTitle, backup, spanA, disabled);

                            } else {
                                spanA.style.color = backup.apiExtra.value ? '#008000' : '#800000';
                            }
                        }

                        if (settings.enableGetFromJijidown) {
                            if (!backup.jijidown || (!settings.advancedDisableUpdateGetFromJijidown && getCurrentTs() - backup.jijidown.ts > 3600 * 24 * 7 * settings.advancedIntervalGetFromJijidown)) {
                                functions.push(getFromJijidown(AVBVTitle, backup, spanJ));

                            } else {
                                if (settings.enableGetFromJijidownExtra) {
                                    if (!backup.jijidownExtra || (!settings.advancedDisableUpdateGetFromJijidownExtra && getCurrentTs() - backup.jijidownExtra.ts > 3600 * 24 * 7 * settings.advancedIntervalGetFromJijidownExtra)) {
                                        functions.push(getFromJijidown(AVBVTitle, backup, spanJ));
                                    } else {
                                        spanJ.style.color = backup.jijidownExtra.value ? '#008000' : '#800000';
                                    }
                                } else {
                                    spanJ.style.color = backup.jijidown.value ? '#00ff00' : '#ff0000';
                                }
                            }
                        }

                        if (settings.enableGetFromXbeibeix) {
                            if (!backup.xbeibeix || (!settings.advancedDisableUpdateGetFromXbeibeix && getCurrentTs() - backup.xbeibeix.ts > 3600 * 24 * 7 * settings.advancedIntervalGetFromXbeibeix)) {
                                functions.push(getFromXbeibeix(AVBVTitle, backup, spanX));

                            } else {
                                spanX.style.color = backup.xbeibeix.value ? '#00ff00' : '#ff0000';
                            }
                        }

                        if (settings.enableGetFromBiliplus) {
                            if (!backup.biliplus || (!settings.advancedDisableUpdateGetFromBiliplus && getCurrentTs() - backup.biliplus.ts > 3600 * 24 * 7 * settings.advancedIntervalGetFromBiliplus)) {
                                functions.push(getFromBiliplus(AVBVTitle, backup, spanB));

                            } else {
                                spanB.style.color = backup.biliplus.value ? '#00ff00' : '#ff0000';
                            }
                        }

                        if (functions.length) {
                            if (controller.signal.aborted) {
                                throw new DOMException('', 'AbortError');
                            }
                            await Promise.all(functions);
                            const sortedBackup = {};
                            for (const sortedKey of sortedKeys) {
                                sortedBackup[sortedKey] = backup[sortedKey];
                            }
                            GM_setValue(AVBVTitle.BV, sortedBackup);
                            if (enableDebug) console.log('保存第三方网站的数据至本地');
                            if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
                            if (enableDebug) console.debug(sortedBackup);
                        }

                    } catch (error) {
                        if (error instanceof Error) {
                            if (error.name === 'AbortError') {
                                throw error;
                            }

                            addMessage('发生未知错误, 请反馈该问题', false, true);
                            addMessage(`收藏夹fid: ${fid}`, true);
                            addMessage(`位置: 第${pageNumber}页的第${index + 1}个`, true);
                            addMessageAVBVTitle(AVBVTitle);
                            addMessage(error.stack, true);

                            console.error(`收藏夹fid: ${fid}`);
                            console.error(`位置: 第${pageNumber}页的第${index + 1}个`);
                            consoleAVBVTitle('error', AVBVTitle);
                            console.error(error);
                            if (as[1]) {
                                as[1].style.color = '#ff0000';
                            }

                        } else {
                            addMessage(error[0], false, true);
                            for (let i = 1; i < error.length; i++) {
                                addMessage(error[i], true);
                            }
                            addMessage(`收藏夹fid: ${fid}`, true);
                            addMessage(`位置: 第${pageNumber}页的第${index + 1}个`, true);
                            addMessageAVBVTitle(AVBVTitle);
                            if (as[1]) {
                                as[1].style.color = '#ff0000';
                            }
                        }
                    }

                    let picture;
                    let sourceAvif;
                    let sourceWebp;
                    let img;

                    if (newFreshSpace) {
                        img = video.querySelector('img');
                    } else {
                        picture = video.querySelector('picture');
                        sourceAvif = picture.querySelector('source[type="image/avif"]');
                        sourceWebp = picture.querySelector('source[type="image/webp"]');
                        img = picture.querySelector('img');
                    }

                    if (disabled) {
                        // video.style.opacity = '0.7';

                        if (newFreshSpace) {
                            as[2].style.textDecoration = 'line-through';
                            as[2].style.opacity = '0.7';

                            if (backup.cover) {
                                img.setAttribute('src', `//${backup.cover[backup.cover.length - 1].value}@672w_378h_1c.avif`);
                            }

                        } else {
                            video.classList.remove('disabled');
                            as[0].classList.remove('disabled');

                            as[0].setAttribute('href', `//www.bilibili.com/video/${AVBVTitle.BV}/`);
                            as[0].setAttribute('target', '_blank');
                            as[1].setAttribute('target', '_blank');
                            as[1].setAttribute('href', `//www.bilibili.com/video/${AVBVTitle.BV}/`);

                            if (backup.cover) {
                                sourceAvif.setAttribute('srcset', `//${backup.cover[backup.cover.length - 1].value}@320w_200h_1c_!web-space-favlist-video.avif`);
                                sourceWebp.setAttribute('srcset', `//${backup.cover[backup.cover.length - 1].value}@320w_200h_1c_!web-space-favlist-video.webp`);
                                img.setAttribute('src', `//${backup.cover[backup.cover.length - 1].value}@320w_200h_1c_!web-space-favlist-video.webp`);
                            }
                        }

                        spanFavTime.style.textDecoration = 'line-through';
                        spanFavTime.style.opacity = '0.7';

                        as[1].style.textDecoration = 'line-through';
                        as[1].style.opacity = '0.5';

                        if (backup.title) {
                            as[1].textContent = backup.title[backup.title.length - 1].value;
                            img.setAttribute('alt', backup.title[backup.title.length - 1].value);
                            if (newFreshSpace) {
                                divTitleNewFreshSpace.setAttribute('title', backup.title[backup.title.length - 1].value);
                            } else {
                                as[1].setAttribute('title', backup.title[backup.title.length - 1].value);
                            }
                        }
                    }

                    if (backup.cover && backup.cover.length > 1) {

                        const spanC = document.createElement('span');
                        spanC.classList.add('backup-spanTCABJX' + classAppendNewFreshSpace);
                        spanC.textContent = 'C';
                        spanC.style.marginRight = '3px';
                        spanC.style.color = '#000000';
                        if (!newFreshSpace) {
                            spanC.style.lineHeight = '16px';
                        }
                        let i = backup.cover.length - 2;
                        spanC.addEventListener('click', () => {
                            try {
                                if (i < 0) {
                                    i = backup.cover.length - 1;
                                }

                                if (newFreshSpace) {
                                    img.setAttribute('src', `//${backup.cover[i].value}@672w_378h_1c.avif`);
                                } else {
                                    sourceAvif.setAttribute('srcset', `//${backup.cover[i].value}@320w_200h_1c_!web-space-favlist-video.avif`);
                                    sourceWebp.setAttribute('srcset', `//${backup.cover[i].value}@320w_200h_1c_!web-space-favlist-video.webp`);
                                    img.setAttribute('src', `//${backup.cover[i].value}@320w_200h_1c_!web-space-favlist-video.webp`);
                                }

                                if (i !== backup.cover.length - 1) {
                                    spanC.style.color = '#999999';
                                } else {
                                    spanC.style.color = '#000000';
                                }

                                i--;

                            } catch (error) {
                                catchUnknownError(error);
                            }
                        });
                        divTCABJX.appendChild(spanC);
                    }

                    if (backup.title && backup.title.length > 1) {

                        const spanT = document.createElement('span');
                        spanT.classList.add('backup-spanTCABJX' + classAppendNewFreshSpace);
                        spanT.textContent = 'T';
                        spanT.style.marginRight = '3px';
                        spanT.style.color = '#000000';
                        if (!newFreshSpace) {
                            spanT.style.lineHeight = '16px';
                        }
                        let i = backup.title.length - 2;
                        spanT.addEventListener('click', () => {
                            try {
                                if (i < 0) {
                                    i = backup.title.length - 1;
                                }

                                as[1].textContent = backup.title[i].value;

                                if (newFreshSpace) {
                                    divTitleNewFreshSpace.setAttribute('title', backup.title[i].value);
                                } else {
                                    as[1].setAttribute('title', backup.title[i].value);
                                }

                                if (i !== backup.title.length - 1) {
                                    spanT.style.color = '#999999';
                                } else {
                                    spanT.style.color = '#000000';
                                }

                                i--;

                            } catch (error) {
                                catchUnknownError(error);
                            }
                        });
                        divTCABJX.appendChild(spanT);
                    }

                    if (controller.signal.aborted) {
                        throw new DOMException('', 'AbortError');
                    }

                    if (!newFreshSpace) {
                        const ul = video.querySelector('ul.be-dropdown-menu');
                        if (ul) {
                            appendDropdowns(ul, AVBVTitle.BV);
                        }
                    }

                    if (functions.length === 1) {
                        await delay(200);
                    }

                } catch (error) {
                    if (error instanceof Error) {
                        if (error.name === 'AbortError') {
                            throw error;
                        }

                        addMessage('发生未知错误, 请反馈该问题', false, true);
                        addMessage(`收藏夹fid: ${fid}`, true);
                        addMessage(`位置: 第${pageNumber}页的第${index + 1}个`, true);
                        addMessageAVBVTitle(AVBVTitle);
                        addMessage(error.stack, true);

                        console.error(`收藏夹fid: ${fid}`);
                        console.error(`位置: 第${pageNumber}页的第${index + 1}个`);
                        consoleAVBVTitle('error', AVBVTitle);
                        console.error(error);
                        if (as[1]) {
                            as[1].style.color = '#ff0000';
                        }

                    } else {
                        addMessage(error[0], false, true);
                        for (let i = 1; i < error.length; i++) {
                            addMessage(error[i], true);
                        }
                        addMessage(`收藏夹fid: ${fid}`, true);
                        addMessage(`位置: 第${pageNumber}页的第${index + 1}个`, true);
                        addMessageAVBVTitle(AVBVTitle);
                        if (as[1]) {
                            as[1].style.color = '#ff0000';
                        }
                    }
                }
            }

            if (enableAutoNextPage) {
                if (newFreshSpace) {
                    const pager = Array.from(document.querySelectorAll('button.vui_pagenation--btn-side')).find(el => el.innerText === '下一页');
                    if (pager && !pager.classList.contains('vui_button--disabled')) {
                        await delay(1000 * settings.advancedIntervalAutoNextPage);
                        if (controller.signal.aborted) {
                            throw new DOMException('', 'AbortError');
                        }
                        if (enableAutoNextPage) {
                            pager.click();
                        }
                    }

                } else {
                    const pager = document.querySelector('li.be-pager-next');
                    if (pager && !pager.classList.contains('be-pager-disabled')) {
                        await delay(1000 * settings.advancedIntervalAutoNextPage);
                        if (controller.signal.aborted) {
                            throw new DOMException('', 'AbortError');
                        }
                        if (enableAutoNextPage) {
                            pager.click();
                        }
                    }
                }
            }

        } catch (error) {
            if (error instanceof Error) {
                if (error.name === 'AbortError') {
                    return;
                }
                catchUnknownError(error);

            } else {
                addMessage(error[0], false, true);
                for (let i = 1; i < error.length; i++) {
                    addMessage(error[i], true);
                }
            }

        } finally {
            activeControllers.delete(controller);
        }
    }

    function initControls() {

        let displayUpdate = false;
        if (settings.version !== version) {
            if (settings.version) {
                displayUpdate = true;
            }
            settings.version = version;
            GM_setValue('settings', settings);
        }

        const style = document.createElement('style');
        style.textContent = `
            .backup-spanTCABJX, .backup-spanTCABJX-newFreshSpace {
                float: right;
                font-weight: bold;
                cursor: pointer;
            }
            .backup-div-first {
                padding: 2px;
            }
            .backup-div-first-newFreshSpace {
                padding: 2px 0;
            }
            .backup-div-second {
                padding: 2px 0 2px 9px;
            }
            .backup-div-second-newFreshSpace {
                padding: 2px 0 2px 8px;
            }
            .backup-div-third {
                padding: 2px 0 2px 16px;
            }
            .backup-div-third-newFreshSpace {
                padding: 2px 0 2px 16px;
            }
            .backup-label, .backup-label-newFreshSpace {
                line-height: 1;
            }
            .backup-disabled, .backup-disabled-newFreshSpace {
                opacity: 0.5;
                pointer-events: none;
            }
            .backup-inputText, .backup-inputText-newFreshSpace {
                box-sizing: content-box;
                border: 1px solid #cccccc;
                padding: 1px 2px;
                line-height: 1;
            }
            .backup-inputText {
                width: 25px;
                height: 14px;
                border-radius: 2px;
                font-size: 14px;
            }
            .backup-inputText-newFreshSpace {
                width: 30px;
                height: 16px;
                border-radius: 3px;
                font-size: 16px;
            }
            .backup-hidden, .backup-hidden-newFreshSpace {
                display: none;
            }
            .backup-button, .backup-button-newFreshSpace {
                border: 1px solid #cccccc;
                line-height: 1;
                cursor: pointer;
            }
            .backup-button {
                border-radius: 2px;
                padding: 2px;
                font-size: 14px;
            }
            .backup-button-newFreshSpace {
                border-radius: 3px;
                padding: 3px;
                font-size: 16px;
            }
            .backup-divMessage, .backup-divMessage-newFreshSpace {
                overflow-y: auto;
                background-color: #eeeeee;
                line-height: 1.5;
                scrollbar-width: none;
            }
            .backup-divMessage {
                margin: 2px;
            }
            .backup-divMessage-heightFixed {
                height: 280px;
            }
            .backup-divMessage::-webkit-scrollbar {
                display: none;
            }
            .backup-divMessage-newFreshSpace {
                margin: 2px 0;
            }
            .backup-divMessage-heightFixed-newFreshSpace {
                height: 320px;
            }
            .backup-divMessage-newFreshSpace::-webkit-scrollbar {
                display: none;
            }
        `;
        document.head.appendChild(style);

        const divSide = document.querySelector(newFreshSpace ? 'div.favlist-aside' : 'div.fav-sidenav');
        if (!newFreshSpace && divSide.querySelector('a.watch-later')) {
            divSide.querySelector('a.watch-later').style.borderBottom = '1px solid #eeeeee';
        }

        const divControls = document.createElement('div');
        divControls.classList.add('backup-div-first' + classAppendNewFreshSpace);
        if (!newFreshSpace) {
            divControls.style.borderTop = '1px solid #e4e9f0';
        }
        divSide.appendChild(divControls);

        const divLabelProcessNormal = document.createElement('div');
        divLabelProcessNormal.classList.add('backup-div-first' + classAppendNewFreshSpace);
        divLabelProcessNormal.setAttribute('title',
            '默认: 开启\n' +
            '由于新视频的BV号随机生成, 各个第三方网站无法自动地爬取新视频的信息。\n' +
            '开启该选项的同时开启下面的从第三方网站获取数据, 脚本将代替您访问相应的第三方网站。\n' +
            '如果处理的视频第三方网站还没有备份, 这将使其备份该视频当前版本的信息。\n' +
            '如果处理的视频之前有人备份过了, 这将获取到该视频的信息备份到第三方网站时的版本。');
        divControls.appendChild(divLabelProcessNormal);

        const labelProcessNormal = document.createElement('label');
        labelProcessNormal.classList.add('backup-label' + classAppendNewFreshSpace);
        labelProcessNormal.textContent = '处理正常视频';
        divLabelProcessNormal.appendChild(labelProcessNormal);

        const checkboxProcessNormal = document.createElement('input');
        checkboxProcessNormal.type = 'checkbox';
        checkboxProcessNormal.checked = settings.processNormal;
        checkboxProcessNormal.addEventListener('change', () => {
            try {
                settings.processNormal = checkboxProcessNormal.checked;
                GM_setValue('settings', settings);
                if (!settings.processNormal && !settings.processDisabled) {
                    divLabelEnableGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelEnableGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromApi) {
                        divLabelAdvancedDisableUpdateGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromApi) {
                            divLabelAdvancedIntervalGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                        divLabelEnableGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (settings.enableGetFromApiExtra) {
                            divLabelAdvancedDisableUpdateGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                            if (!settings.advancedDisableUpdateGetFromApiExtra) {
                                divLabelAdvancedIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                            }
                        }
                    }
                    divLabelEnableGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromBiliplus) {
                        divLabelAdvancedDisableUpdateGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromBiliplus) {
                            divLabelAdvancedIntervalGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                    }
                    divLabelEnableGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromJijidown) {
                        divLabelAdvancedDisableUpdateGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromJijidown) {
                            divLabelAdvancedIntervalGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                        divLabelEnableGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (settings.enableGetFromJijidownExtra) {
                            divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                            if (!settings.advancedDisableUpdateGetFromJijidownExtra) {
                                divLabelAdvancedIntervalGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                            }
                        }
                        divSwitchGetFromJijidownURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        divSwitchGetFromJijidownURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                    divLabelEnableGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromXbeibeix) {
                        divLabelAdvancedDisableUpdateGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromXbeibeix) {
                            divLabelAdvancedIntervalGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                        divSwitchGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        divSwitchGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                }
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelProcessNormal.insertAdjacentElement('afterbegin', checkboxProcessNormal);

        const divLabelProcessDisabled = document.createElement('div');
        divLabelProcessDisabled.classList.add('backup-div-first' + classAppendNewFreshSpace);
        divLabelProcessDisabled.setAttribute('title',
            '默认: 开启\n' +
            '开启该选项的同时开启下面的从第三方网站获取数据, 脚本将尝试从相应的第三方网站获取失效视频的信息。');
        divControls.appendChild(divLabelProcessDisabled);

        const labelProcessDisabled = document.createElement('label');
        labelProcessDisabled.classList.add('backup-label' + classAppendNewFreshSpace);
        labelProcessDisabled.textContent = '处理失效视频';
        divLabelProcessDisabled.appendChild(labelProcessDisabled);

        const checkboxProcessDisabled = document.createElement('input');
        checkboxProcessDisabled.type = 'checkbox';
        checkboxProcessDisabled.checked = settings.processDisabled;
        checkboxProcessDisabled.addEventListener('change', () => {
            try {
                settings.processDisabled = checkboxProcessDisabled.checked;
                GM_setValue('settings', settings);
                if (!settings.processNormal && !settings.processDisabled) {
                    divLabelEnableGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelEnableGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromApi) {
                        divLabelAdvancedDisableUpdateGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromApi) {
                            divLabelAdvancedIntervalGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                        divLabelEnableGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (settings.enableGetFromApiExtra) {
                            divLabelAdvancedDisableUpdateGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                            if (!settings.advancedDisableUpdateGetFromApiExtra) {
                                divLabelAdvancedIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                            }
                        }
                    }
                    divLabelEnableGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromBiliplus) {
                        divLabelAdvancedDisableUpdateGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromBiliplus) {
                            divLabelAdvancedIntervalGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                    }
                    divLabelEnableGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromJijidown) {
                        divLabelAdvancedDisableUpdateGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromJijidown) {
                            divLabelAdvancedIntervalGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                        divLabelEnableGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (settings.enableGetFromJijidownExtra) {
                            divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                            if (!settings.advancedDisableUpdateGetFromJijidownExtra) {
                                divLabelAdvancedIntervalGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                            }
                        }
                        divSwitchGetFromJijidownURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        divSwitchGetFromJijidownURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                    divLabelEnableGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromXbeibeix) {
                        divLabelAdvancedDisableUpdateGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromXbeibeix) {
                            divLabelAdvancedIntervalGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                        divSwitchGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        divSwitchGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                }
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelProcessDisabled.insertAdjacentElement('afterbegin', checkboxProcessDisabled);

        const divLabelEnableGetFromApi = document.createElement('div');
        divLabelEnableGetFromApi.classList.add('backup-div-second' + classAppendNewFreshSpace);
        divLabelEnableGetFromApi.setAttribute('title',
            '默认: 开启\n' +
            '地址: https://api.bilibili.com/x/v3/fav/resource/list?media_id={收藏夹fid}&pn={页码}&ps={每页展示视频数量}\n' +
            '数据: AV号, 标题 (失效视频无法获取), 简介 (仅能获取前255个字符), 封面地址 (失效视频无法获取), UP主UID, UP主昵称, UP主头像地址, 上传时间, 发布时间, 添加到当前收藏夹的时间 (均为最新版本)\n' +
            '地址: https://api.bilibili.com/x/web-interface/archive/desc?bvid={BV号}\n' +
            '数据: 完整简介 (最新版本, 非必要不会调用该接口)');
        divControls.appendChild(divLabelEnableGetFromApi);

        const labelEnableGetFromApi = document.createElement('label');
        labelEnableGetFromApi.classList.add('backup-label' + classAppendNewFreshSpace);
        labelEnableGetFromApi.textContent = '从B站接口获取数据';
        divLabelEnableGetFromApi.appendChild(labelEnableGetFromApi);

        const checkboxEnableGetFromApi = document.createElement('input');
        checkboxEnableGetFromApi.type = 'checkbox';
        checkboxEnableGetFromApi.checked = settings.enableGetFromApi;
        checkboxEnableGetFromApi.addEventListener('change', () => {
            try {
                settings.enableGetFromApi = checkboxEnableGetFromApi.checked;
                if (!settings.enableGetFromApi) {
                    settings.enableGetFromApiExtra = false;
                    checkboxEnableGetFromApiExtra.checked = false;
                    divLabelAdvancedDisableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedDisableUpdateGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (!settings.advancedDisableUpdateGetFromApi) {
                        divLabelAdvancedIntervalGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                    divLabelEnableGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromApiExtra) {
                        divLabelAdvancedDisableUpdateGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromApiExtra) {
                            divLabelAdvancedIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                    }
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelEnableGetFromApi.insertAdjacentElement('afterbegin', checkboxEnableGetFromApi);

        const divLabelAdvancedDisableUpdateGetFromApi = document.createElement('div');
        divLabelAdvancedDisableUpdateGetFromApi.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedDisableUpdateGetFromApi.setAttribute('title',
            '默认: 关闭\n' +
            '开启后每个视频从B站接口只会获取一次数据。\n' +
            '不建议开启, 因为某些视频的信息可能会经常更新。');
        divControls.appendChild(divLabelAdvancedDisableUpdateGetFromApi);

        const labelAdvancedDisableUpdateGetFromApi = document.createElement('label');
        labelAdvancedDisableUpdateGetFromApi.classList.add('backup-label' + classAppendNewFreshSpace);
        labelAdvancedDisableUpdateGetFromApi.textContent = '禁用更新';
        divLabelAdvancedDisableUpdateGetFromApi.appendChild(labelAdvancedDisableUpdateGetFromApi);

        const checkboxAdvancedDisableUpdateGetFromApi = document.createElement('input');
        checkboxAdvancedDisableUpdateGetFromApi.type = 'checkbox';
        checkboxAdvancedDisableUpdateGetFromApi.checked = settings.advancedDisableUpdateGetFromApi;
        checkboxAdvancedDisableUpdateGetFromApi.addEventListener('change', () => {
            try {
                settings.advancedDisableUpdateGetFromApi = checkboxAdvancedDisableUpdateGetFromApi.checked;
                if (settings.advancedDisableUpdateGetFromApi) {
                    divLabelAdvancedIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedIntervalGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelAdvancedDisableUpdateGetFromApi.insertAdjacentElement('afterbegin', checkboxAdvancedDisableUpdateGetFromApi);

        const divLabelAdvancedIntervalGetFromApi = document.createElement('div');
        divLabelAdvancedIntervalGetFromApi.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedIntervalGetFromApi.setAttribute('title',
            '默认: 5小时\n' +
            '脚本处理某个视频时, 如果发现距离上次从B站接口获取到该视频的数据已经超过了设定的时间间隔, 则会再次从B站接口获取该视频的数据。');
        divControls.appendChild(divLabelAdvancedIntervalGetFromApi);

        const labelAdvancedIntervalGetFromApi = document.createElement('label');
        labelAdvancedIntervalGetFromApi.classList.add('backup-label' + classAppendNewFreshSpace);
        divLabelAdvancedIntervalGetFromApi.appendChild(labelAdvancedIntervalGetFromApi);

        const inputTextAdvancedIntervalGetFromApi = document.createElement('input');
        inputTextAdvancedIntervalGetFromApi.type = 'text';
        inputTextAdvancedIntervalGetFromApi.classList.add('backup-inputText' + classAppendNewFreshSpace);
        inputTextAdvancedIntervalGetFromApi.value = settings.advancedIntervalGetFromApi;
        inputTextAdvancedIntervalGetFromApi.setAttribute('backup-def', 5);
        inputTextAdvancedIntervalGetFromApi.setAttribute('backup-min', 1);
        inputTextAdvancedIntervalGetFromApi.setAttribute('backup-max', 100);
        inputTextAdvancedIntervalGetFromApi.setAttribute('backup-setting', 'advancedIntervalGetFromApi');
        inputTextAdvancedIntervalGetFromApi.addEventListener('blur', validateInputText);

        labelAdvancedIntervalGetFromApi.appendChild(document.createTextNode('最小更新间隔'))
        labelAdvancedIntervalGetFromApi.appendChild(inputTextAdvancedIntervalGetFromApi);
        labelAdvancedIntervalGetFromApi.appendChild(document.createTextNode('小时'));

        const divLabelEnableGetFromApiExtra = document.createElement('div');
        divLabelEnableGetFromApiExtra.classList.add('backup-div-second' + classAppendNewFreshSpace);
        divLabelEnableGetFromApiExtra.setAttribute('title',
            '默认: 关闭\n' +
            '地址: https://api.bilibili.com/x/web-interface/view?bvid={BV号}\n' +
            '数据: 完整简介, 视频发布动态内容, 每个分集的标题, 第1帧截图地址 (旧视频无法获取), cid (均为最新版本, 失效视频均无法获取, 不会调用该接口)');
        divControls.appendChild(divLabelEnableGetFromApiExtra);

        const labelEnableGetFromApiExtra = document.createElement('label');
        labelEnableGetFromApiExtra.classList.add('backup-label' + classAppendNewFreshSpace);
        labelEnableGetFromApiExtra.textContent = '从B站接口获取额外数据';
        divLabelEnableGetFromApiExtra.appendChild(labelEnableGetFromApiExtra);

        const checkboxEnableGetFromApiExtra = document.createElement('input');
        checkboxEnableGetFromApiExtra.type = 'checkbox';
        checkboxEnableGetFromApiExtra.checked = settings.enableGetFromApiExtra;
        checkboxEnableGetFromApiExtra.addEventListener('change', () => {
            try {
                settings.enableGetFromApiExtra = checkboxEnableGetFromApiExtra.checked;
                if (!settings.enableGetFromApiExtra) {
                    divLabelAdvancedDisableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedDisableUpdateGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (!settings.advancedDisableUpdateGetFromApiExtra) {
                        divLabelAdvancedIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelEnableGetFromApiExtra.insertAdjacentElement('afterbegin', checkboxEnableGetFromApiExtra);

        const divLabelAdvancedDisableUpdateGetFromApiExtra = document.createElement('div');
        divLabelAdvancedDisableUpdateGetFromApiExtra.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedDisableUpdateGetFromApiExtra.setAttribute('title',
            '默认: 关闭\n' +
            '不建议开启, 因为某些视频的信息可能会经常更新。');
        divControls.appendChild(divLabelAdvancedDisableUpdateGetFromApiExtra);

        const labelAdvancedDisableUpdateGetFromApiExtra = document.createElement('label');
        labelAdvancedDisableUpdateGetFromApiExtra.classList.add('backup-label' + classAppendNewFreshSpace);
        labelAdvancedDisableUpdateGetFromApiExtra.textContent = '禁用更新';
        divLabelAdvancedDisableUpdateGetFromApiExtra.appendChild(labelAdvancedDisableUpdateGetFromApiExtra);

        const checkboxAdvancedDisableUpdateGetFromApiExtra = document.createElement('input');
        checkboxAdvancedDisableUpdateGetFromApiExtra.type = 'checkbox';
        checkboxAdvancedDisableUpdateGetFromApiExtra.checked = settings.advancedDisableUpdateGetFromApiExtra;
        checkboxAdvancedDisableUpdateGetFromApiExtra.addEventListener('change', () => {
            try {
                settings.advancedDisableUpdateGetFromApiExtra = checkboxAdvancedDisableUpdateGetFromApiExtra.checked;
                if (settings.advancedDisableUpdateGetFromApiExtra) {
                    divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelAdvancedDisableUpdateGetFromApiExtra.insertAdjacentElement('afterbegin', checkboxAdvancedDisableUpdateGetFromApiExtra);

        const divLabelAdvancedIntervalGetFromApiExtra = document.createElement('div');
        divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedIntervalGetFromApiExtra.setAttribute('title',
            '默认: 5天');
        divControls.appendChild(divLabelAdvancedIntervalGetFromApiExtra);

        const labelAdvancedIntervalGetFromApiExtra = document.createElement('label');
        labelAdvancedIntervalGetFromApiExtra.classList.add('backup-label' + classAppendNewFreshSpace);
        divLabelAdvancedIntervalGetFromApiExtra.appendChild(labelAdvancedIntervalGetFromApiExtra);

        const inputTextAdvancedIntervalGetFromApiExtra = document.createElement('input');
        inputTextAdvancedIntervalGetFromApiExtra.type = 'text';
        inputTextAdvancedIntervalGetFromApiExtra.classList.add('backup-inputText' + classAppendNewFreshSpace);
        inputTextAdvancedIntervalGetFromApiExtra.value = settings.advancedIntervalGetFromApiExtra;
        inputTextAdvancedIntervalGetFromApiExtra.setAttribute('backup-def', 5);
        inputTextAdvancedIntervalGetFromApiExtra.setAttribute('backup-min', 1);
        inputTextAdvancedIntervalGetFromApiExtra.setAttribute('backup-max', 100);
        inputTextAdvancedIntervalGetFromApiExtra.setAttribute('backup-setting', 'advancedIntervalGetFromApiExtra');
        inputTextAdvancedIntervalGetFromApiExtra.addEventListener('blur', validateInputText);

        labelAdvancedIntervalGetFromApiExtra.appendChild(document.createTextNode('最小更新间隔'))
        labelAdvancedIntervalGetFromApiExtra.appendChild(inputTextAdvancedIntervalGetFromApiExtra);
        labelAdvancedIntervalGetFromApiExtra.appendChild(document.createTextNode('天'));

        const divLabelEnableGetFromBiliplus = document.createElement('div');
        divLabelEnableGetFromBiliplus.classList.add('backup-div-second' + classAppendNewFreshSpace);
        divLabelEnableGetFromBiliplus.setAttribute('title',
            '默认: 开启\n' +
            '地址: https://www.biliplus.com/video/{BV号}\n' +
            '数据: 标题, 简介, 封面地址, UP主昵称, UP主头像地址, 视频发布动态内容, 每个分集的标题, 第1帧截图地址 (旧视频无法获取), cid (均为备份时的版本)\n' +
            '部分视频BiliPlus无法备份, 可能的原因是其备份每个视频的信息较其他第三方网站更为丰富, 而某些信息从B站获取有一定的限制条件。');
        divControls.appendChild(divLabelEnableGetFromBiliplus);

        const labelEnableGetFromBiliplus = document.createElement('label');
        labelEnableGetFromBiliplus.classList.add('backup-label' + classAppendNewFreshSpace);
        labelEnableGetFromBiliplus.textContent = '从BiliPlus获取数据';
        divLabelEnableGetFromBiliplus.appendChild(labelEnableGetFromBiliplus);

        const checkboxEnableGetFromBiliplus = document.createElement('input');
        checkboxEnableGetFromBiliplus.type = 'checkbox';
        checkboxEnableGetFromBiliplus.checked = settings.enableGetFromBiliplus;
        checkboxEnableGetFromBiliplus.addEventListener('change', () => {
            try {
                settings.enableGetFromBiliplus = checkboxEnableGetFromBiliplus.checked;
                if (!settings.enableGetFromBiliplus) {
                    divLabelAdvancedDisableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedDisableUpdateGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (!settings.advancedDisableUpdateGetFromBiliplus) {
                        divLabelAdvancedIntervalGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelEnableGetFromBiliplus.insertAdjacentElement('afterbegin', checkboxEnableGetFromBiliplus);

        const divLabelAdvancedDisableUpdateGetFromBiliplus = document.createElement('div');
        divLabelAdvancedDisableUpdateGetFromBiliplus.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedDisableUpdateGetFromBiliplus.setAttribute('title',
            '默认: 开启');
        divControls.appendChild(divLabelAdvancedDisableUpdateGetFromBiliplus);

        const labelAdvancedDisableUpdateGetFromBiliplus = document.createElement('label');
        labelAdvancedDisableUpdateGetFromBiliplus.classList.add('backup-label' + classAppendNewFreshSpace);
        labelAdvancedDisableUpdateGetFromBiliplus.textContent = '禁用更新';
        divLabelAdvancedDisableUpdateGetFromBiliplus.appendChild(labelAdvancedDisableUpdateGetFromBiliplus);

        const checkboxAdvancedDisableUpdateGetFromBiliplus = document.createElement('input');
        checkboxAdvancedDisableUpdateGetFromBiliplus.type = 'checkbox';
        checkboxAdvancedDisableUpdateGetFromBiliplus.checked = settings.advancedDisableUpdateGetFromBiliplus;
        checkboxAdvancedDisableUpdateGetFromBiliplus.addEventListener('change', () => {
            try {
                settings.advancedDisableUpdateGetFromBiliplus = checkboxAdvancedDisableUpdateGetFromBiliplus.checked;
                if (settings.advancedDisableUpdateGetFromBiliplus) {
                    divLabelAdvancedIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedIntervalGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelAdvancedDisableUpdateGetFromBiliplus.insertAdjacentElement('afterbegin', checkboxAdvancedDisableUpdateGetFromBiliplus);

        const divLabelAdvancedIntervalGetFromBiliplus = document.createElement('div');
        divLabelAdvancedIntervalGetFromBiliplus.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedIntervalGetFromBiliplus.setAttribute('title',
            '默认: 10星期');
        divControls.appendChild(divLabelAdvancedIntervalGetFromBiliplus);

        const labelAdvancedIntervalGetFromBiliplus = document.createElement('label');
        labelAdvancedIntervalGetFromBiliplus.classList.add('backup-label' + classAppendNewFreshSpace);
        divLabelAdvancedIntervalGetFromBiliplus.appendChild(labelAdvancedIntervalGetFromBiliplus);

        const inputTextAdvancedIntervalGetFromBiliplus = document.createElement('input');
        inputTextAdvancedIntervalGetFromBiliplus.type = 'text';
        inputTextAdvancedIntervalGetFromBiliplus.classList.add('backup-inputText' + classAppendNewFreshSpace);
        inputTextAdvancedIntervalGetFromBiliplus.value = settings.advancedIntervalGetFromBiliplus;
        inputTextAdvancedIntervalGetFromBiliplus.setAttribute('backup-def', 10);
        inputTextAdvancedIntervalGetFromBiliplus.setAttribute('backup-min', 1);
        inputTextAdvancedIntervalGetFromBiliplus.setAttribute('backup-max', 100);
        inputTextAdvancedIntervalGetFromBiliplus.setAttribute('backup-setting', 'advancedIntervalGetFromBiliplus');
        inputTextAdvancedIntervalGetFromBiliplus.addEventListener('blur', validateInputText);

        labelAdvancedIntervalGetFromBiliplus.appendChild(document.createTextNode('最小更新间隔'))
        labelAdvancedIntervalGetFromBiliplus.appendChild(inputTextAdvancedIntervalGetFromBiliplus);
        labelAdvancedIntervalGetFromBiliplus.appendChild(document.createTextNode('星期'));

        const divLabelEnableGetFromJijidown = document.createElement('div');
        divLabelEnableGetFromJijidown.classList.add('backup-div-second' + classAppendNewFreshSpace);
        divLabelEnableGetFromJijidown.setAttribute('title',
            '默认: 关闭\n' +
            '唧唧的服务器尚不稳定, 从唧唧获取数据时可能会出现问题。\n' +
            '地址: https://www.jijidown.com/api/v1/video_bv/get_info?id={BV号后10位}\n' +
            '或 https://www.jiji.moe/api/v1/video_bv/get_info?id={BV号后10位} (取决于下面的单选项)\n' +
            '数据: 标题, 简介, 封面地址, UP主昵称, UP主头像地址 (均为备份时的版本)');
        divControls.appendChild(divLabelEnableGetFromJijidown);

        const labelEnableGetFromJijidown = document.createElement('label');
        labelEnableGetFromJijidown.classList.add('backup-label' + classAppendNewFreshSpace);
        labelEnableGetFromJijidown.textContent = '从唧唧获取数据(不稳定)';
        divLabelEnableGetFromJijidown.appendChild(labelEnableGetFromJijidown);

        const checkboxEnableGetFromJijidown = document.createElement('input');
        checkboxEnableGetFromJijidown.type = 'checkbox';
        checkboxEnableGetFromJijidown.checked = settings.enableGetFromJijidown;
        checkboxEnableGetFromJijidown.addEventListener('change', () => {
            try {
                settings.enableGetFromJijidown = checkboxEnableGetFromJijidown.checked;
                if (!settings.enableGetFromJijidown) {
                    settings.enableGetFromJijidownExtra = false;
                    checkboxEnableGetFromJijidownExtra.checked = false;
                    divLabelAdvancedDisableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedDisableUpdateGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (!settings.advancedDisableUpdateGetFromJijidown) {
                        divLabelAdvancedIntervalGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                    divLabelEnableGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (settings.enableGetFromJijidownExtra) {
                        divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        if (!settings.advancedDisableUpdateGetFromJijidownExtra) {
                            divLabelAdvancedIntervalGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                        }
                    }
                    divSwitchGetFromJijidownURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromJijidownURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelEnableGetFromJijidown.insertAdjacentElement('afterbegin', checkboxEnableGetFromJijidown);

        const divLabelAdvancedDisableUpdateGetFromJijidown = document.createElement('div');
        divLabelAdvancedDisableUpdateGetFromJijidown.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedDisableUpdateGetFromJijidown.setAttribute('title',
            '默认: 开启');
        divControls.appendChild(divLabelAdvancedDisableUpdateGetFromJijidown);

        const labelAdvancedDisableUpdateGetFromJijidown = document.createElement('label');
        labelAdvancedDisableUpdateGetFromJijidown.classList.add('backup-label' + classAppendNewFreshSpace);
        labelAdvancedDisableUpdateGetFromJijidown.textContent = '禁用更新';
        divLabelAdvancedDisableUpdateGetFromJijidown.appendChild(labelAdvancedDisableUpdateGetFromJijidown);

        const checkboxAdvancedDisableUpdateGetFromJijidown = document.createElement('input');
        checkboxAdvancedDisableUpdateGetFromJijidown.type = 'checkbox';
        checkboxAdvancedDisableUpdateGetFromJijidown.checked = settings.advancedDisableUpdateGetFromJijidown;
        checkboxAdvancedDisableUpdateGetFromJijidown.addEventListener('change', () => {
            try {
                settings.advancedDisableUpdateGetFromJijidown = checkboxAdvancedDisableUpdateGetFromJijidown.checked;
                if (settings.advancedDisableUpdateGetFromJijidown) {
                    divLabelAdvancedIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedIntervalGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelAdvancedDisableUpdateGetFromJijidown.insertAdjacentElement('afterbegin', checkboxAdvancedDisableUpdateGetFromJijidown);

        const divLabelAdvancedIntervalGetFromJijidown = document.createElement('div');
        divLabelAdvancedIntervalGetFromJijidown.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedIntervalGetFromJijidown.setAttribute('title',
            '默认: 10星期');
        divControls.appendChild(divLabelAdvancedIntervalGetFromJijidown);

        const labelAdvancedIntervalGetFromJijidown = document.createElement('label');
        labelAdvancedIntervalGetFromJijidown.classList.add('backup-label' + classAppendNewFreshSpace);
        divLabelAdvancedIntervalGetFromJijidown.appendChild(labelAdvancedIntervalGetFromJijidown);

        const inputTextAdvancedIntervalGetFromJijidown = document.createElement('input');
        inputTextAdvancedIntervalGetFromJijidown.type = 'text';
        inputTextAdvancedIntervalGetFromJijidown.classList.add('backup-inputText' + classAppendNewFreshSpace);
        inputTextAdvancedIntervalGetFromJijidown.value = settings.advancedIntervalGetFromJijidown;
        inputTextAdvancedIntervalGetFromJijidown.setAttribute('backup-def', 10);
        inputTextAdvancedIntervalGetFromJijidown.setAttribute('backup-min', 1);
        inputTextAdvancedIntervalGetFromJijidown.setAttribute('backup-max', 100);
        inputTextAdvancedIntervalGetFromJijidown.setAttribute('backup-setting', 'advancedIntervalGetFromJijidown');
        inputTextAdvancedIntervalGetFromJijidown.addEventListener('blur', validateInputText);

        labelAdvancedIntervalGetFromJijidown.appendChild(document.createTextNode('最小更新间隔'))
        labelAdvancedIntervalGetFromJijidown.appendChild(inputTextAdvancedIntervalGetFromJijidown);
        labelAdvancedIntervalGetFromJijidown.appendChild(document.createTextNode('星期'));

        const divLabelEnableGetFromJijidownExtra = document.createElement('div');
        divLabelEnableGetFromJijidownExtra.classList.add('backup-div-second' + classAppendNewFreshSpace);
        divLabelEnableGetFromJijidownExtra.setAttribute('title',
            '默认: 关闭\n' +
            '唧唧的服务器尚不稳定, 从唧唧获取数据时可能会出现问题。\n' +
            '地址: https://www.jijidown.com/api/v1/video_bv/get_download_info?id={BV号后10位}\n' +
            '或 https://www.jiji.moe/api/v1/video_bv/get_download_info?id={BV号后10位} (取决于下面的单选项)\n' +
            '数据: 每个分集的标题, cid (均为备份时的版本)');
        divControls.appendChild(divLabelEnableGetFromJijidownExtra);

        const labelEnableGetFromJijidownExtra = document.createElement('label');
        labelEnableGetFromJijidownExtra.classList.add('backup-label' + classAppendNewFreshSpace);
        labelEnableGetFromJijidownExtra.textContent = '从唧唧获取额外数据(不稳定)';
        divLabelEnableGetFromJijidownExtra.appendChild(labelEnableGetFromJijidownExtra);

        const checkboxEnableGetFromJijidownExtra = document.createElement('input');
        checkboxEnableGetFromJijidownExtra.type = 'checkbox';
        checkboxEnableGetFromJijidownExtra.checked = settings.enableGetFromJijidownExtra;
        checkboxEnableGetFromJijidownExtra.addEventListener('change', () => {
            try {
                settings.enableGetFromJijidownExtra = checkboxEnableGetFromJijidownExtra.checked;
                if (!settings.enableGetFromJijidownExtra) {
                    divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (!settings.advancedDisableUpdateGetFromJijidownExtra) {
                        divLabelAdvancedIntervalGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelEnableGetFromJijidownExtra.insertAdjacentElement('afterbegin', checkboxEnableGetFromJijidownExtra);

        const divLabelAdvancedDisableUpdateGetFromJijidownExtra = document.createElement('div');
        divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedDisableUpdateGetFromJijidownExtra.setAttribute('title',
            '默认: 开启');
        divControls.appendChild(divLabelAdvancedDisableUpdateGetFromJijidownExtra);

        const labelAdvancedDisableUpdateGetFromJijidownExtra = document.createElement('label');
        labelAdvancedDisableUpdateGetFromJijidownExtra.classList.add('backup-label' + classAppendNewFreshSpace);
        labelAdvancedDisableUpdateGetFromJijidownExtra.textContent = '禁用更新';
        divLabelAdvancedDisableUpdateGetFromJijidownExtra.appendChild(labelAdvancedDisableUpdateGetFromJijidownExtra);

        const checkboxAdvancedDisableUpdateGetFromJijidownExtra = document.createElement('input');
        checkboxAdvancedDisableUpdateGetFromJijidownExtra.type = 'checkbox';
        checkboxAdvancedDisableUpdateGetFromJijidownExtra.checked = settings.advancedDisableUpdateGetFromJijidownExtra;
        checkboxAdvancedDisableUpdateGetFromJijidownExtra.addEventListener('change', () => {
            try {
                settings.advancedDisableUpdateGetFromJijidownExtra = checkboxAdvancedDisableUpdateGetFromJijidownExtra.checked;
                if (settings.advancedDisableUpdateGetFromJijidownExtra) {
                    divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedIntervalGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelAdvancedDisableUpdateGetFromJijidownExtra.insertAdjacentElement('afterbegin', checkboxAdvancedDisableUpdateGetFromJijidownExtra);

        const divLabelAdvancedIntervalGetFromJijidownExtra = document.createElement('div');
        divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedIntervalGetFromJijidownExtra.setAttribute('title',
            '默认: 10星期');
        divControls.appendChild(divLabelAdvancedIntervalGetFromJijidownExtra);

        const labelAdvancedIntervalGetFromJijidownExtra = document.createElement('label');
        labelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-label' + classAppendNewFreshSpace);
        divLabelAdvancedIntervalGetFromJijidownExtra.appendChild(labelAdvancedIntervalGetFromJijidownExtra);

        const inputTextAdvancedIntervalGetFromJijidownExtra = document.createElement('input');
        inputTextAdvancedIntervalGetFromJijidownExtra.type = 'text';
        inputTextAdvancedIntervalGetFromJijidownExtra.classList.add('backup-inputText' + classAppendNewFreshSpace);
        inputTextAdvancedIntervalGetFromJijidownExtra.value = settings.advancedIntervalGetFromJijidownExtra;
        inputTextAdvancedIntervalGetFromJijidownExtra.setAttribute('backup-def', 10);
        inputTextAdvancedIntervalGetFromJijidownExtra.setAttribute('backup-min', 1);
        inputTextAdvancedIntervalGetFromJijidownExtra.setAttribute('backup-max', 100);
        inputTextAdvancedIntervalGetFromJijidownExtra.setAttribute('backup-setting', 'advancedIntervalGetFromJijidownExtra');
        inputTextAdvancedIntervalGetFromJijidownExtra.addEventListener('blur', validateInputText);

        labelAdvancedIntervalGetFromJijidownExtra.appendChild(document.createTextNode('最小更新间隔'))
        labelAdvancedIntervalGetFromJijidownExtra.appendChild(inputTextAdvancedIntervalGetFromJijidownExtra);
        labelAdvancedIntervalGetFromJijidownExtra.appendChild(document.createTextNode('星期'));

        const divSwitchGetFromJijidownURL1 = document.createElement('div');
        divSwitchGetFromJijidownURL1.classList.add('backup-div-third' + classAppendNewFreshSpace);
        divSwitchGetFromJijidownURL1.setAttribute('title',
            '默认: www.jijidown.com\n' +
            'www.jiji.moe为唧唧的新域名。\n' +
            '如果脚本从唧唧获取数据时反复出现问题, 切换至另一域名可能有帮助。');
        divControls.appendChild(divSwitchGetFromJijidownURL1);

        const labelGetFromJijidownURL1 = document.createElement('label');
        labelGetFromJijidownURL1.classList.add('backup-label' + classAppendNewFreshSpace);
        labelGetFromJijidownURL1.textContent = 'www.jijidown.com';
        divSwitchGetFromJijidownURL1.appendChild(labelGetFromJijidownURL1);

        const radioGetFromJijidownURL1 = document.createElement('input');
        radioGetFromJijidownURL1.type = 'radio';
        radioGetFromJijidownURL1.name = 'getFromJijidownURL';
        radioGetFromJijidownURL1.value = 'www.jijidown.com';
        radioGetFromJijidownURL1.checked = settings.getFromJijidownURL === 'www.jijidown.com' ? true : false;
        radioGetFromJijidownURL1.addEventListener('change', () => {
            try {
                settings.getFromJijidownURL = 'www.jijidown.com';
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelGetFromJijidownURL1.insertAdjacentElement('afterbegin', radioGetFromJijidownURL1);

        const divSwitchGetFromJijidownURL2 = document.createElement('div');
        divSwitchGetFromJijidownURL2.classList.add('backup-div-third' + classAppendNewFreshSpace);
        divSwitchGetFromJijidownURL2.setAttribute('title',
            '默认: www.jijidown.com\n' +
            'www.jiji.moe为唧唧的新域名。\n' +
            '如果脚本从唧唧获取数据时反复出现问题, 切换至另一域名可能有帮助。');
        divControls.appendChild(divSwitchGetFromJijidownURL2);

        const labelGetFromJijidownURL2 = document.createElement('label');
        labelGetFromJijidownURL2.classList.add('backup-label' + classAppendNewFreshSpace);
        labelGetFromJijidownURL2.textContent = 'www.jiji.moe';
        divSwitchGetFromJijidownURL2.appendChild(labelGetFromJijidownURL2);

        const radioGetFromJijidownURL2 = document.createElement('input');
        radioGetFromJijidownURL2.type = 'radio';
        radioGetFromJijidownURL2.name = 'getFromJijidownURL';
        radioGetFromJijidownURL2.value = 'www.jiji.moe';
        radioGetFromJijidownURL2.checked = settings.getFromJijidownURL === 'www.jiji.moe' ? true : false;
        radioGetFromJijidownURL2.addEventListener('change', () => {
            try {
                settings.getFromJijidownURL = 'www.jiji.moe';
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelGetFromJijidownURL2.insertAdjacentElement('afterbegin', radioGetFromJijidownURL2);

        const divLabelEnableGetFromXbeibeix = document.createElement('div');
        divLabelEnableGetFromXbeibeix.classList.add('backup-div-second' + classAppendNewFreshSpace);
        divLabelEnableGetFromXbeibeix.setAttribute('title',
            '默认: 关闭\n' +
            '贝贝工具站正在修改其网站页面, 从贝贝工具站获取数据时可能会出现问题。\n' +
            '地址: https://xbeibeix.com/video/{BV号}\n' +
            '或 https://bbdownloader.com/video/{BV号} (取决于下面的单选项)\n' +
            '数据: 标题, 简介, 封面地址, UP主昵称 (均为备份时的版本)');
        divControls.appendChild(divLabelEnableGetFromXbeibeix);

        const labelEnableGetFromXbeibeix = document.createElement('label');
        labelEnableGetFromXbeibeix.classList.add('backup-label' + classAppendNewFreshSpace);
        labelEnableGetFromXbeibeix.textContent = '从贝贝工具站获取数据(不稳定)';
        divLabelEnableGetFromXbeibeix.appendChild(labelEnableGetFromXbeibeix);

        const checkboxEnableGetFromXbeibeix = document.createElement('input');
        checkboxEnableGetFromXbeibeix.type = 'checkbox';
        checkboxEnableGetFromXbeibeix.checked = settings.enableGetFromXbeibeix;
        checkboxEnableGetFromXbeibeix.addEventListener('change', () => {
            try {
                settings.enableGetFromXbeibeix = checkboxEnableGetFromXbeibeix.checked;
                GM_setValue('settings', settings);
                if (!settings.enableGetFromXbeibeix) {
                    divLabelAdvancedDisableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedDisableUpdateGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    if (!settings.advancedDisableUpdateGetFromXbeibeix) {
                        divLabelAdvancedIntervalGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    }
                    divSwitchGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                    divSwitchGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                }
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelEnableGetFromXbeibeix.insertAdjacentElement('afterbegin', checkboxEnableGetFromXbeibeix);

        const divLabelAdvancedDisableUpdateGetFromXbeibeix = document.createElement('div');
        divLabelAdvancedDisableUpdateGetFromXbeibeix.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedDisableUpdateGetFromXbeibeix.setAttribute('title',
            '默认: 开启');
        divControls.appendChild(divLabelAdvancedDisableUpdateGetFromXbeibeix);

        const labelAdvancedDisableUpdateGetFromXbeibeix = document.createElement('label');
        labelAdvancedDisableUpdateGetFromXbeibeix.classList.add('backup-label' + classAppendNewFreshSpace);
        labelAdvancedDisableUpdateGetFromXbeibeix.textContent = '禁用更新';
        divLabelAdvancedDisableUpdateGetFromXbeibeix.appendChild(labelAdvancedDisableUpdateGetFromXbeibeix);

        const checkboxAdvancedDisableUpdateGetFromXbeibeix = document.createElement('input');
        checkboxAdvancedDisableUpdateGetFromXbeibeix.type = 'checkbox';
        checkboxAdvancedDisableUpdateGetFromXbeibeix.checked = settings.advancedDisableUpdateGetFromXbeibeix;
        checkboxAdvancedDisableUpdateGetFromXbeibeix.addEventListener('change', () => {
            try {
                settings.advancedDisableUpdateGetFromXbeibeix = checkboxAdvancedDisableUpdateGetFromXbeibeix.checked;
                if (settings.advancedDisableUpdateGetFromXbeibeix) {
                    divLabelAdvancedIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    divLabelAdvancedIntervalGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
                }
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelAdvancedDisableUpdateGetFromXbeibeix.insertAdjacentElement('afterbegin', checkboxAdvancedDisableUpdateGetFromXbeibeix);

        const divLabelAdvancedIntervalGetFromXbeibeix = document.createElement('div');
        divLabelAdvancedIntervalGetFromXbeibeix.classList.add('backup-div-third' + classAppendNewFreshSpace, 'backup-advanced');
        divLabelAdvancedIntervalGetFromXbeibeix.setAttribute('title',
            '默认: 10星期');
        divControls.appendChild(divLabelAdvancedIntervalGetFromXbeibeix);

        const labelAdvancedIntervalGetFromXbeibeix = document.createElement('label');
        labelAdvancedIntervalGetFromXbeibeix.classList.add('backup-label' + classAppendNewFreshSpace);
        divLabelAdvancedIntervalGetFromXbeibeix.appendChild(labelAdvancedIntervalGetFromXbeibeix);

        const inputTextAdvancedIntervalGetFromXbeibeix = document.createElement('input');
        inputTextAdvancedIntervalGetFromXbeibeix.type = 'text';
        inputTextAdvancedIntervalGetFromXbeibeix.classList.add('backup-inputText' + classAppendNewFreshSpace);
        inputTextAdvancedIntervalGetFromXbeibeix.value = settings.advancedIntervalGetFromXbeibeix;
        inputTextAdvancedIntervalGetFromXbeibeix.setAttribute('backup-def', 10);
        inputTextAdvancedIntervalGetFromXbeibeix.setAttribute('backup-min', 1);
        inputTextAdvancedIntervalGetFromXbeibeix.setAttribute('backup-max', 100);
        inputTextAdvancedIntervalGetFromXbeibeix.setAttribute('backup-setting', 'advancedIntervalGetFromXbeibeix');
        inputTextAdvancedIntervalGetFromXbeibeix.addEventListener('blur', validateInputText);

        labelAdvancedIntervalGetFromXbeibeix.appendChild(document.createTextNode('最小更新间隔'))
        labelAdvancedIntervalGetFromXbeibeix.appendChild(inputTextAdvancedIntervalGetFromXbeibeix);
        labelAdvancedIntervalGetFromXbeibeix.appendChild(document.createTextNode('星期'));

        const divSwitchGetFromXbeibeixURL1 = document.createElement('div');
        divSwitchGetFromXbeibeixURL1.classList.add('backup-div-third' + classAppendNewFreshSpace);
        divSwitchGetFromXbeibeixURL1.setAttribute('title',
            '默认: xbeibeix.com\n' +
            'bbdownloader.com为贝贝工具站的新域名。\n' +
            '如果脚本从贝贝工具站获取数据时反复出现问题, 切换至另一域名可能有帮助。');
        divControls.appendChild(divSwitchGetFromXbeibeixURL1);

        const labelGetFromXbeibeixURL1 = document.createElement('label');
        labelGetFromXbeibeixURL1.classList.add('backup-label' + classAppendNewFreshSpace);
        labelGetFromXbeibeixURL1.textContent = 'xbeibeix.com';
        divSwitchGetFromXbeibeixURL1.appendChild(labelGetFromXbeibeixURL1);

        const radioGetFromXbeibeixURL1 = document.createElement('input');
        radioGetFromXbeibeixURL1.type = 'radio';
        radioGetFromXbeibeixURL1.name = 'getFromXbeibeixURL';
        radioGetFromXbeibeixURL1.value = 'xbeibeix.com';
        radioGetFromXbeibeixURL1.checked = settings.getFromXbeibeixURL === 'xbeibeix.com' ? true : false;
        radioGetFromXbeibeixURL1.addEventListener('change', () => {
            try {
                settings.getFromXbeibeixURL = 'xbeibeix.com';
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelGetFromXbeibeixURL1.insertAdjacentElement('afterbegin', radioGetFromXbeibeixURL1);

        const divSwitchGetFromXbeibeixURL2 = document.createElement('div');
        divSwitchGetFromXbeibeixURL2.classList.add('backup-div-third' + classAppendNewFreshSpace);
        divSwitchGetFromXbeibeixURL2.setAttribute('title',
            '默认: xbeibeix.com\n' +
            'bbdownloader.com为贝贝工具站的新域名。\n' +
            '如果脚本从贝贝工具站获取数据时反复出现问题, 切换至另一域名可能有帮助。');
        divControls.appendChild(divSwitchGetFromXbeibeixURL2);

        const labelGetFromXbeibeixURL2 = document.createElement('label');
        labelGetFromXbeibeixURL2.classList.add('backup-label' + classAppendNewFreshSpace);
        labelGetFromXbeibeixURL2.textContent = 'bbdownloader.com';
        divSwitchGetFromXbeibeixURL2.appendChild(labelGetFromXbeibeixURL2);

        const radioGetFromXbeibeixURL2 = document.createElement('input');
        radioGetFromXbeibeixURL2.type = 'radio';
        radioGetFromXbeibeixURL2.name = 'getFromXbeibeixURL';
        radioGetFromXbeibeixURL2.value = 'bbdownloader.com';
        radioGetFromXbeibeixURL2.checked = settings.getFromXbeibeixURL === 'bbdownloader.com' ? true : false;
        radioGetFromXbeibeixURL2.addEventListener('change', () => {
            try {
                settings.getFromXbeibeixURL = 'bbdownloader.com';
                GM_setValue('settings', settings);
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelGetFromXbeibeixURL2.insertAdjacentElement('afterbegin', radioGetFromXbeibeixURL2);

        const divLabelEnableAutoNextPage = document.createElement('div');
        divLabelEnableAutoNextPage.classList.add('backup-div-first' + classAppendNewFreshSpace);
        divLabelEnableAutoNextPage.setAttribute('title',
            '开启后脚本将在当前页的视频都处理完毕之后点击下一页, 继续处理下一页的视频。');
        divControls.appendChild(divLabelEnableAutoNextPage);

        const labelEnableAutoNextPage = document.createElement('label');
        labelEnableAutoNextPage.classList.add('backup-label' + classAppendNewFreshSpace);
        labelEnableAutoNextPage.textContent = '自动点击下一页';
        divLabelEnableAutoNextPage.appendChild(labelEnableAutoNextPage);

        const checkboxEnableAutoNextPage = document.createElement('input');
        checkboxEnableAutoNextPage.type = 'checkbox';
        checkboxEnableAutoNextPage.checked = enableAutoNextPage;
        checkboxEnableAutoNextPage.addEventListener('change', async () => {
            try {
                enableAutoNextPage = checkboxEnableAutoNextPage.checked;
                if (enableAutoNextPage && !activeControllers.size) {
                    if (newFreshSpace) {
                        const pager = Array.from(document.querySelectorAll('button.vui_pagenation--btn-side')).find(el => el.innerText === '下一页');
                        if (pager && !pager.classList.contains('vui_button--disabled')) {
                            await delay(500);
                            if (enableAutoNextPage) {
                                pager.click();
                            }
                        }

                    } else {
                        const pager = document.querySelector('li.be-pager-next');
                        if (pager && !pager.classList.contains('be-pager-disabled')) {
                            await delay(500);
                            if (enableAutoNextPage) {
                                pager.click();
                            }
                        }
                    }
                }
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelEnableAutoNextPage.insertAdjacentElement('afterbegin', checkboxEnableAutoNextPage);

        const divLabelDisplayAdvancedControls = document.createElement('div');
        divLabelDisplayAdvancedControls.classList.add('backup-div-first' + classAppendNewFreshSpace);
        divControls.appendChild(divLabelDisplayAdvancedControls);

        const labelDisplayAdvancedControls = document.createElement('label');
        labelDisplayAdvancedControls.classList.add('backup-label' + classAppendNewFreshSpace);
        // labelDisplayAdvancedControls.textContent = '显示高级选项和功能';
        labelDisplayAdvancedControls.textContent = '显示高级选项';
        divLabelDisplayAdvancedControls.appendChild(labelDisplayAdvancedControls);

        const checkboxDisplayAdvancedControls = document.createElement('input');
        checkboxDisplayAdvancedControls.type = 'checkbox';
        checkboxDisplayAdvancedControls.checked = settings.displayAdvancedControls;
        checkboxDisplayAdvancedControls.addEventListener('change', () => {
            try {
                settings.displayAdvancedControls = checkboxDisplayAdvancedControls.checked;
                GM_setValue('settings', settings);
                if (!settings.displayAdvancedControls) {
                    divControls.querySelectorAll('.backup-advanced').forEach(el => { el.classList.add('backup-hidden' + classAppendNewFreshSpace) });
                } else {
                    divControls.querySelectorAll('.backup-advanced').forEach(el => { el.classList.remove('backup-hidden' + classAppendNewFreshSpace) });
                }
            } catch (error) {
                catchUnknownError(error);
            }
        });
        labelDisplayAdvancedControls.insertAdjacentElement('afterbegin', checkboxDisplayAdvancedControls);

        const divButtonExportBackup = document.createElement('div');
        divButtonExportBackup.classList.add('backup-div-first' + classAppendNewFreshSpace);
        divButtonExportBackup.setAttribute('title',
            '导入的备份数据会与脚本内已有的备份数据合并在一起。\n' +
            '请不要随意修改导出的备份数据文件中的内容, 否则导入时可能会出错。');
        divControls.appendChild(divButtonExportBackup);

        const buttonExportBackup = document.createElement('button');
        buttonExportBackup.type = 'button';
        buttonExportBackup.classList.add('backup-button' + classAppendNewFreshSpace);
        buttonExportBackup.textContent = '导出本地备份数据';
        buttonExportBackup.addEventListener('click', () => {
            try {
                // const BVs = GM_listValues();
                // const backupsToExport = {};
                // BVs.forEach(BV => {
                //     backupsToExport[BV] = GM_getValue(BV, null);
                // });

                const backupsToExport = GM_getValues(GM_listValues().sort());
                delete backupsToExport.settings;

                // const backupData = JSON.stringify(backupToExport);
                const backupsData = JSON.stringify(backupsToExport, null, 4);
                const blob = new Blob([backupsData], { type: 'application/json' });
                const link = document.createElement('a');
                link.href = URL.createObjectURL(blob);
                link.download = `${formatTsYYMMDD_HHMMSS(getCurrentTs())}.json`;
                link.click();
                URL.revokeObjectURL(link.href);

            } catch (error) {
                catchUnknownError(error);
            }
        });
        divButtonExportBackup.appendChild(buttonExportBackup);

        const divButtonImportBackup = document.createElement('div');
        divButtonImportBackup.classList.add('backup-div-first' + classAppendNewFreshSpace);
        divButtonImportBackup.setAttribute('title',
            '导入的备份数据会与脚本内已有的备份数据合并在一起。\n' +
            '请不要随意修改导出的备份数据文件中的内容, 否则导入时可能会出错。');
        divControls.appendChild(divButtonImportBackup);

        const buttonImportBackup = document.createElement('button');
        buttonImportBackup.type = 'button';
        buttonImportBackup.classList.add('backup-button' + classAppendNewFreshSpace);
        buttonImportBackup.textContent = '导入本地备份数据';
        divButtonImportBackup.appendChild(buttonImportBackup);

        const divInputFile = document.createElement('div');
        divInputFile.style.display = 'none';
        divControls.appendChild(divInputFile);

        const inputFile = document.createElement('input');
        inputFile.type = 'file';
        divInputFile.appendChild(inputFile);

        buttonImportBackup.addEventListener('click', () => {
            try {
                inputFile.click();
            } catch (error) {
                catchUnknownError(error);
            }
        });

        inputFile.addEventListener('change', (event) => {
            try {
                const file = event.target.files[0];
                if (!file) {
                    return;
                }

                const reader = new FileReader();
                reader.onload = (e) => {
                    try {
                        const backupsToImport = JSON.parse(e.target.result);
                        if (typeof backupsToImport !== 'object') {
                            addMessage('文件内容有误, 无法导入', false, true);
                            return;
                        }

                        for (const BVOfBackupToImport in backupsToImport) {
                            const backupToImport = backupsToImport[BVOfBackupToImport];

                            try {

                                ///////////////////////////////////////////////////////////////////////////////////
                                // v9
                                if (backupToImport.timeFavorite) {
                                    backupToImport.timeFavorite.forEach(el => {
                                        if (typeof el.fid === 'string') {
                                            el.fid = parseInt(el.fid, 10);
                                        }
                                    });
                                }
                                // v9
                                if (backupToImport.timeUpload && typeof backupToImport.timeUpload === 'object') {
                                    if (backupToImport.timeUpload.length === 1) {
                                        backupToImport.timeUpload = backupToImport.timeUpload[0].value;
                                    } else {
                                        backupToImport.timeUpload = null;
                                    }
                                }
                                // v9
                                if (backupToImport.timePublish && typeof backupToImport.timePublish === 'object') {
                                    if (backupToImport.timePublish.length === 1) {
                                        backupToImport.timePublish = backupToImport.timePublish[0].value;
                                    } else {
                                        backupToImport.timePublish = null;
                                    }
                                }
                                // v10
                                if (backupToImport.hasOwnProperty('jiji')) {
                                    backupToImport.jijidown = backupToImport.jiji;
                                    delete backupToImport.jiji;
                                }
                                // v10
                                if (backupToImport.hasOwnProperty('bbdownloader')) {
                                    backupToImport.xbeibeix = backupToImport.bbdownloader;
                                    delete backupToImport.bbdownloader;
                                }
                                // v12
                                ['cover', 'upperAvatar'].forEach(key => {
                                    if (backupToImport[key] && backupToImport[key].length > 1) {
                                        const tempBackup = {};
                                        backupToImport[key].forEach(el => {
                                            updateArrayDataInBackup(tempBackup, key, el.value, el.ts, el.from);
                                        });
                                        backupToImport[key] = tempBackup[key];
                                    }
                                });
                                // v14
                                if (backupToImport.hasOwnProperty('firstFrame')) {
                                    delete backupToImport.firstFrame;
                                }
                                // v16
                                if (backupToImport.intro) {
                                    const tempBackup = { intro: null };
                                    backupToImport.intro.forEach(el => {
                                        updateArrayDataInBackup(tempBackup, 'intro', el.value, el.ts, el.from);
                                    });
                                    backupToImport.intro = tempBackup.intro;
                                }
                                ///////////////////////////////////////////////////////////////////////////////////

                                const backup = GM_getValue(backupToImport.BV, {
                                    BV: null,
                                    AV: null,
                                    title: null,
                                    intro: null,
                                    cover: null,
                                    upperUID: null,
                                    upperName: null,
                                    upperAvatar: null,
                                    timeUpload: null,
                                    timePublish: null,
                                    timeFavorite: null,
                                    dynamic: null,
                                    pages: null,
                                    api: null,
                                    apiExtra: null,
                                    biliplus: null,
                                    jijidown: null,
                                    jijidownExtra: null,
                                    xbeibeix: null,
                                });

                                ///////////////////////////////////////////////////////////////////////////////////
                                // v9
                                if (backup.timeFavorite) {
                                    backup.timeFavorite.forEach(el => {
                                        if (typeof el.fid === 'string') {
                                            el.fid = parseInt(el.fid, 10);
                                        }
                                    });
                                }
                                // v9
                                if (backup.timeUpload && typeof backup.timeUpload === 'object') {
                                    if (backup.timeUpload.length === 1) {
                                        backup.timeUpload = backup.timeUpload[0].value;
                                    } else {
                                        backup.timeUpload = null;
                                    }
                                }
                                // v9
                                if (backup.timePublish && typeof backup.timePublish === 'object') {
                                    if (backup.timePublish.length === 1) {
                                        backup.timePublish = backup.timePublish[0].value;
                                    } else {
                                        backup.timePublish = null;
                                    }
                                }
                                // v10
                                if (backup.hasOwnProperty('jiji')) {
                                    backup.jijidown = backup.jiji;
                                    delete backup.jiji;
                                }
                                // v10
                                if (backup.hasOwnProperty('bbdownloader')) {
                                    backup.xbeibeix = backup.bbdownloader;
                                    delete backup.bbdownloader;
                                }
                                // v12
                                ['cover', 'upperAvatar'].forEach(key => {
                                    if (backup[key] && backup[key].length > 1) {
                                        const tempBackup = {};
                                        backup[key].forEach(el => {
                                            updateArrayDataInBackup(tempBackup, key, el.value, el.ts, el.from);
                                        });
                                        backup[key] = tempBackup[key];
                                    }
                                });
                                // v14
                                if (backup.hasOwnProperty('firstFrame')) {
                                    delete backup.firstFrame;
                                }
                                // v16
                                if (backup.intro) {
                                    const tempBackup = { intro: null };
                                    backup.intro.forEach(el => {
                                        updateArrayDataInBackup(tempBackup, 'intro', el.value, el.ts, el.from);
                                    });
                                    backup.intro = tempBackup.intro;
                                }
                                ///////////////////////////////////////////////////////////////////////////////////

                                if (backupToImport.AV) {
                                    backup.AV = backupToImport.AV;
                                }
                                if (backupToImport.BV) {
                                    backup.BV = backupToImport.BV;
                                }
                                if (backupToImport.title) {
                                    backupToImport.title.forEach(el => {
                                        updateArrayDataInBackup(backup, 'title', el.value, el.ts, el.from);
                                    });
                                }
                                if (backupToImport.intro) {
                                    backupToImport.intro.forEach(el => {
                                        updateArrayDataInBackup(backup, 'intro', el.value, el.ts, el.from);
                                    });
                                }
                                if (backupToImport.cover) {
                                    backupToImport.cover.forEach(el => {
                                        updateArrayDataInBackup(backup, 'cover', el.value, el.ts, el.from);
                                    });
                                }
                                if (backupToImport.upperUID) {
                                    backup.upperUID = backupToImport.upperUID;
                                }
                                if (backupToImport.upperName) {
                                    backupToImport.upperName.forEach(el => {
                                        updateArrayDataInBackup(backup, 'upperName', el.value, el.ts, el.from);
                                    });
                                }
                                if (backupToImport.upperAvatar) {
                                    backupToImport.upperAvatar.forEach(el => {
                                        updateArrayDataInBackup(backup, 'upperAvatar', el.value, el.ts, el.from);
                                    });
                                }
                                if (backupToImport.timeUpload) {
                                    backup.timeUpload = backupToImport.timeUpload;
                                }
                                if (backupToImport.timePublish) {
                                    backup.timePublish = backupToImport.timePublish;
                                }
                                if (backupToImport.timeFavorite) {
                                    backupToImport.timeFavorite.forEach(el => {
                                        updateTimeFavoriteInBackup(backup, el.value, el.fid);
                                    });
                                }
                                if (backupToImport.dynamic) {
                                    backupToImport.dynamic.forEach(el => {
                                        updateArrayDataInBackup(backup, 'dynamic', el.value, el.ts, el.from);
                                    });
                                }
                                if (backupToImport.pages) {
                                    backupToImport.pages.forEach(el => {
                                        updatePagesInBackup(backup, el.index, el.title, el.firstFrame, el.cid, el.ts, el.from);
                                    });
                                }
                                ['api', 'apiExtra', 'biliplus', 'jijidown', 'jijidownExtra', 'xbeibeix'].forEach(key => {
                                    if (backupToImport[key]) {
                                        if (!backup[key]) {
                                            backup[key] = { value: backupToImport[key].value, ts: backupToImport[key].ts };
                                        } else {
                                            if (backup[key].ts < backupToImport[key].ts) {
                                                backup[key].value = backupToImport[key].value;
                                                backup[key].ts = backupToImport[key].ts;
                                            }
                                        }
                                    }
                                });
                                const sortedBackup = {};
                                for (const sortedKey of sortedKeys) {
                                    sortedBackup[sortedKey] = backup[sortedKey];
                                }
                                GM_setValue(backupToImport.BV, sortedBackup);

                            } catch (error) {
                                addMessage('导入该视频失败', false, true);
                                if (backupToImport.BV) {
                                    addMessage(`BV号: ${backupToImport.BV}`, true);
                                }
                                if (error instanceof Error) {
                                    addMessage(error.stack, true);
                                    console.error(error);
                                } else {
                                    addMessage(error[0], true);
                                    for (let i = 1; i < error.length; i++) {
                                        addMessage(error[i], true);
                                    }
                                }
                                console.error('需要导入的数据');
                                console.error(backupToImport);
                                if (backupToImport.BV) {
                                    console.error('本地已有的数据');
                                    console.error(GM_getValue(backupToImport.BV, {}));
                                }
                            }
                        }

                        addMessage('导入完成');

                    } catch (error) {
                        catchUnknownError(error);
                    }
                };

                reader.readAsText(file);

            } catch (error) {
                catchUnknownError(error);
            }
        });

        const divButtonStopProcessing = document.createElement('div');
        divButtonStopProcessing.classList.add('backup-div-first' + classAppendNewFreshSpace);
        divButtonStopProcessing.setAttribute('title',
            '此功能适用于脚本处理视频时反复出现问题的情况。');
        divControls.appendChild(divButtonStopProcessing);

        const buttonStopProcessing = document.createElement('button');
        buttonStopProcessing.type = 'button';
        buttonStopProcessing.classList.add('backup-button' + classAppendNewFreshSpace);
        buttonStopProcessing.textContent = '停止处理当前页视频';
        buttonStopProcessing.addEventListener('click', () => {
            try {
                abortActiveControllers();
            } catch (error) {
                catchUnknownError(error);
            }
        });
        divButtonStopProcessing.appendChild(buttonStopProcessing);

        if (enableDebug) {
            const divButton = document.createElement('div');
            divButton.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced');
            divControls.appendChild(divButton);

            const button = document.createElement('button');
            button.type = 'button';
            button.classList.add('backup-button' + classAppendNewFreshSpace);
            button.textContent = '清空提示信息';
            button.addEventListener('click', () => {
                try {
                    clearMessage();
                } catch (error) {
                    catchUnknownError(error);
                }
            });
            divButton.appendChild(button);
        }

        if (enableDebug) {
            const divButton = document.createElement('div');
            divButton.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced');
            divControls.appendChild(divButton);

            const button = document.createElement('button');
            button.type = 'button';
            button.classList.add('backup-button' + classAppendNewFreshSpace);
            button.textContent = '添加提示信息';
            button.addEventListener('click', () => {
                try {
                    addMessage(divMessage.scrollHeight);
                } catch (error) {
                    catchUnknownError(error);
                }
            });
            divButton.appendChild(button);
        }

        divMessage = document.createElement('div');
        divMessage.classList.add('backup-divMessage' + classAppendNewFreshSpace);
        divControls.appendChild(divMessage);

        if (displayUpdate) {
            setTimeout(() => {
                addMessage(updates);
            }, 300);
        }

        if (!settings.processNormal && !settings.processDisabled) {
            divLabelEnableGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedDisableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedDisableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelEnableGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedDisableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelEnableGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedDisableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelEnableGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedDisableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divLabelAdvancedIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divSwitchGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
            divSwitchGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
        } else {
            if (!settings.enableGetFromApi) {
                divLabelAdvancedDisableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelAdvancedIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelAdvancedDisableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
            } else {
                if (settings.advancedDisableUpdateGetFromApi) {
                    divLabelAdvancedIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
                }
                if (!settings.enableGetFromApiExtra) {
                    divLabelAdvancedDisableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    if (settings.advancedDisableUpdateGetFromApiExtra) {
                        divLabelAdvancedIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    }
                }
            }
            if (!settings.enableGetFromBiliplus) {
                divLabelAdvancedDisableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelAdvancedIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
            } else {
                if (settings.advancedDisableUpdateGetFromBiliplus) {
                    divLabelAdvancedIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
                }
            }
            if (!settings.enableGetFromJijidown) {
                divLabelAdvancedDisableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelAdvancedIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
            } else {
                if (settings.advancedDisableUpdateGetFromJijidown) {
                    divLabelAdvancedIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
                }
                if (!settings.enableGetFromJijidownExtra) {
                    divLabelAdvancedDisableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                } else {
                    if (settings.advancedDisableUpdateGetFromJijidownExtra) {
                        divLabelAdvancedIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
                    }
                }
            }
            if (!settings.enableGetFromXbeibeix) {
                divLabelAdvancedDisableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divLabelAdvancedIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divSwitchGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
                divSwitchGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
            } else {
                if (settings.advancedDisableUpdateGetFromXbeibeix) {
                    divLabelAdvancedIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
                }
            }
        }

        if (!settings.displayAdvancedControls) {
            divControls.querySelectorAll('.backup-advanced').forEach(el => {
                el.classList.add('backup-hidden' + classAppendNewFreshSpace);
            });
        }
    }

    function appendDropdowns(dropdownContainer, BV) {

        try {
            if (newFreshSpace) {
                const biliCardDropdownVisible = document.querySelectorAll('div.bili-card-dropdown--visible');
                if (biliCardDropdownVisible.length !== 1) {
                    addMessage('下拉列表开关不存在或不唯一, 无法确定下拉列表所对应的视频, 刷新页面可能有帮助', false, true);
                    return;
                }

                let divTargetVideo;
                try {
                    divTargetVideo = document.querySelector('div.items__item:has(div.bili-card-dropdown--visible)');
                } catch {
                    const items = document.querySelectorAll('div.items__item');
                    for (const item of items) {
                        if (item.contains(biliCardDropdownVisible[0])) {
                            divTargetVideo = item;
                            break;
                        }
                    }
                }
                if (!divTargetVideo) {
                    addMessage('无法确定下拉列表所对应的视频, 请反馈该问题', false, true);
                    return;
                }

                if (divTargetVideo.querySelector('div.bili-cover-card__tags')) {
                    if (enableDebug) console.log('不处理特殊视频');
                    return;
                }

                if (!settings.processNormal && divTargetVideo.querySelector('div.bili-cover-card__stats')) {
                    return;
                }
                if (!settings.processDisabled && !divTargetVideo.querySelector('div.bili-cover-card__stats')) {
                    return;
                }

                const getBVFromURLMatch = biliCardDropdownVisible[0].parentNode.querySelector('a').getAttribute('href').match(getBVFromURLRegex);
                if (!getBVFromURLMatch) {
                    addMessage('无法获取该视频的BV号, 请检查是否有其他脚本或插件修改了该视频封面和标题的链接地址, 并将其关闭', false, true);
                    return;
                }
                BV = getBVFromURLMatch[1];

            } else {
                if (dropdownContainer.lastElementChild.classList.contains('backup')) {
                    return;
                }
                dropdownContainer.lastElementChild.classList.add('be-dropdown-item-delimiter');
            }

            const backup = GM_getValue(BV, {});

            if (backup.cover) {
                const dropdownCover = document.createElement(newFreshSpace ? 'div' : 'li');
                dropdownCover.classList.add(newFreshSpace ? 'bili-card-dropdown-popper__item' : 'be-dropdown-item');
                if (!newFreshSpace) {
                    dropdownCover.classList.add('backup');
                }
                dropdownCover.setAttribute('title',
                    '查看该视频的本地备份数据中所有版本的封面原图, 从新到旧');
                dropdownCover.textContent = '封面原图';
                dropdownCover.addEventListener('click', () => {
                    try {
                        if (newFreshSpace) {
                            dropdownContainer.classList.remove('visible');
                        }
                        GM_openInTab(`https://${backup.cover[backup.cover.length - 1].value}`, { active: true, insert: true, setParent: true });
                        for (let i = backup.cover.length - 2; i >= 0; i--) {
                            GM_openInTab(`https://${backup.cover[i].value}`, { insert: false, setParent: true });
                        }

                    } catch (error) {
                        catchUnknownError(error);
                    }
                });
                dropdownContainer.appendChild(dropdownCover);
            }

            const dropdownLocal = document.createElement(newFreshSpace ? 'div' : 'li');
            dropdownLocal.classList.add(newFreshSpace ? 'bili-card-dropdown-popper__item' : 'be-dropdown-item');
            if (!newFreshSpace) {
                dropdownLocal.classList.add('backup');
            }
            dropdownLocal.setAttribute('title',
                '查看该视频的本地备份数据');
            dropdownLocal.textContent = '本地备份数据';
            dropdownLocal.addEventListener('click', () => {
                try {
                    if (newFreshSpace) {
                        dropdownContainer.classList.remove('visible');
                    }
                    const data = GM_getValue(BV, {});
                    const json = JSON.stringify(data);
                    // GM_openInTab('data:text/plain;charset=utf-8,' + encodeURIComponent(json), { active: true, insert: false, setParent: true });
                    GM_openInTab('data:application/json;charset=utf-8,' + encodeURIComponent(json), { active: true, insert: false, setParent: true });

                } catch (error) {
                    catchUnknownError(error);
                }
            });
            dropdownContainer.appendChild(dropdownLocal);

            const dropdownJump = document.createElement(newFreshSpace ? 'div' : 'li');
            dropdownJump.classList.add(newFreshSpace ? 'bili-card-dropdown-popper__item' : 'be-dropdown-item');
            if (!newFreshSpace) {
                dropdownJump.classList.add('backup');
            }
            dropdownJump.setAttribute('title',
                '跳转至该视频在各个第三方网站的原始页面');
            dropdownJump.textContent = '跳转至BJX';
            dropdownJump.addEventListener('click', () => {
                try {
                    if (newFreshSpace) {
                        dropdownContainer.classList.remove('visible');
                    }
                    GM_openInTab(`https://www.biliplus.com/video/${BV}`, { active: true, insert: false, setParent: true });
                    GM_openInTab(`https://${settings.getFromJijidownURL}/video/${BV}`, { insert: false, setParent: true });
                    GM_openInTab(`https://${settings.getFromXbeibeixURL}/video/${BV}`, { insert: false, setParent: true });

                } catch (error) {
                    catchUnknownError(error);
                }
            });
            dropdownContainer.appendChild(dropdownJump);

            const dropdownReset = document.createElement(newFreshSpace ? 'div' : 'li');
            dropdownReset.classList.add(newFreshSpace ? 'bili-card-dropdown-popper__item' : 'be-dropdown-item');
            if (!newFreshSpace) {
                dropdownReset.classList.add('backup');
            }
            dropdownReset.setAttribute('title',
                '如果该视频的本地备份数据出现错乱, 请使用此功能将其删除以便重新备份该视频。\n' +
                '如果您想删除脚本内所有已保存的数据, 请依次点击: Tampermonkey > 管理面板 >\n' +
                '哔哩哔哩(B站|Bilibili)收藏夹Fix (备份视频信息) > 开发者 > 重置到出厂。');
            dropdownReset.textContent = '重置备份数据';
            dropdownReset.addEventListener('click', () => {
                try {
                    if (newFreshSpace) {
                        dropdownContainer.classList.remove('visible');
                    }
                    GM_deleteValue(BV);

                } catch (error) {
                    catchUnknownError(error);
                }
            });
            dropdownContainer.appendChild(dropdownReset);

        } catch (error) {
            catchUnknownError(error);
        }
    }

    async function getFromApi(AVBVTitle, backup, spanA, apiDetails, fid, pageNumber, disabled, spanFavTime) {

        if (!apiDetails.value) {
            const response = await new Promise(async (resolve, reject) => {
                GM.xmlHttpRequest({
                    method: 'GET',
                    url: await appendParamsForGetFromApi(fid, pageNumber, pageSize),
                    timeout: 5000,
                    responseType: 'json',
                    onload: (res) => resolve(res),
                    onerror: (res) => reject(['请求失败', 'api.bilibili.com/x/v3/fav/resource/list', res.error]),
                    ontimeout: () => reject(['请求超时', 'api.bilibili.com/x/v3/fav/resource/list'])
                });
            });

            apiDetails.value = response.response.data.medias;
        }

        const apiDetail = apiDetails.value.find(el => el.bvid === AVBVTitle.BV);
        if (!apiDetail) {
            if (enableDebug) console.warn('getFromApi 从B站接口获取的数据中没有该视频');
            return true;
        }

        if (!AVBVTitle.AV) {
            AVBVTitle.AV = apiDetail.id;
            backup.AV = apiDetail.id;
        }

        if (enableDebug) console.log('从B站接口获取数据');
        if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
        if (enableDebug) console.debug(apiDetail);

        if (!disabled) {
            updateArrayDataInBackup(backup, 'title', apiDetail.title, getCurrentTs(), 'api.bilibili.com/x/v3/fav/resource/list');
            updateArrayDataInBackup(backup, 'cover', apiDetail.cover, getCurrentTs(), 'api.bilibili.com/x/v3/fav/resource/list');
        }
        updateArrayDataInBackup(backup, 'intro', apiDetail.intro, getCurrentTs(), 'api.bilibili.com/x/v3/fav/resource/list');
        if (!disabled && apiDetail.intro.length >= 255) {
            if (settings.enableGetFromApiExtra && (!backup.apiExtra || (!settings.advancedDisableUpdateGetFromApiExtra && getCurrentTs() - backup.apiExtra.ts > 3600 * 24 * settings.advancedIntervalGetFromApiExtra))) {

            } else {
                const response = await new Promise((resolve, reject) => {
                    GM.xmlHttpRequest({
                        method: 'GET',
                        url: `https://api.bilibili.com/x/web-interface/archive/desc?bvid=${AVBVTitle.BV}`,
                        timeout: 5000,
                        responseType: 'json',
                        onload: (res) => resolve(res),
                        onerror: (res) => reject(['请求失败', 'api.bilibili.com/x/web-interface/archive/desc', res.error]),
                        ontimeout: () => reject(['请求超时', 'api.bilibili.com/x/web-interface/archive/desc'])
                    });
                });
                updateArrayDataInBackup(backup, 'intro', response.response.data, getCurrentTs(), 'api.bilibili.com/x/web-interface/archive/desc');
            }
        }

        if (!backup.upperUID) {
            backup.upperUID = apiDetail.upper.mid;
        }
        updateArrayDataInBackup(backup, 'upperName', apiDetail.upper.name, getCurrentTs(), 'api.bilibili.com/x/v3/fav/resource/list');
        updateArrayDataInBackup(backup, 'upperAvatar', apiDetail.upper.face, getCurrentTs(), 'api.bilibili.com/x/v3/fav/resource/list');

        backup.timeUpload = apiDetail.ctime;
        backup.timePublish = apiDetail.pubtime;
        updateTimeFavoriteInBackup(backup, apiDetail.fav_time, fid);

        if (newFreshSpace) {
            spanFavTime.textContent = `投稿于:${formatTsTimePublish(apiDetail.pubtime * 1000)}`;
            spanFavTime.setAttribute('title', new Date(apiDetail.pubtime * 1000).toLocaleString());
        } else {
            spanFavTime.textContent = `收藏于:${formatTsTimeFavorite(new Date(apiDetail.fav_time * 1000))}`;
            spanFavTime.setAttribute('title', new Date(apiDetail.fav_time * 1000).toLocaleString());
        }

        if (disabled) {
            backup.api = { value: false, ts: getCurrentTs() };
            spanA.style.color = '#ff0000';
        } else {
            backup.api = { value: true, ts: getCurrentTs() };
            spanA.style.color = '#00ff00';
        }

        const sortedBackup = {};
        for (const sortedKey of sortedKeys) {
            sortedBackup[sortedKey] = backup[sortedKey];
        }
        GM_setValue(AVBVTitle.BV, sortedBackup);
        if (enableDebug) console.log('保存B站接口的数据至本地');
        if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
        if (enableDebug) console.debug(sortedBackup);
    }

    async function getFromApiExtra(AVBVTitle, backup, spanA, disabled) {

        if (disabled) {
            backup.apiExtra = { value: false, ts: getCurrentTs() };
            spanA.style.color = '#800000';

        } else {
            const response = await new Promise((resolve, reject) => {
                GM.xmlHttpRequest({
                    method: 'GET',
                    url: `https://api.bilibili.com/x/web-interface/view?bvid=${AVBVTitle.BV}`,
                    timeout: 5000,
                    responseType: 'json',
                    onload: (res) => resolve(res),
                    onerror: (res) => reject(['请求失败', 'api.bilibili.com/x/web-interface/view', res.error]),
                    ontimeout: () => reject(['请求超时', 'api.bilibili.com/x/web-interface/view'])
                });
            });

            updateArrayDataInBackup(backup, 'intro', response.response.data.desc, getCurrentTs(), 'api.bilibili.com/x/web-interface/view');
            if (response.response.data.desc_v2) {
                let introWithUID = '';
                for (const [index, desc] of response.response.data.desc_v2.entries()) {
                    if (desc.type === 1) {
                        introWithUID = introWithUID + desc.raw_text;
                    } else if (desc.type === 2) {
                        introWithUID = introWithUID + `@${desc.raw_text}{{UID:${desc.biz_id}}}` + (index === response.response.data.desc_v2.length - 1 ? '' : ' ');
                    } else {
                        if (enableDebug) console.warn(`getFromApiExtra desc_v2未知type: ${desc.type}`);
                    }
                }
                updateArrayDataInBackup(backup, 'intro', introWithUID, getCurrentTs(), 'api.bilibili.com/x/web-interface/view');
            }
            updateArrayDataInBackup(backup, 'dynamic', response.response.data.dynamic, getCurrentTs(), 'api.bilibili.com/x/web-interface/view');

            response.response.data.pages.forEach(el => {
                updatePagesInBackup(backup, el.page, el.part, el.first_frame, el.cid, getCurrentTs(), 'api.bilibili.com/x/web-interface/view');
            });

            backup.apiExtra = { value: true, ts: getCurrentTs() };
            spanA.style.color = '#008000';
        }

        const sortedBackup = {};
        for (const sortedKey of sortedKeys) {
            sortedBackup[sortedKey] = backup[sortedKey];
        }
        GM_setValue(AVBVTitle.BV, sortedBackup);
        if (enableDebug) console.log('保存B站接口的额外数据至本地');
        if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
        if (enableDebug) console.debug(sortedBackup);
    }

    async function getFromBiliplus(AVBVTitle, backup, spanB) {

        const response = await new Promise((resolve, reject) => {
            GM.xmlHttpRequest({
                method: 'GET',
                url: `https://www.biliplus.com/video/${AVBVTitle.BV}`,
                timeout: 5000,
                onload: (res) => resolve(res),
                onerror: (res) => reject(['请求失败', 'www.biliplus.com/video', res.error]),
                ontimeout: () => reject(['请求超时', 'www.biliplus.com/video'])
            });
        });

        const json = JSON.parse(response.response.match(getJsonFromBiliplusRegex)[1]);
        if (json.title) {
            if (enableDebug) console.log('从BiliPlus获取有效数据');
            if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
            if (enableDebug) console.debug(json);

            if (!json.lastupdatets) {
                if (!json.lastupdate) {
                    throw ['从BiliPlus获取的数据中无备份时间, 请反馈该问题'];
                }
                if (!localeTimeStringRegex.test(json.lastupdate)) {
                    throw ['从BiliPlus获取的数据中备份时间不符合规范, 请反馈该问题'];
                }
                if (isNaN(new Date(json.lastupdate).getTime())) {
                    throw ['从BiliPlus获取的数据中备份时间不符合规范, 请反馈该问题'];
                }
                json.lastupdatets = new Date(json.lastupdate).getTime() / 1000;
            }

            updateArrayDataInBackup(backup, 'title', json.title, json.lastupdatets, 'www.biliplus.com/video');
            updateArrayDataInBackup(backup, 'intro', json.description, json.lastupdatets, 'www.biliplus.com/video');
            updateArrayDataInBackup(backup, 'cover', json.pic, json.lastupdatets, 'www.biliplus.com/video');
            updateArrayDataInBackup(backup, 'upperName', json.author, json.lastupdatets, 'www.biliplus.com/video');

            json.list.forEach(el => {
                updatePagesInBackup(backup, el.page, el.part, el.first_frame, el.cid, json.lastupdatets, 'www.biliplus.com/video');
            });

            if (json.v2_app_api) {
                updateArrayDataInBackup(backup, 'title', json.v2_app_api.title, json.lastupdatets, 'www.biliplus.com/video');
                updateArrayDataInBackup(backup, 'intro', json.v2_app_api.desc, json.lastupdatets, 'www.biliplus.com/video');
                updateArrayDataInBackup(backup, 'cover', json.v2_app_api.pic, json.lastupdatets, 'www.biliplus.com/video');
                updateArrayDataInBackup(backup, 'upperName', json.v2_app_api.owner.name, json.lastupdatets, 'www.biliplus.com/video');
                updateArrayDataInBackup(backup, 'upperAvatar', json.v2_app_api.owner.face, json.lastupdatets, 'www.biliplus.com/video');

                ///////////////////////////////////////////////////////////////////////////////////
                // if (json.v2_app_api.cid && json.v2_app_api.cid !== json.list[0].cid) {
                //     console.error(json.v2_app_api.cid);
                //     console.error(json.list[0].cid);
                //     console.error('getFromBiliplus cid 不一致1');
                // }
                // if (json.v2_app_api.cid && json.v2_app_api.cid !== json.v2_app_api.pages[0].cid) {
                //     console.error(json.v2_app_api.cid);
                //     console.error(json.v2_app_api.pages[0].cid);
                //     console.error('getFromBiliplus cid 不一致2');
                // }
                // if (json.list[0].cid !== json.v2_app_api.pages[0].cid) {
                //     console.error(json.list[0].cid);
                //     console.error(json.v2_app_api.pages[0].cid);
                //     console.error('getFromBiliplus cid 不一致3');
                // }
                ///////////////////////////////////////////////////////////////////////////////////
                if (json.v2_app_api.first_frame !== json.v2_app_api.pages[0].first_frame) {
                    if (enableDebug) console.warn('getFromBiliplus firstFrame 不一致');
                    if (enableDebug) console.warn(json.v2_app_api.first_frame);
                    if (enableDebug) console.warn(json.v2_app_api.pages[0].first_frame);
                    updatePagesInBackup(backup, 0, undefined, json.v2_app_api.first_frame, 0, json.lastupdatets, 'www.biliplus.com/video');
                }

                updateArrayDataInBackup(backup, 'dynamic', json.v2_app_api.dynamic, json.lastupdatets, 'www.biliplus.com/video');
                json.v2_app_api.pages.forEach(el => {
                    updatePagesInBackup(backup, el.page, el.part, el.first_frame, el.cid, json.lastupdatets, 'www.biliplus.com/video');
                });
            }

            backup.biliplus = { value: true, ts: getCurrentTs() };
            spanB.style.color = '#00ff00';

        } else {
            if (enableDebug) console.log('从BiliPlus获取无效数据');
            if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
            if (enableDebug) console.debug(json);
            backup.biliplus = { value: false, ts: getCurrentTs() };
            spanB.style.color = '#ff0000';
        }
    }

    async function getFromJijidown(AVBVTitle, backup, spanJ) {

        let retryCount = 0;
        while (true) {
            const response = await new Promise((resolve, reject) => {
                GM.xmlHttpRequest({
                    method: 'GET',
                    url: `https://${settings.getFromJijidownURL}/api/v1/video_bv/get_info?id=${AVBVTitle.BV.slice(2)}`,
                    timeout: 5000,
                    responseType: 'json',
                    onload: (res) => resolve(res),
                    onerror: (res) => reject(['请求失败', `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`, res.error]),
                    ontimeout: () => reject(['请求超时', `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`])
                });
            });

            if (enableDebug) console.debug(response);
            if (response.status !== 200) {
                throw ['请求失败', `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`, `${response.status} ${response.statusText}`];
            }

            if (response.response.upid > 0) {
                if (enableDebug) console.log('从唧唧获取有效数据');
                if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
                if (enableDebug) console.debug(response.response);

                updateArrayDataInBackup(backup, 'title', response.response.title, response.response.ltime, `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`);
                if (response.response.desc) {
                    updateArrayDataInBackup(backup, 'intro', decodeHTMLEntities(response.response.desc.replaceAll('<br/>', '\n').replaceAll('\r', '\\r')).replaceAll('\\r', '\r'), response.response.ltime, `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`);
                }
                updateArrayDataInBackup(backup, 'cover', response.response.img, response.response.ltime, `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`);
                if (response.response.up.id > 0) {
                    updateArrayDataInBackup(backup, 'upperName', response.response.up.author, response.response.ltime, `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`);
                    updateArrayDataInBackup(backup, 'upperAvatar', response.response.up.avatar, response.response.ltime, `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`);
                }

                backup.jijidown = { value: true, ts: getCurrentTs() };
                spanJ.style.color = '#00ff00';

                if (settings.enableGetFromJijidownExtra && (!backup.jijidownExtra || (!settings.advancedDisableUpdateGetFromJijidownExtra && getCurrentTs() - backup.jijidownExtra.ts > 3600 * 24 * 7 * settings.advancedIntervalGetFromJijidownExtra))) {
                    await getFromJijidownExtra(AVBVTitle, backup, spanJ, response.response.ltime);
                }

                return;

            } else if (response.response.msg === 'loading') {
                retryCount++;
                if (enableDebug) console.log('从唧唧获取无效数据');
                if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
                if (enableDebug) console.log(`请求重试次数: ${retryCount}`);
                if (enableDebug) console.debug(response.response);

                if (retryCount > 4) {
                    throw ['请求重试次数过多', `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`];
                }

            } else {
                if (enableDebug) console.log('从唧唧获取无效数据');
                if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
                if (enableDebug) console.debug(response.response);
                backup.jijidown = { value: false, ts: getCurrentTs() };
                if (settings.enableGetFromJijidownExtra && (!backup.jijidownExtra || (!settings.advancedDisableUpdateGetFromJijidownExtra && getCurrentTs() - backup.jijidownExtra.ts > 3600 * 24 * 7 * settings.advancedIntervalGetFromJijidownExtra))) {
                    backup.jijidownExtra = { value: false, ts: getCurrentTs() };
                    spanJ.style.color = '#800000';
                } else {
                    spanJ.style.color = '#ff0000';
                }
                return;
            }

            await delay(600);
        }
    }

    async function getFromJijidownExtra(AVBVTitle, backup, spanJ, ts) {

        const response = await new Promise((resolve, reject) => {
            GM.xmlHttpRequest({
                method: 'GET',
                url: `https://${settings.getFromJijidownURL}/api/v1/video_bv/get_download_info?id=${AVBVTitle.BV.slice(2)}`,
                timeout: 5000,
                responseType: 'json',
                onload: (res) => resolve(res),
                onerror: (res) => reject(['请求失败', `${settings.getFromJijidownURL}/api/v1/video_bv/get_download_info`, res.error]),
                ontimeout: () => reject(['请求超时', `${settings.getFromJijidownURL}/api/v1/video_bv/get_download_info`])
            });
        });

        if (enableDebug) console.debug(response);
        if (response.status !== 200) {
            throw ['请求失败', `${settings.getFromJijidownURL}/api/v1/video_bv/get_download_info`, `${response.status} ${response.statusText}`];
        }

        if (response.response.res && response.response.res.length) {
            if (enableDebug) console.log('从唧唧获取有效额外数据');
            if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
            if (enableDebug) console.debug(response.response);

            response.response.res.forEach(el => {
                updatePagesInBackup(backup, 0, el.part, undefined, el.cid, ts, `${settings.getFromJijidownURL}/api/v1/video_bv/get_download_info`);
            });

            backup.jijidownExtra = { value: true, ts: getCurrentTs() };
            spanJ.style.color = '#008000';

        } else {
            if (enableDebug) console.log('从唧唧获取无效额外数据');
            if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
            if (enableDebug) console.debug(response.response);
            backup.jijidownExtra = { value: false, ts: getCurrentTs() };
            spanJ.style.color = '#800000';
        }
    }

    async function getFromXbeibeix(AVBVTitle, backup, spanX) {

        const response = await new Promise((resolve, reject) => {
            GM.xmlHttpRequest({
                method: 'GET',
                url: `https://${settings.getFromXbeibeixURL}/video/${AVBVTitle.BV}`,
                timeout: 5000,
                onload: (res) => resolve(res),
                onerror: (res) => reject(['请求失败', `${settings.getFromXbeibeixURL}/video`, res.error]),
                ontimeout: () => reject(['请求超时', `${settings.getFromXbeibeixURL}/video`])
            });
        });

        if (enableDebug) console.debug(response);
        if (response.status !== 200) {
            throw ['请求失败', `${settings.getFromXbeibeixURL}/video`, `${response.status} ${response.statusText}`];
        }

        if (response.finalUrl !== `https://${settings.getFromXbeibeixURL}/`) {
            if (enableDebug) console.log('从贝贝工具站获取有效数据');
            if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
            if (enableDebug) console.debug(response);

            updateArrayDataInBackup(backup, 'title', response.responseXML.querySelector('h5.fw-bold').innerText, undefined, `${settings.getFromXbeibeixURL}/video`);
            if (response.responseXML.querySelector('div.col-8 > textarea').innerText) {
                updateArrayDataInBackup(backup, 'intro', decodeHTMLEntities(response.responseXML.querySelector('div.col-8 > textarea').innerText), undefined, `${settings.getFromXbeibeixURL}/video`);
            }
            updateArrayDataInBackup(backup, 'cover', response.responseXML.querySelector('div.col-4 > img').getAttribute('src'), undefined, `${settings.getFromXbeibeixURL}/video`);
            updateArrayDataInBackup(backup, 'upperName', response.responseXML.querySelector('div.input-group.mb-2 > input').value, undefined, `${settings.getFromXbeibeixURL}/video`);

            backup.xbeibeix = { value: true, ts: getCurrentTs() };
            spanX.style.color = '#00ff00';

        } else {
            if (enableDebug) console.log('从贝贝工具站获取无效数据');
            if (enableDebug) consoleAVBVTitle('debug', AVBVTitle);
            if (enableDebug) console.debug(response);
            backup.xbeibeix = { value: false, ts: getCurrentTs() };
            spanX.style.color = '#ff0000';
        }
    }

    function addMessage(msg, smallFontSize, border) {
        let px;
        if (smallFontSize) {
            px = newFreshSpace ? 11 : 10;
        } else {
            px = newFreshSpace ? 13 : 12;
        }
        const p = document.createElement('p');
        p.innerHTML = msg;
        p.style.fontSize = `${px}px`;
        if (border) {
            p.style.borderTop = '1px solid #ff0000';
        }
        divMessage.appendChild(p);

        if (divMessageHeightFixed) {
            divMessage.scrollTop = divMessage.scrollHeight;
        } else {
            if (newFreshSpace) {
                if (divMessage.scrollHeight > 320) {
                    divMessage.classList.add('backup-divMessage-heightFixed-newFreshSpace');
                    divMessageHeightFixed = true;
                    divMessage.scrollTop = divMessage.scrollHeight;
                }
            } else {
                if (divMessage.scrollHeight > 280) {
                    divMessage.classList.add('backup-divMessage-heightFixed');
                    divMessageHeightFixed = true;
                    divMessage.scrollTop = divMessage.scrollHeight;
                }
            }
        }

        divMessage.scrollIntoView({ behavior: 'instant', block: 'nearest' });
    }

    function clearMessage() {
        while (divMessage.firstChild) {
            divMessage.removeChild(divMessage.firstChild);
        }
        divMessage.classList.remove('backup-divMessage-heightFixed' + classAppendNewFreshSpace);
        divMessageHeightFixed = false;
    }

    function addMessageAVBVTitle(AVBVTitle) {
        addMessage(`AV号: ${AVBVTitle.AV}`, true);
        addMessage(`BV号: ${AVBVTitle.BV}`, true);
        if (AVBVTitle.title) {
            addMessage(`标题: ${AVBVTitle.title.slice(0, 13)}`, true);
        }
    }

    function consoleAVBVTitle(type, AVBVTitle) {
        switch (type) {
            case 'debug':
                console.debug(`AV号: ${AVBVTitle.AV}`);
                console.debug(`BV号: ${AVBVTitle.BV}`);
                console.debug(`标题: ${AVBVTitle.title.slice(0, 13)}`);
                break;
            case 'log':
                console.log(`AV号: ${AVBVTitle.AV}`);
                console.log(`BV号: ${AVBVTitle.BV}`);
                console.log(`标题: ${AVBVTitle.title.slice(0, 13)}`);
                break;
            case 'warn':
                console.warn(`AV号: ${AVBVTitle.AV}`);
                console.warn(`BV号: ${AVBVTitle.BV}`);
                console.warn(`标题: ${AVBVTitle.title.slice(0, 13)}`);
                break;
            case 'error':
                console.error(`AV号: ${AVBVTitle.AV}`);
                console.error(`BV号: ${AVBVTitle.BV}`);
                if (AVBVTitle.title) {
                    console.error(`标题: ${AVBVTitle.title.slice(0, 13)}`);
                }
                break;
            default:
                throw Error('invalid type');
        }
    }

    function catchUnknownError(error) {
        addMessage('发生未知错误, 请反馈该问题', false, true);
        addMessage(error.stack, true);
        console.error(error);
    }

    function delay(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    function getCurrentTs() {
        return Math.floor(Date.now() / 1000);
    }

    function abortActiveControllers() {
        for (const controller of activeControllers) {
            controller.abort();
        }
    }

    function formatTsTimeFavorite(t) {
        const e = new Date();
        const n = e.getTime();
        const r = t.getTime();
        const o = n - r;
        return o < 6e4
            ? '刚刚'
            : o < 36e5
                ? Math.floor(o / 6e4) + '分钟前'
                : o < 864e5
                    ? Math.floor(o / 36e5) + '小时前'
                    : r >= new Date(e.getFullYear(), e.getMonth(), e.getDate() - 1).getTime()
                        ? '昨天'
                        : r >= new Date(e.getFullYear(), 0, 1).getTime()
                            ? (t.getMonth() + 1) + '-' + t.getDate()
                            // : o < 63072e6
                            //     ? t.getFullYear() + '-' + (t.getMonth() + 1) + '-' + t.getDate()
                            //     : '2年前';
                            : t.getFullYear() + '-' + (t.getMonth() + 1) + '-' + t.getDate();
    }

    function formatTsYYMMDD_HHMMSS(ts) {
        const date = new Date(ts * 1000);
        const year = String(date.getFullYear()).slice(2);
        const month = String(date.getMonth() + 1).padStart(2, '0');
        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 formatTsTimePublish(e) {
        let n = new Date(e);
        let u = Date.now();
        if (u - e <= 6e4) {
            return '刚刚';
        }
        if (u - e < 36e5) {
            return Math.floor((u - e) / 6e4) + '分钟前';
        }
        if (u - e < 864e5) {
            return Math.floor((u - e) / 36e5) + '小时前';
        }
        if (new Date().setHours(0, 0, 0, 0) - e < 864e5) {
            return '昨天';
        }
        let l = n.getFullYear();
        let c = '0'.concat(n.getMonth() + 1).slice(-2);
        let f = '0'.concat(n.getDate()).slice(-2);
        return l === new Date().getFullYear() ? ''.concat(c, '-').concat(f) : ''.concat(l, '-').concat(c, '-').concat(f);
    }

    function decodeHTMLEntities(str) {
        return new DOMParser().parseFromString(`<!doctype html><body>${str}`, 'text/html').body.textContent;
    }

    function updateArrayDataInBackup(backup, key, value, ts, from) {
        if (!value) {
            return;
        }
        if (!ts) {
            ts = 0;
        }
        if (key === 'cover' || key === 'upperAvatar') {
            value = value.replace(getHttpsFromURLRegex, '').replace(getAvifFromURLRegex, '');
        }

        if (!backup[key]) {
            backup[key] = [];
            const data = { value, ts, from };
            backup[key].push(data);
            return;
        }

        let target;
        target = backup[key].find(el => el.value === value);
        if (target) {
            if (target.ts <= ts) {
                target.ts = ts;
                target.from = from;
                backup[key].sort((a, b) => a.ts - b.ts);
            }
            return;
        }

        if (key === 'cover' || key === 'upperAvatar') {
            target = backup[key].find(el => el.value.match(getFilenameFromURLRegex)[0] === value.match(getFilenameFromURLRegex)[0]);
            if (target) {
                if (target.ts <= ts) {
                    target.value = value;
                    target.ts = ts;
                    target.from = from;
                    backup[key].sort((a, b) => a.ts - b.ts);
                }
                return;
            }

        } else if (key === 'intro') {
            target = backup.intro.find(el => el.value.replaceAll('\r', '') === value);
            if (target) {
                return;
            }

            target = backup.intro.find(el => el.value === value.replaceAll('\r', ''));
            if (target) {
                target.value = value;
                target.ts = ts;
                target.from = from;
                backup.intro.sort((a, b) => a.ts - b.ts);
                return;
            }

            if (value.length >= 255 || ((from.includes('xbeibeix') || from.includes('bbdownloader')) && value.length >= 200)) {
                target = backup.intro.find(el => el.value.replaceAll('\r', '').startsWith(value.replaceAll('\r', '')));
                if (target) {
                    return;
                }

                target = backup.intro.find(el => value.replaceAll('\r', '').startsWith(el.value.replaceAll('\r', '')));
                if (target) {
                    target.value = value;
                    target.ts = ts;
                    target.from = from;
                    backup.intro.sort((a, b) => a.ts - b.ts);
                    return;
                }
            }
        }

        const data = { value, ts, from };
        backup[key].push(data);
        backup[key].sort((a, b) => a.ts - b.ts);
    }

    function updateTimeFavoriteInBackup(backup, value, fid) {
        if (!value) {
            value = 0;
        }
        if (!backup.timeFavorite) {
            backup.timeFavorite = [];
            const data = { value, fid };
            backup.timeFavorite.push(data);
            return true;

        } else {
            const target = backup.timeFavorite.find(el => el.fid === fid);
            if (target) {
                if (target.value < value) {
                    target.value = value;
                    backup.timeFavorite.sort((a, b) => a.value - b.value);
                    return true;
                }
            } else {
                const data = { value, fid };
                backup.timeFavorite.push(data);
                backup.timeFavorite.sort((a, b) => a.value - b.value);
                return true;
            }
        }
    }

    function updatePagesInBackup(backup, index, title, firstFrame, cid, ts, from) {
        if (!index && index !== 0) {
            index = null;
        }
        if (title) {
            if (typeof title !== 'object') {
                title = [title];
            }
        } else {
            title = null;
        }
        if (firstFrame) {
            firstFrame = firstFrame.replace(getHttpsFromURLRegex, '').replace(getAvifFromURLRegex, '');
        } else {
            firstFrame = null;
        }
        if (!cid && cid !== 0) {
            cid = null;
        }
        if (!ts) {
            ts = 0;
        }

        if (!backup.pages) {
            backup.pages = [];
            const data = { index, title, firstFrame, cid, ts, from };
            backup.pages.push(data);

        } else {
            const target = backup.pages.find(el => el.cid === cid);
            if (target) {
                let modified = false;
                if (index) {
                    if (!target.index) {
                        target.index = index;
                        modified = true;
                    } else if (target.index !== index) {
                        if (enableDebug) console.warn('updatePagesInBackup index不一致');
                        if (enableDebug) console.warn(`旧: ${target.index}`);
                        if (enableDebug) console.warn(`新: ${index}`);
                        target.index = index;
                        modified = true;
                    }
                }
                if (title) {
                    if (!target.title) {
                        target.title = title;
                        modified = true;
                    } else {
                        title.forEach(el => {
                            if (!target.title.find(ele => ele === el)) {
                                if (enableDebug) console.warn('updatePagesInBackup title不一致');
                                target.title.push(el);
                                modified = true;
                            }
                        });
                    }
                }
                if (firstFrame) {
                    if (!target.firstFrame) {
                        target.firstFrame = firstFrame;
                        modified = true;
                    } else if (target.firstFrame !== firstFrame) {
                        if (enableDebug) console.warn('updatePagesInBackup firstFrame不一致');
                        if (enableDebug) console.warn(`旧: ${target.firstFrame}`);
                        if (enableDebug) console.warn(`新: ${firstFrame}`);
                        // target.firstFrame = firstFrame;
                        // modified = true;
                    }
                }
                if (target.ts <= ts) {
                    target.ts = ts;
                    modified = true;
                }
                if (modified) {
                    target.from = from;
                    backup.pages.sort((a, b) => {
                        if (a.index !== b.index) {
                            return a.index - b.index;
                        } else if (a.ts !== b.ts) {
                            return a.ts - b.ts;
                        } else {
                            return a.cid - b.cid;
                        }
                    });
                }

            } else {
                if (backup.pages.find(el => el.index === index)) {
                    if (enableDebug) console.warn(`updatePagesInBackup 分集${index}更改`);
                }
                const data = { index, title, firstFrame, cid, ts, from };
                backup.pages.push(data);
                backup.pages.sort((a, b) => {
                    if (a.index !== b.index) {
                        return a.index - b.index;
                    } else if (a.ts !== b.ts) {
                        return a.ts - b.ts;
                    } else {
                        return a.cid - b.cid;
                    }
                });
            }
        }
    }

    async function appendParamsForGetFromApi(fid, pageNumber, pageSize) {
        const inputKeyword = document.querySelector(newFreshSpace ? 'input.fav-list-header-filter__search' : 'input.search-fav-input');
        let keyword = '';
        if (inputKeyword) {
            keyword = encodeURIComponent(inputKeyword.value);
        }
        if (enableDebug) console.log(`keyword: ${decodeURIComponent(keyword)}`);
        if (enableDebug) console.log(keyword);

        if (!newFreshSpace) {
            const divFilterOrder = document.querySelector('div.fav-filters > div:nth-child(3) > span');
            let orderText = '收藏';
            if (divFilterOrder) {
                orderText = divFilterOrder.innerText;
            }
            if (orderText.includes('收藏')) {
                order = 'mtime';
            } else if (orderText.includes('播放')) {
                order = 'view';
            } else if (orderText.includes('投稿')) {
                order = 'pubtime';
            } else {
                throw ['无法确定各个视频的排序方式, 请反馈该问题'];
            }
        }
        if (enableDebug) console.log(`order: ${order}`);

        const divType = document.querySelector(newFreshSpace ? 'div.vui_input__prepend' : 'div.search-types');
        let typeText = '当前';
        if (divType) {
            typeText = divType.innerText;
        }
        if (newFreshSpace && keyword === '') {
            typeText = '当前';
        }
        if (enableDebug) console.log(`typeText: ${typeText}`);
        let type;
        if (typeText.includes('当前')) {
            type = 0;
        } else if (typeText.includes('全部')) {
            type = 1;
        } else {
            throw ['无法确定搜索的范围为当前收藏夹还是全部收藏夹, 请反馈该问题'];
        }
        if (enableDebug) console.log(`type: ${type}`);

        const divTid = document.querySelector(newFreshSpace ? 'div.fav-list-header-collapse div.radio-filter__item--active' : 'div.fav-filters > div:nth-child(2) > span');
        let tidText = '全部分区';
        if (divTid) {
            tidText = divTid.innerText;
        }
        if (enableDebug) console.log(`tidText: ${tidText}`);
        let tid;
        if (tidText.includes('全部')) {
            tid = 0;
        } else {
            const UID = parseInt(location.href.match(getUIDFromURLRegex)[1], 10);
            const response = await new Promise((resolve, reject) => {
                GM.xmlHttpRequest({
                    method: 'GET',
                    url: `https://api.bilibili.com/x/v3/fav/resource/partition?up_mid=${UID}&media_id=${fid}` + (newFreshSpace ? '&web_location=333.1387' : ''),
                    timeout: 5000,
                    responseType: 'json',
                    onload: (res) => resolve(res),
                    onerror: (res) => reject(['请求失败', 'api.bilibili.com/x/v3/fav/resource/partition', res.error]),
                    ontimeout: () => reject(['请求超时', 'api.bilibili.com/x/v3/fav/resource/partition'])
                });
            });
            const partitions = response.response.data;
            const target = partitions.find(el => tidText.includes(el.name));
            if (target) {
                tid = target.tid;
            } else {
                throw ['无法确定选择的分区, 请反馈该问题'];
            }
        }
        if (enableDebug) console.log(`tid: ${tid}`);

        if (enableDebug) console.log(`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${fid}&pn=${pageNumber}&ps=${pageSize}&keyword=${keyword}&order=${order}&type=${type}&tid=${tid}&platform=web` + (newFreshSpace ? '&web_location=333.1387' : ''));
        return (`https://api.bilibili.com/x/v3/fav/resource/list?media_id=${fid}&pn=${pageNumber}&ps=${pageSize}&keyword=${keyword}&order=${order}&type=${type}&tid=${tid}&platform=web` + (newFreshSpace ? '&web_location=333.1387' : ''));
    }

    function validateInputText(event) {
        const inputText = event.target;
        let value = inputText.value.trim();
        const def = parseInt(inputText.getAttribute('backup-def'), 10);
        if (!value || isNaN(value)) {
            value = def;
        } else {
            value = parseInt(value, 10);
            const min = parseInt(inputText.getAttribute('backup-min'), 10);
            const max = parseInt(inputText.getAttribute('backup-max'), 10);
            if (value < min) {
                value = min;
            } else if (value > max) {
                value = max;
            }
        }
        inputText.value = value;
        const key = inputText.getAttribute('backup-setting');
        settings[key] = value;
        GM_setValue('settings', settings);
    }

    // async function mainNewFreshSpace(mutations) {
    // async function mainNewFreshSpace() {

    // mutations_count++;
    // console.debug('mutations_count' + mutations_count);
    // for (const mutation of mutations) {
    //     mutation_count++;
    //     console.debug('mutation_count' + mutation_count);
    //     console.debug(mutation);
    // }

    // if (firstTime) {
    //     firstTime = false;
    // } else {
    //     mutations = mutations.reverse();
    // }

    // for (const mutation of mutations) {
    //     if (mutation.addedNodes.length) {

    // const items = document.querySelectorAll('div.items__item');
    // for (const item of items) {

    // console.debug(mutation.addedNodes[0].querySelectorAll('a'));
    // console.debug(mutation.addedNodes[0].querySelectorAll('a')[1].innerText);
    // mutation.addedNodes[0].querySelectorAll('a')[1].style.color = 'red';

    // }
    // }
})();