Greasy Fork is available in English.
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 25 // @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>' + '修复: 旧版个人空间中指定关键词后无法从B站接口获取数据的问题'; const version = 25; 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 getUIDFromURLRegex = /https:\/\/space\.bilibili\.com\/(\d+)/; const getBVFromURLRegex = /video\/(BV\w{10})/; const getHttpsFromURLRegex = /^(https?:\/\/|\/\/)/; const getJsonFromBiliplusRegex = /window\.addEventListener\('DOMContentLoaded',function\(\){view\((.+)\);}\);/; const getParamsWithSignFromBiliplusRegex = /api\/view_all(.+)'/; const getFilenameFromURLRegex = /[^/]+(?:\.[a-zA-Z0-9]+)$/; const getAvifFromURLRegex = /@.*/; let onFavlistPage = false; let enableAutoNextPage = false; let enableAutoNextFavlist = false; let enableDebug = false; let newFreshSpace; let classAppendNewFreshSpace; let pageSize; let firstTimeMain = true; let di#####age; let di#####ageHeightFixed = 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', 'biliplusExtra', 'jijidown', 'jijidownExtra', 'xbeibeix', ]; const settings = GM_getValue('settings', { processNormal: true, processDisabled: true, enableGetFromApi: true, enableUpdateGetFromApi: true, intervalGetFromApi: 5, enableGetFromApiExtra: false, enableGetThumbnails: false, enableUpdateGetFromApiExtra: true, intervalGetFromApiExtra: 5, enableGetFromBiliplus: true, enableUpdateGetFromBiliplus: false, intervalGetFromBiliplus: 10, enableGetFromBiliplusExtra: false, enableUpdateGetFromBiliplusExtra: false, intervalGetFromBiliplusExtra: 10, enableGetFromJijidown: false, enableUpdateGetFromJijidown: false, intervalGetFromJijidown: 10, enableGetFromJijidownExtra: false, enableUpdateGetFromJijidownExtra: false, intervalGetFromJijidownExtra: 10, getFromJijidownURL: 'www.jijidown.com', enableGetFromXbeibeix: false, enableUpdateGetFromXbeibeix: false, intervalGetFromXbeibeix: 10, getFromXbeibeixURL: 'xbeibeix.com', intervalAutoNextPage: 5, requestTimeout: 10, delayBeforeMain: 300, appendDropdownCover: true, appendDropdownLocal: true, appendDropdownJump: true, appendDropdownReset: true, displayAdvancedControls: false, exportBackupWithoutTsFrom: false, version: 0, defaultUID: null, defaultFavlistFid: null, }); /////////////////////////////////////////////////////////////////////////////////// // enableDebug = true; // settings.delayBeforeMain = 500; // 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); } // v19 if (!settings.hasOwnProperty('displayAdvancedControls')) { settings.displayAdvancedControls = false; settings.advancedEnableUpdateGetFromApi = true; settings.advancedEnableUpdateGetFromApiExtra = true; settings.advancedEnableUpdateGetFromBiliplus = false; settings.advancedEnableUpdateGetFromJijidown = false; settings.advancedEnableUpdateGetFromJijidownExtra = false; settings.advancedEnableUpdateGetFromXbeibeix = false; 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); } // v19 if (settings.hasOwnProperty('advancedDisableUpdateGetFromApi')) { settings.advancedEnableUpdateGetFromApi = !settings.advancedDisableUpdateGetFromApi; settings.advancedEnableUpdateGetFromApiExtra = !settings.advancedDisableUpdateGetFromApiExtra; settings.advancedEnableUpdateGetFromBiliplus = !settings.advancedDisableUpdateGetFromBiliplus; settings.advancedEnableUpdateGetFromJijidown = !settings.advancedDisableUpdateGetFromJijidown; settings.advancedEnableUpdateGetFromJijidownExtra = !settings.advancedDisableUpdateGetFromJijidownExtra; settings.advancedEnableUpdateGetFromXbeibeix = !settings.advancedDisableUpdateGetFromXbeibeix; delete settings.advancedDisableUpdateGetFromApi; delete settings.advancedDisableUpdateGetFromApiExtra; delete settings.advancedDisableUpdateGetFromBiliplus; delete settings.advancedDisableUpdateGetFromJijidown; delete settings.advancedDisableUpdateGetFromJijidownExtra; delete settings.advancedDisableUpdateGetFromXbeibeix; GM_setValue('settings', settings); } // v20 if (settings.hasOwnProperty('advancedIntervalAutoNextPage')) { settings.enableUpdateGetFromApi = settings.advancedEnableUpdateGetFromApi; settings.enableUpdateGetFromApiExtra = settings.advancedEnableUpdateGetFromApiExtra; settings.enableUpdateGetFromBiliplus = settings.advancedEnableUpdateGetFromBiliplus; settings.enableUpdateGetFromJijidown = settings.advancedEnableUpdateGetFromJijidown; settings.enableUpdateGetFromJijidownExtra = settings.advancedEnableUpdateGetFromJijidownExtra; settings.enableUpdateGetFromXbeibeix = settings.advancedEnableUpdateGetFromXbeibeix; settings.intervalGetFromApi = settings.advancedIntervalGetFromApi; settings.intervalGetFromApiExtra = settings.advancedIntervalGetFromApiExtra; settings.intervalGetFromBiliplus = settings.advancedIntervalGetFromBiliplus; settings.intervalGetFromJijidown = settings.advancedIntervalGetFromJijidown; settings.intervalGetFromJijidownExtra = settings.advancedIntervalGetFromJijidownExtra; settings.intervalGetFromXbeibeix = settings.advancedIntervalGetFromXbeibeix; settings.intervalAutoNextPage = settings.advancedIntervalAutoNextPage; delete settings.advancedEnableUpdateGetFromApi; delete settings.advancedEnableUpdateGetFromApiExtra; delete settings.advancedEnableUpdateGetFromBiliplus; delete settings.advancedEnableUpdateGetFromJijidown; delete settings.advancedEnableUpdateGetFromJijidownExtra; delete settings.advancedEnableUpdateGetFromXbeibeix; delete settings.advancedIntervalGetFromApi; delete settings.advancedIntervalGetFromApiExtra; delete settings.advancedIntervalGetFromBiliplus; delete settings.advancedIntervalGetFromJijidown; delete settings.advancedIntervalGetFromJijidownExtra; delete settings.advancedIntervalGetFromXbeibeix; delete settings.advancedIntervalAutoNextPage; GM_setValue('settings', settings); } // v20 if (settings.hasOwnProperty('advancedRequestTimeout')) { settings.requestTimeout = settings.advancedRequestTimeout; delete settings.advancedRequestTimeout; GM_setValue('settings', settings); } // v20 if (!settings.hasOwnProperty('requestTimeout')) { settings.requestTimeout = 10; GM_setValue('settings', settings); } // v20 if (settings.hasOwnProperty('advancedExportBackupWithoutTsFrom')) { settings.exportBackupWithoutTsFrom = settings.advancedExportBackupWithoutTsFrom; delete settings.advancedExportBackupWithoutTsFrom; GM_setValue('settings', settings); } // v20 if (!settings.hasOwnProperty('exportBackupWithoutTsFrom')) { settings.exportBackupWithoutTsFrom = false; GM_setValue('settings', settings); } // v20 if (!settings.hasOwnProperty('enableGetThumbnails')) { settings.enableGetThumbnails = false; GM_setValue('settings', settings); } // v21 if (!settings.hasOwnProperty('delayBeforeMain')) { settings.delayBeforeMain = 300; settings.appendDropdownCover = true; settings.appendDropdownLocal = true; settings.appendDropdownJump = true; settings.appendDropdownReset = true; GM_setValue('settings', settings); } // v22 if (!settings.hasOwnProperty('enableGetFromBiliplusExtra')) { settings.enableGetFromBiliplusExtra = false; settings.enableUpdateGetFromBiliplusExtra = false; settings.intervalGetFromBiliplusExtra = 10; 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(settings.delayBeforeMain); 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 () => { abortActiveControllers(); if (enableDebug) console.debug('callback itemsObserver'); await delay(settings.delayBeforeMain); 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; enableAutoNextPage = false; enableAutoNextFavlist = false; 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 currentFavlist; if (newFreshSpace) { currentFavlist = document.querySelector('div.vui_sidebar-item--active'); if (!document.querySelector('div.fav-collapse').contains(currentFavlist)) { if (enableDebug) console.log('不处理特殊收藏夹'); return; } } else { currentFavlist = document.querySelector('.fav-item.cur'); if (!document.querySelector('div.nav-container').contains(currentFavlist)) { if (enableDebug) console.log('不处理特殊收藏夹'); return; } } let fid; if (newFreshSpace) { const getFidFromURLMatch = location.href.match(getFidFromURLRegex); if (getFidFromURLMatch) { fid = parseInt(getFidFromURLMatch[1], 10); if (!settings.defaultFavlistFid && !currentFavlist.parentNode.getAttribute('id')) { settings.defaultFavlistFid = fid; GM_setValue('settings', settings); } } else if (settings.defaultFavlistFid) { fid = settings.defaultFavlistFid; } else { throw ['无法获取当前收藏夹的fid, 刷新页面可能有帮助']; } } else { fid = parseInt(currentFavlist.getAttribute('fid'), 10); } 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'); 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'); } 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 = 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, biliplusExtra: null, jijidown: null, jijidownExtra: null, xbeibeix: null, }); if (!backup.BV) { backup.BV = AVBVTitle.BV; GM_setValue(AVBVTitle.BV, backup); } AVBVTitle.AV = backup.AV; formatBackup(backup, true, AVBVTitle.BV); if (updateTimeFavoriteNeeded() && updateTimeFavoriteInBackup(backup, undefined, fid)) { GM_setValue(AVBVTitle.BV, backup); } const functions = []; try { if (newFreshSpace) { if (backup.timePublish) { spanFavTime.textContent = `投稿于:${formatTsTimePublish(1000 * backup.timePublish)}`; spanFavTime.setAttribute('title', new Date(1000 * backup.timePublish).toLocaleString()); } } else { if (backup.timeFavorite) { const target = backup.timeFavorite.find(el => el.fid === fid); if (target && target.value) { spanFavTime.textContent = `收藏于:${formatTsTimeFavorite(new Date(1000 * target.value))}`; spanFavTime.setAttribute('title', new Date(1000 * target.value).toLocaleString()); } } } if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (settings.enableGetFromApi) { if (!backup.api || (settings.enableUpdateGetFromApi && getCurrentTs() - backup.api.ts > 3600 * settings.intervalGetFromApi)) { 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 (updateTimeFavoriteNeeded() && 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 (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (settings.enableGetFromApiExtra) { if (!backup.apiExtra || (settings.enableUpdateGetFromApiExtra && getCurrentTs() - backup.apiExtra.ts > 3600 * 24 * settings.intervalGetFromApiExtra)) { await getFromApiExtra(AVBVTitle, backup, spanA, disabled, controller); } else { spanA.style.color = backup.apiExtra.value ? '#008000' : '#800000'; } } if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (settings.enableGetFromJijidown) { if (!backup.jijidown || (settings.enableUpdateGetFromJijidown && getCurrentTs() - backup.jijidown.ts > 3600 * 24 * 7 * settings.intervalGetFromJijidown)) { functions.push(getFromJijidown(AVBVTitle, backup, spanJ)); } else { if (settings.enableGetFromJijidownExtra) { if (!backup.jijidownExtra || (settings.enableUpdateGetFromJijidownExtra && getCurrentTs() - backup.jijidownExtra.ts > 3600 * 24 * 7 * settings.intervalGetFromJijidownExtra)) { 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.enableUpdateGetFromXbeibeix && getCurrentTs() - backup.xbeibeix.ts > 3600 * 24 * 7 * settings.intervalGetFromXbeibeix)) { functions.push(getFromXbeibeix(AVBVTitle, backup, spanX)); } else { spanX.style.color = backup.xbeibeix.value ? '#00ff00' : '#ff0000'; } } if (settings.enableGetFromBiliplus) { if (!backup.biliplus || (settings.enableUpdateGetFromBiliplus && getCurrentTs() - backup.biliplus.ts > 3600 * 24 * 7 * settings.intervalGetFromBiliplus)) { 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); } if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (settings.enableGetFromBiliplusExtra) { if (!backup.biliplusExtra || (settings.enableUpdateGetFromBiliplusExtra && getCurrentTs() - backup.biliplusExtra.ts > 3600 * 24 * 7 * settings.intervalGetFromBiliplusExtra)) { await getFromBiliplusExtra(AVBVTitle, backup, spanB); } else { spanB.style.color = backup.biliplusExtra.value ? '#008000' : '#800000'; } } } 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'); if (enableDebug) { if (!img.getAttribute('src').endsWith('@672w_378h_1c.avif')) { addMessage('封面avif已更改'); console.warn('封面avif已更改'); } } } 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.slice(8)}@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.slice(8)}@320w_200h_1c_!web-space-favlist-video.avif`); sourceWebp.setAttribute('srcset', `//${backup.cover[backup.cover.length - 1].value.slice(8)}@320w_200h_1c_!web-space-favlist-video.webp`); img.setAttribute('src', `//${backup.cover[backup.cover.length - 1].value.slice(8)}@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.slice(8)}@672w_378h_1c.avif`); } else { sourceAvif.setAttribute('srcset', `//${backup.cover[i].value.slice(8)}@320w_200h_1c_!web-space-favlist-video.avif`); sourceWebp.setAttribute('srcset', `//${backup.cover[i].value.slice(8)}@320w_200h_1c_!web-space-favlist-video.webp`); img.setAttribute('src', `//${backup.cover[i].value.slice(8)}@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); } } } 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.intervalAutoNextPage); if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (enableAutoNextPage) { pager.click(); } } else if (enableAutoNextFavlist) { if (!currentFavlist.parentNode.getAttribute('id')) { if (document.querySelector('div.fav-sortable-list').childElementCount) { await delay(1000 * settings.intervalAutoNextPage); if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (enableAutoNextFavlist) { document.querySelector('div.fav-sortable-list').firstElementChild.querySelector('div').click(); } } } else { const nextFavlist = currentFavlist.parentNode.nextElementSibling; if (nextFavlist) { await delay(1000 * settings.intervalAutoNextPage); if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (enableAutoNextFavlist) { nextFavlist.querySelector('div').click(); } } } } } else { const pager = document.querySelector('li.be-pager-next'); if (pager && !pager.classList.contains('be-pager-disabled')) { await delay(1000 * settings.intervalAutoNextPage); if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (enableAutoNextPage) { pager.click(); } } else if (enableAutoNextFavlist) { if (currentFavlist.nodeName === 'DIV') { if (document.querySelector('ul.fav-list').childElementCount) { await delay(1000 * settings.intervalAutoNextPage); if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (enableAutoNextFavlist) { document.querySelector('ul.fav-list').firstElementChild.querySelector('a').click(); } } } else { const nextFavlist = currentFavlist.nextElementSibling; if (nextFavlist) { await delay(1000 * settings.intervalAutoNextPage); if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (enableAutoNextFavlist) { nextFavlist.querySelector('a').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 16px; } .backup-div-second-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: 28px; height: 14px; border-radius: 2px; font-size: 14px; } .backup-inputText-newFreshSpace { width: 32px; 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-di#####age, .backup-di#####age-newFreshSpace { overflow-y: auto; background-color: #eeeeee; line-height: 1.5; scrollbar-width: none; } .backup-di#####age { margin: 2px; } .backup-di#####age-heightFixed { height: 280px; } .backup-di#####age::-webkit-scrollbar { display: none; } .backup-di#####age-newFreshSpace { margin: 2px 0; } .backup-di#####age-heightFixed-newFreshSpace { height: 320px; } .backup-di#####age-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; if (!settings.processNormal && !settings.processDisabled) { divLabelEnableGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromXbeibeix.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) { divLabelEnableUpdateGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromApi) { divLabelIntervalGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace); } divLabelEnableGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromApiExtra) { divLabelEnableGetThumbnails.classList.remove('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromApiExtra) { divLabelIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } } divLabelEnableGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromBiliplus) { divLabelEnableUpdateGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromBiliplus) { divLabelIntervalGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } if (settings.enableGetFromApi && settings.enableGetFromBiliplus) { divLabelEnableGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromBiliplusExtra) { divLabelEnableUpdateGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromBiliplusExtra) { divLabelIntervalGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } } divLabelEnableGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromJijidown) { divLabelEnableUpdateGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromJijidown) { divLabelIntervalGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace); } divLabelEnableGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromJijidownExtra) { divLabelEnableUpdateGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromJijidownExtra) { divLabelIntervalGetFromJijidownExtra.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) { divLabelEnableUpdateGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromXbeibeix) { divLabelIntervalGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace); } divSwitchGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } GM_setValue('settings', settings); } 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; if (!settings.processNormal && !settings.processDisabled) { divLabelEnableGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromXbeibeix.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) { divLabelEnableUpdateGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromApi) { divLabelIntervalGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace); } divLabelEnableGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromApiExtra) { divLabelEnableGetThumbnails.classList.remove('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromApiExtra) { divLabelIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } } divLabelEnableGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromBiliplus) { divLabelEnableUpdateGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromBiliplus) { divLabelIntervalGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace); } if (settings.enableGetFromApi) { divLabelEnableGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromBiliplusExtra) { divLabelEnableUpdateGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromBiliplusExtra) { divLabelIntervalGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } } } divLabelEnableGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromJijidown) { divLabelEnableUpdateGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromJijidown) { divLabelIntervalGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace); } divLabelEnableGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromJijidownExtra) { divLabelEnableUpdateGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromJijidownExtra) { divLabelIntervalGetFromJijidownExtra.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) { divLabelEnableUpdateGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromXbeibeix) { divLabelIntervalGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace); } divSwitchGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelProcessDisabled.insertAdjacentElement('afterbegin', checkboxProcessDisabled); const divLabelEnableGetFromApi = document.createElement('div'); divLabelEnableGetFromApi.classList.add('backup-div-first' + 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主头像地址, 上传时间, 发布时间, 添加到当前收藏夹的时间, 第1个分集的cid (均为最新版本)\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; settings.enableGetThumbnails = false; checkboxEnableGetThumbnails.checked = false; settings.enableGetFromBiliplusExtra = false; checkboxEnableGetFromBiliplusExtra.checked = false; divLabelEnableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelEnableUpdateGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromApi) { divLabelIntervalGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace); } divLabelEnableGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromApiExtra) { divLabelEnableGetThumbnails.classList.remove('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromApiExtra) { divLabelIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } if (settings.enableGetFromBiliplus) { divLabelEnableGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromBiliplusExtra) { divLabelEnableUpdateGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromBiliplusExtra) { divLabelIntervalGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } } } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableGetFromApi.insertAdjacentElement('afterbegin', checkboxEnableGetFromApi); const divLabelEnableUpdateGetFromApi = document.createElement('div'); divLabelEnableUpdateGetFromApi.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelEnableUpdateGetFromApi.setAttribute('title', '默认: 开启\n' + '关闭后每个视频从B站接口只会获取一次数据。\n' + '不建议关闭, 因为某些视频的信息可能会经常更新。'); divControls.appendChild(divLabelEnableUpdateGetFromApi); const labelEnableUpdateGetFromApi = document.createElement('label'); labelEnableUpdateGetFromApi.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableUpdateGetFromApi.textContent = '启用更新'; divLabelEnableUpdateGetFromApi.appendChild(labelEnableUpdateGetFromApi); const checkboxEnableUpdateGetFromApi = document.createElement('input'); checkboxEnableUpdateGetFromApi.type = 'checkbox'; checkboxEnableUpdateGetFromApi.checked = settings.enableUpdateGetFromApi; checkboxEnableUpdateGetFromApi.addEventListener('change', () => { try { settings.enableUpdateGetFromApi = checkboxEnableUpdateGetFromApi.checked; if (!settings.enableUpdateGetFromApi) { divLabelIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelIntervalGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace); } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableUpdateGetFromApi.insertAdjacentElement('afterbegin', checkboxEnableUpdateGetFromApi); const divLabelIntervalGetFromApi = document.createElement('div'); divLabelIntervalGetFromApi.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelIntervalGetFromApi.setAttribute('title', '默认: 5小时\n' + '脚本处理某个视频时, 如果发现距离上次从B站接口获取到该视频的数据已经超过了设定的时间间隔, 则会再次从B站接口获取该视频的数据。'); divControls.appendChild(divLabelIntervalGetFromApi); const labelIntervalGetFromApi = document.createElement('label'); labelIntervalGetFromApi.classList.add('backup-label' + classAppendNewFreshSpace); divLabelIntervalGetFromApi.appendChild(labelIntervalGetFromApi); const inputTextIntervalGetFromApi = document.createElement('input'); inputTextIntervalGetFromApi.type = 'text'; inputTextIntervalGetFromApi.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextIntervalGetFromApi.value = settings.intervalGetFromApi; inputTextIntervalGetFromApi.setAttribute('backup-def', 5); inputTextIntervalGetFromApi.setAttribute('backup-min', 1); inputTextIntervalGetFromApi.setAttribute('backup-max', 100); inputTextIntervalGetFromApi.setAttribute('backup-setting', 'intervalGetFromApi'); inputTextIntervalGetFromApi.addEventListener('blur', validateInputText); labelIntervalGetFromApi.appendChild(document.createTextNode('最小更新间隔')); labelIntervalGetFromApi.appendChild(inputTextIntervalGetFromApi); labelIntervalGetFromApi.appendChild(document.createTextNode('小时')); const divLabelEnableGetFromApiExtra = document.createElement('div'); divLabelEnableGetFromApiExtra.classList.add('backup-div-first' + 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) { settings.enableGetThumbnails = false; checkboxEnableGetThumbnails.checked = false; divLabelEnableGetThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelEnableGetThumbnails.classList.remove('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromApiExtra) { divLabelIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableGetFromApiExtra.insertAdjacentElement('afterbegin', checkboxEnableGetFromApiExtra); const divLabelEnableGetThumbnails = document.createElement('div'); divLabelEnableGetThumbnails.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divLabelEnableGetThumbnails.setAttribute('title', '默认: 关闭\n' + '地址: https://api.bilibili.com/x/player/videoshot?aid={AV号}&cid={分集cid}\n' + '数据: 进度条缩略图地址 (失效视频以及部分旧视频无法获取)\n' + '如果UP主对某个视频进行了换源, 只要该视频的本地备份数据中保存了旧源的cid, 就可以尝试获取旧源的进度条缩略图地址。\n' + '一次请求只能获取一个分集的进度条缩略图地址, 如果某个视频的分集较多, 则需要等待一段时间。'); divControls.appendChild(divLabelEnableGetThumbnails); const labelEnableGetThumbnails = document.createElement('label'); labelEnableGetThumbnails.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableGetThumbnails.textContent = '获取进度条缩略图地址'; divLabelEnableGetThumbnails.appendChild(labelEnableGetThumbnails); const checkboxEnableGetThumbnails = document.createElement('input'); checkboxEnableGetThumbnails.type = 'checkbox'; checkboxEnableGetThumbnails.checked = settings.enableGetThumbnails; checkboxEnableGetThumbnails.addEventListener('change', () => { try { settings.enableGetThumbnails = checkboxEnableGetThumbnails.checked; GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableGetThumbnails.insertAdjacentElement('afterbegin', checkboxEnableGetThumbnails); const divLabelEnableUpdateGetFromApiExtra = document.createElement('div'); divLabelEnableUpdateGetFromApiExtra.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelEnableUpdateGetFromApiExtra.setAttribute('title', '默认: 开启'); divControls.appendChild(divLabelEnableUpdateGetFromApiExtra); const labelEnableUpdateGetFromApiExtra = document.createElement('label'); labelEnableUpdateGetFromApiExtra.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableUpdateGetFromApiExtra.textContent = '启用更新'; divLabelEnableUpdateGetFromApiExtra.appendChild(labelEnableUpdateGetFromApiExtra); const checkboxEnableUpdateGetFromApiExtra = document.createElement('input'); checkboxEnableUpdateGetFromApiExtra.type = 'checkbox'; checkboxEnableUpdateGetFromApiExtra.checked = settings.enableUpdateGetFromApiExtra; checkboxEnableUpdateGetFromApiExtra.addEventListener('change', () => { try { settings.enableUpdateGetFromApiExtra = checkboxEnableUpdateGetFromApiExtra.checked; if (!settings.enableUpdateGetFromApiExtra) { divLabelIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelIntervalGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableUpdateGetFromApiExtra.insertAdjacentElement('afterbegin', checkboxEnableUpdateGetFromApiExtra); const divLabelIntervalGetFromApiExtra = document.createElement('div'); divLabelIntervalGetFromApiExtra.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelIntervalGetFromApiExtra.setAttribute('title', '默认: 5天'); divControls.appendChild(divLabelIntervalGetFromApiExtra); const labelIntervalGetFromApiExtra = document.createElement('label'); labelIntervalGetFromApiExtra.classList.add('backup-label' + classAppendNewFreshSpace); divLabelIntervalGetFromApiExtra.appendChild(labelIntervalGetFromApiExtra); const inputTextIntervalGetFromApiExtra = document.createElement('input'); inputTextIntervalGetFromApiExtra.type = 'text'; inputTextIntervalGetFromApiExtra.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextIntervalGetFromApiExtra.value = settings.intervalGetFromApiExtra; inputTextIntervalGetFromApiExtra.setAttribute('backup-def', 5); inputTextIntervalGetFromApiExtra.setAttribute('backup-min', 1); inputTextIntervalGetFromApiExtra.setAttribute('backup-max', 100); inputTextIntervalGetFromApiExtra.setAttribute('backup-setting', 'intervalGetFromApiExtra'); inputTextIntervalGetFromApiExtra.addEventListener('blur', validateInputText); labelIntervalGetFromApiExtra.appendChild(document.createTextNode('最小更新间隔')); labelIntervalGetFromApiExtra.appendChild(inputTextIntervalGetFromApiExtra); labelIntervalGetFromApiExtra.appendChild(document.createTextNode('天')); const divLabelEnableGetFromBiliplus = document.createElement('div'); divLabelEnableGetFromBiliplus.classList.add('backup-div-first' + 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) { settings.enableGetFromBiliplusExtra = false; checkboxEnableGetFromBiliplusExtra.checked = false; divLabelEnableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelEnableUpdateGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromBiliplus) { divLabelIntervalGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace); } if (settings.enableGetFromApi) { divLabelEnableGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromBiliplusExtra) { divLabelEnableUpdateGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromBiliplusExtra) { divLabelIntervalGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } } } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableGetFromBiliplus.insertAdjacentElement('afterbegin', checkboxEnableGetFromBiliplus); const divLabelEnableUpdateGetFromBiliplus = document.createElement('div'); divLabelEnableUpdateGetFromBiliplus.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelEnableUpdateGetFromBiliplus.setAttribute('title', '默认: 关闭'); divControls.appendChild(divLabelEnableUpdateGetFromBiliplus); const labelEnableUpdateGetFromBiliplus = document.createElement('label'); labelEnableUpdateGetFromBiliplus.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableUpdateGetFromBiliplus.textContent = '启用更新'; divLabelEnableUpdateGetFromBiliplus.appendChild(labelEnableUpdateGetFromBiliplus); const checkboxEnableUpdateGetFromBiliplus = document.createElement('input'); checkboxEnableUpdateGetFromBiliplus.type = 'checkbox'; checkboxEnableUpdateGetFromBiliplus.checked = settings.enableUpdateGetFromBiliplus; checkboxEnableUpdateGetFromBiliplus.addEventListener('change', () => { try { settings.enableUpdateGetFromBiliplus = checkboxEnableUpdateGetFromBiliplus.checked; if (!settings.enableUpdateGetFromBiliplus) { divLabelIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelIntervalGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace); } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableUpdateGetFromBiliplus.insertAdjacentElement('afterbegin', checkboxEnableUpdateGetFromBiliplus); const divLabelIntervalGetFromBiliplus = document.createElement('div'); divLabelIntervalGetFromBiliplus.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelIntervalGetFromBiliplus.setAttribute('title', '默认: 10星期'); divControls.appendChild(divLabelIntervalGetFromBiliplus); const labelIntervalGetFromBiliplus = document.createElement('label'); labelIntervalGetFromBiliplus.classList.add('backup-label' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplus.appendChild(labelIntervalGetFromBiliplus); const inputTextIntervalGetFromBiliplus = document.createElement('input'); inputTextIntervalGetFromBiliplus.type = 'text'; inputTextIntervalGetFromBiliplus.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextIntervalGetFromBiliplus.value = settings.intervalGetFromBiliplus; inputTextIntervalGetFromBiliplus.setAttribute('backup-def', 10); inputTextIntervalGetFromBiliplus.setAttribute('backup-min', 1); inputTextIntervalGetFromBiliplus.setAttribute('backup-max', 100); inputTextIntervalGetFromBiliplus.setAttribute('backup-setting', 'intervalGetFromBiliplus'); inputTextIntervalGetFromBiliplus.addEventListener('blur', validateInputText); labelIntervalGetFromBiliplus.appendChild(document.createTextNode('最小更新间隔')); labelIntervalGetFromBiliplus.appendChild(inputTextIntervalGetFromBiliplus); labelIntervalGetFromBiliplus.appendChild(document.createTextNode('星期')); const divLabelEnableGetFromBiliplusExtra = document.createElement('div'); divLabelEnableGetFromBiliplusExtra.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divLabelEnableGetFromBiliplusExtra.setAttribute('title', '默认: 关闭\n' + '地址: https://www.biliplus.com/all/video/av{AV号}/\n' + '数据: 调用下面的接口所需的验证参数\n' + '地址: https://www.biliplus.com/api/view_all?av={AV号}&ts={验证参数1}&sign={验证参数2}\n' + '数据: 标题, 简介, 封面地址, UP主昵称 (第一次备份到BiliPlus时的版本); 每个分集的标题, cid (所有曾经备份到BiliPlus版本)\n' + 'BiliPlus原始页面的底部有一个刷新数据的功能, 该功能会让BiliPlus再次从B站接口获取某个视频的最新信息并保存在其数据库中。\n' + 'BiliPlus原始页面显示的信息为最后一次备份到BiliPlus时的版本, 而此接口可以获取到之前备份到BiliPlus时的版本。\n' + '请注意: 此接口有调用频率限制, 平均每分钟不能超过5次, 否则会出现请求失败的情况。\n' + '在脚本从BiliPlus获取了当前页所有视频的额外数据之后, 继续从BiliPlus获取下一页所有视频的额外数据之前, 如果您使用的是新版个人空间, 请至少等待360秒; 如果是旧版个人空间, 请至少等待180秒。'); divControls.appendChild(divLabelEnableGetFromBiliplusExtra); const labelEnableGetFromBiliplusExtra = document.createElement('label'); labelEnableGetFromBiliplusExtra.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableGetFromBiliplusExtra.textContent = '从BiliPlus获取额外数据(频率受限)'; divLabelEnableGetFromBiliplusExtra.appendChild(labelEnableGetFromBiliplusExtra); const checkboxEnableGetFromBiliplusExtra = document.createElement('input'); checkboxEnableGetFromBiliplusExtra.type = 'checkbox'; checkboxEnableGetFromBiliplusExtra.checked = settings.enableGetFromBiliplusExtra; checkboxEnableGetFromBiliplusExtra.addEventListener('change', () => { try { settings.enableGetFromBiliplusExtra = checkboxEnableGetFromBiliplusExtra.checked; if (!settings.enableGetFromBiliplusExtra) { divLabelEnableUpdateGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelEnableUpdateGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromBiliplusExtra) { divLabelIntervalGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableGetFromBiliplusExtra.insertAdjacentElement('afterbegin', checkboxEnableGetFromBiliplusExtra); const divLabelEnableUpdateGetFromBiliplusExtra = document.createElement('div'); divLabelEnableUpdateGetFromBiliplusExtra.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelEnableUpdateGetFromBiliplusExtra.setAttribute('title', '默认: 关闭'); divControls.appendChild(divLabelEnableUpdateGetFromBiliplusExtra); const labelEnableUpdateGetFromBiliplusExtra = document.createElement('label'); labelEnableUpdateGetFromBiliplusExtra.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableUpdateGetFromBiliplusExtra.textContent = '启用更新'; divLabelEnableUpdateGetFromBiliplusExtra.appendChild(labelEnableUpdateGetFromBiliplusExtra); const checkboxEnableUpdateGetFromBiliplusExtra = document.createElement('input'); checkboxEnableUpdateGetFromBiliplusExtra.type = 'checkbox'; checkboxEnableUpdateGetFromBiliplusExtra.checked = settings.enableUpdateGetFromBiliplusExtra; checkboxEnableUpdateGetFromBiliplusExtra.addEventListener('change', () => { try { settings.enableUpdateGetFromBiliplusExtra = checkboxEnableUpdateGetFromBiliplusExtra.checked; if (!settings.enableUpdateGetFromBiliplusExtra) { divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelIntervalGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableUpdateGetFromBiliplusExtra.insertAdjacentElement('afterbegin', checkboxEnableUpdateGetFromBiliplusExtra); const divLabelIntervalGetFromBiliplusExtra = document.createElement('div'); divLabelIntervalGetFromBiliplusExtra.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelIntervalGetFromBiliplusExtra.setAttribute('title', '默认: 10星期'); divControls.appendChild(divLabelIntervalGetFromBiliplusExtra); const labelIntervalGetFromBiliplusExtra = document.createElement('label'); labelIntervalGetFromBiliplusExtra.classList.add('backup-label' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplusExtra.appendChild(labelIntervalGetFromBiliplusExtra); const inputTextIntervalGetFromBiliplusExtra = document.createElement('input'); inputTextIntervalGetFromBiliplusExtra.type = 'text'; inputTextIntervalGetFromBiliplusExtra.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextIntervalGetFromBiliplusExtra.value = settings.intervalGetFromBiliplusExtra; inputTextIntervalGetFromBiliplusExtra.setAttribute('backup-def', 10); inputTextIntervalGetFromBiliplusExtra.setAttribute('backup-min', 1); inputTextIntervalGetFromBiliplusExtra.setAttribute('backup-max', 100); inputTextIntervalGetFromBiliplusExtra.setAttribute('backup-setting', 'intervalGetFromBiliplusExtra'); inputTextIntervalGetFromBiliplusExtra.addEventListener('blur', validateInputText); labelIntervalGetFromBiliplusExtra.appendChild(document.createTextNode('最小更新间隔')); labelIntervalGetFromBiliplusExtra.appendChild(inputTextIntervalGetFromBiliplusExtra); labelIntervalGetFromBiliplusExtra.appendChild(document.createTextNode('星期')); const divLabelEnableGetFromJijidown = document.createElement('div'); divLabelEnableGetFromJijidown.classList.add('backup-div-first' + 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; divLabelEnableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelEnableUpdateGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromJijidown) { divLabelIntervalGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace); } divLabelEnableGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableGetFromJijidownExtra) { divLabelEnableUpdateGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromJijidownExtra) { divLabelIntervalGetFromJijidownExtra.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 divLabelEnableUpdateGetFromJijidown = document.createElement('div'); divLabelEnableUpdateGetFromJijidown.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelEnableUpdateGetFromJijidown.setAttribute('title', '默认: 关闭'); divControls.appendChild(divLabelEnableUpdateGetFromJijidown); const labelEnableUpdateGetFromJijidown = document.createElement('label'); labelEnableUpdateGetFromJijidown.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableUpdateGetFromJijidown.textContent = '启用更新'; divLabelEnableUpdateGetFromJijidown.appendChild(labelEnableUpdateGetFromJijidown); const checkboxEnableUpdateGetFromJijidown = document.createElement('input'); checkboxEnableUpdateGetFromJijidown.type = 'checkbox'; checkboxEnableUpdateGetFromJijidown.checked = settings.enableUpdateGetFromJijidown; checkboxEnableUpdateGetFromJijidown.addEventListener('change', () => { try { settings.enableUpdateGetFromJijidown = checkboxEnableUpdateGetFromJijidown.checked; if (!settings.enableUpdateGetFromJijidown) { divLabelIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelIntervalGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace); } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableUpdateGetFromJijidown.insertAdjacentElement('afterbegin', checkboxEnableUpdateGetFromJijidown); const divLabelIntervalGetFromJijidown = document.createElement('div'); divLabelIntervalGetFromJijidown.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelIntervalGetFromJijidown.setAttribute('title', '默认: 10星期'); divControls.appendChild(divLabelIntervalGetFromJijidown); const labelIntervalGetFromJijidown = document.createElement('label'); labelIntervalGetFromJijidown.classList.add('backup-label' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidown.appendChild(labelIntervalGetFromJijidown); const inputTextIntervalGetFromJijidown = document.createElement('input'); inputTextIntervalGetFromJijidown.type = 'text'; inputTextIntervalGetFromJijidown.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextIntervalGetFromJijidown.value = settings.intervalGetFromJijidown; inputTextIntervalGetFromJijidown.setAttribute('backup-def', 10); inputTextIntervalGetFromJijidown.setAttribute('backup-min', 1); inputTextIntervalGetFromJijidown.setAttribute('backup-max', 100); inputTextIntervalGetFromJijidown.setAttribute('backup-setting', 'intervalGetFromJijidown'); inputTextIntervalGetFromJijidown.addEventListener('blur', validateInputText); labelIntervalGetFromJijidown.appendChild(document.createTextNode('最小更新间隔')); labelIntervalGetFromJijidown.appendChild(inputTextIntervalGetFromJijidown); labelIntervalGetFromJijidown.appendChild(document.createTextNode('星期')); const divLabelEnableGetFromJijidownExtra = document.createElement('div'); divLabelEnableGetFromJijidownExtra.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); 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) { divLabelEnableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelEnableUpdateGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromJijidownExtra) { divLabelIntervalGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableGetFromJijidownExtra.insertAdjacentElement('afterbegin', checkboxEnableGetFromJijidownExtra); const divLabelEnableUpdateGetFromJijidownExtra = document.createElement('div'); divLabelEnableUpdateGetFromJijidownExtra.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelEnableUpdateGetFromJijidownExtra.setAttribute('title', '默认: 关闭'); divControls.appendChild(divLabelEnableUpdateGetFromJijidownExtra); const labelEnableUpdateGetFromJijidownExtra = document.createElement('label'); labelEnableUpdateGetFromJijidownExtra.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableUpdateGetFromJijidownExtra.textContent = '启用更新'; divLabelEnableUpdateGetFromJijidownExtra.appendChild(labelEnableUpdateGetFromJijidownExtra); const checkboxEnableUpdateGetFromJijidownExtra = document.createElement('input'); checkboxEnableUpdateGetFromJijidownExtra.type = 'checkbox'; checkboxEnableUpdateGetFromJijidownExtra.checked = settings.enableUpdateGetFromJijidownExtra; checkboxEnableUpdateGetFromJijidownExtra.addEventListener('change', () => { try { settings.enableUpdateGetFromJijidownExtra = checkboxEnableUpdateGetFromJijidownExtra.checked; if (!settings.enableUpdateGetFromJijidownExtra) { divLabelIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelIntervalGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace); } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableUpdateGetFromJijidownExtra.insertAdjacentElement('afterbegin', checkboxEnableUpdateGetFromJijidownExtra); const divLabelIntervalGetFromJijidownExtra = document.createElement('div'); divLabelIntervalGetFromJijidownExtra.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelIntervalGetFromJijidownExtra.setAttribute('title', '默认: 10星期'); divControls.appendChild(divLabelIntervalGetFromJijidownExtra); const labelIntervalGetFromJijidownExtra = document.createElement('label'); labelIntervalGetFromJijidownExtra.classList.add('backup-label' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidownExtra.appendChild(labelIntervalGetFromJijidownExtra); const inputTextIntervalGetFromJijidownExtra = document.createElement('input'); inputTextIntervalGetFromJijidownExtra.type = 'text'; inputTextIntervalGetFromJijidownExtra.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextIntervalGetFromJijidownExtra.value = settings.intervalGetFromJijidownExtra; inputTextIntervalGetFromJijidownExtra.setAttribute('backup-def', 10); inputTextIntervalGetFromJijidownExtra.setAttribute('backup-min', 1); inputTextIntervalGetFromJijidownExtra.setAttribute('backup-max', 100); inputTextIntervalGetFromJijidownExtra.setAttribute('backup-setting', 'intervalGetFromJijidownExtra'); inputTextIntervalGetFromJijidownExtra.addEventListener('blur', validateInputText); labelIntervalGetFromJijidownExtra.appendChild(document.createTextNode('最小更新间隔')); labelIntervalGetFromJijidownExtra.appendChild(inputTextIntervalGetFromJijidownExtra); labelIntervalGetFromJijidownExtra.appendChild(document.createTextNode('星期')); const divSwitchGetFromJijidownURL1 = document.createElement('div'); divSwitchGetFromJijidownURL1.classList.add('backup-div-second' + 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'; 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-second' + 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'; 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-first' + 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; if (!settings.enableGetFromXbeibeix) { divLabelEnableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelEnableUpdateGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (settings.enableUpdateGetFromXbeibeix) { divLabelIntervalGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace); } divSwitchGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace); } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableGetFromXbeibeix.insertAdjacentElement('afterbegin', checkboxEnableGetFromXbeibeix); const divLabelEnableUpdateGetFromXbeibeix = document.createElement('div'); divLabelEnableUpdateGetFromXbeibeix.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelEnableUpdateGetFromXbeibeix.setAttribute('title', '默认: 关闭'); divControls.appendChild(divLabelEnableUpdateGetFromXbeibeix); const labelEnableUpdateGetFromXbeibeix = document.createElement('label'); labelEnableUpdateGetFromXbeibeix.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableUpdateGetFromXbeibeix.textContent = '启用更新'; divLabelEnableUpdateGetFromXbeibeix.appendChild(labelEnableUpdateGetFromXbeibeix); const checkboxEnableUpdateGetFromXbeibeix = document.createElement('input'); checkboxEnableUpdateGetFromXbeibeix.type = 'checkbox'; checkboxEnableUpdateGetFromXbeibeix.checked = settings.enableUpdateGetFromXbeibeix; checkboxEnableUpdateGetFromXbeibeix.addEventListener('change', () => { try { settings.enableUpdateGetFromXbeibeix = checkboxEnableUpdateGetFromXbeibeix.checked; if (!settings.enableUpdateGetFromXbeibeix) { divLabelIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { divLabelIntervalGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace); } GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelEnableUpdateGetFromXbeibeix.insertAdjacentElement('afterbegin', checkboxEnableUpdateGetFromXbeibeix); const divLabelIntervalGetFromXbeibeix = document.createElement('div'); divLabelIntervalGetFromXbeibeix.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelIntervalGetFromXbeibeix.setAttribute('title', '默认: 10星期'); divControls.appendChild(divLabelIntervalGetFromXbeibeix); const labelIntervalGetFromXbeibeix = document.createElement('label'); labelIntervalGetFromXbeibeix.classList.add('backup-label' + classAppendNewFreshSpace); divLabelIntervalGetFromXbeibeix.appendChild(labelIntervalGetFromXbeibeix); const inputTextIntervalGetFromXbeibeix = document.createElement('input'); inputTextIntervalGetFromXbeibeix.type = 'text'; inputTextIntervalGetFromXbeibeix.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextIntervalGetFromXbeibeix.value = settings.intervalGetFromXbeibeix; inputTextIntervalGetFromXbeibeix.setAttribute('backup-def', 10); inputTextIntervalGetFromXbeibeix.setAttribute('backup-min', 1); inputTextIntervalGetFromXbeibeix.setAttribute('backup-max', 100); inputTextIntervalGetFromXbeibeix.setAttribute('backup-setting', 'intervalGetFromXbeibeix'); inputTextIntervalGetFromXbeibeix.addEventListener('blur', validateInputText); labelIntervalGetFromXbeibeix.appendChild(document.createTextNode('最小更新间隔')); labelIntervalGetFromXbeibeix.appendChild(inputTextIntervalGetFromXbeibeix); labelIntervalGetFromXbeibeix.appendChild(document.createTextNode('星期')); const divSwitchGetFromXbeibeixURL1 = document.createElement('div'); divSwitchGetFromXbeibeixURL1.classList.add('backup-div-second' + 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'; 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-second' + 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'; 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) { divLabelEnableAutoNextFavlist.classList.remove('backup-disabled' + classAppendNewFreshSpace); if (!activeControllers.size) { if (newFreshSpace) { if (!document.querySelector('div.fav-collapse').contains(document.querySelector('div.vui_sidebar-item--active'))) { return; } 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 { if (!document.querySelector('div.nav-container').contains(document.querySelector('.fav-item.cur'))) { return; } const pager = document.querySelector('li.be-pager-next'); if (pager && !pager.classList.contains('be-pager-disabled')) { await delay(500); if (enableAutoNextPage) { pager.click(); } } } } } else { enableAutoNextFavlist = false; checkboxEnableAutoNextFavlist.checked = false; divLabelEnableAutoNextFavlist.classList.add('backup-disabled' + classAppendNewFreshSpace); } } catch (error) { catchUnknownError(error); } }); labelEnableAutoNextPage.insertAdjacentElement('afterbegin', checkboxEnableAutoNextPage); const divLabelEnableAutoNextFavlist = document.createElement('div'); divLabelEnableAutoNextFavlist.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace); divLabelEnableAutoNextFavlist.setAttribute('title', '开启后脚本将在当前收藏夹的视频都处理完毕之后点击下一收藏夹, 继续处理下一收藏夹的视频。'); divControls.appendChild(divLabelEnableAutoNextFavlist); const labelEnableAutoNextFavlist = document.createElement('label'); labelEnableAutoNextFavlist.classList.add('backup-label' + classAppendNewFreshSpace); labelEnableAutoNextFavlist.textContent = '自动点击下一收藏夹'; divLabelEnableAutoNextFavlist.appendChild(labelEnableAutoNextFavlist); const checkboxEnableAutoNextFavlist = document.createElement('input'); checkboxEnableAutoNextFavlist.type = 'checkbox'; checkboxEnableAutoNextFavlist.checked = enableAutoNextFavlist; checkboxEnableAutoNextFavlist.addEventListener('change', async () => { try { enableAutoNextFavlist = checkboxEnableAutoNextFavlist.checked; if (enableAutoNextFavlist && !activeControllers.size) { let currentFavlist; if (newFreshSpace) { currentFavlist = document.querySelector('div.vui_sidebar-item--active'); if (!document.querySelector('div.fav-collapse').contains(currentFavlist)) { return; } const pager = Array.from(document.querySelectorAll('button.vui_pagenation--btn-side')).find(el => el.innerText === '下一页'); if (pager && !pager.classList.contains('vui_button--disabled')) { } else { if (!currentFavlist.parentNode.getAttribute('id')) { if (document.querySelector('div.fav-sortable-list').childElementCount) { await delay(500); if (enableAutoNextFavlist) { document.querySelector('div.fav-sortable-list').firstElementChild.querySelector('div').click(); } } } else { const nextFavlist = currentFavlist.parentNode.nextElementSibling; if (nextFavlist) { await delay(500); if (enableAutoNextFavlist) { nextFavlist.querySelector('div').click(); } } } } } else { currentFavlist = document.querySelector('.fav-item.cur'); if (!document.querySelector('div.nav-container').contains(currentFavlist)) { return; } const pager = document.querySelector('li.be-pager-next'); if (pager && !pager.classList.contains('be-pager-disabled')) { } else { if (currentFavlist.nodeName === 'DIV') { if (document.querySelector('ul.fav-list').childElementCount) { await delay(500); if (enableAutoNextFavlist) { document.querySelector('ul.fav-list').firstElementChild.querySelector('a').click(); } } } else { const nextFavlist = currentFavlist.nextElementSibling; if (nextFavlist) { await delay(500); if (enableAutoNextFavlist) { nextFavlist.querySelector('a').click(); } } } } } } } catch (error) { catchUnknownError(error); } }); labelEnableAutoNextFavlist.insertAdjacentElement('afterbegin', checkboxEnableAutoNextFavlist); const divLabelIntervalAutoNextPage = document.createElement('div'); divLabelIntervalAutoNextPage.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced'); divLabelIntervalAutoNextPage.setAttribute('title', '默认: 5秒\n' + '每次点击下一页或下一收藏夹之前停留在当前页的时间。'); divControls.appendChild(divLabelIntervalAutoNextPage); const labelIntervalAutoNextPage = document.createElement('label'); labelIntervalAutoNextPage.classList.add('backup-label' + classAppendNewFreshSpace); divLabelIntervalAutoNextPage.appendChild(labelIntervalAutoNextPage); const inputTextIntervalAutoNextPage = document.createElement('input'); inputTextIntervalAutoNextPage.type = 'text'; inputTextIntervalAutoNextPage.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextIntervalAutoNextPage.value = settings.intervalAutoNextPage; inputTextIntervalAutoNextPage.setAttribute('backup-def', 5); inputTextIntervalAutoNextPage.setAttribute('backup-min', 1); inputTextIntervalAutoNextPage.setAttribute('backup-max', 500); inputTextIntervalAutoNextPage.setAttribute('backup-setting', 'intervalAutoNextPage'); inputTextIntervalAutoNextPage.addEventListener('blur', validateInputText); labelIntervalAutoNextPage.appendChild(document.createTextNode('停留间隔')); labelIntervalAutoNextPage.appendChild(inputTextIntervalAutoNextPage); labelIntervalAutoNextPage.appendChild(document.createTextNode('秒')); const divLabelRequestTimeout = document.createElement('div'); divLabelRequestTimeout.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divLabelRequestTimeout.setAttribute('title', '默认: 10秒\n' + '脚本获取数据时, 如果等待了设定的时长后仍未得到响应数据, 则暂时跳过处理当前视频。'); divControls.appendChild(divLabelRequestTimeout); const labelRequestTimeout = document.createElement('label'); labelRequestTimeout.classList.add('backup-label' + classAppendNewFreshSpace); divLabelRequestTimeout.appendChild(labelRequestTimeout); const inputTextRequestTimeout = document.createElement('input'); inputTextRequestTimeout.type = 'text'; inputTextRequestTimeout.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextRequestTimeout.value = settings.requestTimeout; inputTextRequestTimeout.setAttribute('backup-def', 10); inputTextRequestTimeout.setAttribute('backup-min', 1); inputTextRequestTimeout.setAttribute('backup-max', 100); inputTextRequestTimeout.setAttribute('backup-setting', 'requestTimeout'); inputTextRequestTimeout.addEventListener('blur', validateInputText); labelRequestTimeout.appendChild(document.createTextNode('请求超时时间')); labelRequestTimeout.appendChild(inputTextRequestTimeout); labelRequestTimeout.appendChild(document.createTextNode('秒')); const divDelayBeforeMain = document.createElement('div'); divDelayBeforeMain.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divDelayBeforeMain.setAttribute('title', '默认: 300毫秒\n' + '如果您使用的是新版个人空间, 并且遇到了视频标题下方的信息展示出来后又突然消失的情况, 请将这个时长调大一些。'); divControls.appendChild(divDelayBeforeMain); const labelDelayBeforeMain = document.createElement('label'); labelDelayBeforeMain.classList.add('backup-label' + classAppendNewFreshSpace); divDelayBeforeMain.appendChild(labelDelayBeforeMain); const inputTextDelayBeforeMain = document.createElement('input'); inputTextDelayBeforeMain.type = 'text'; inputTextDelayBeforeMain.classList.add('backup-inputText' + classAppendNewFreshSpace); inputTextDelayBeforeMain.value = settings.delayBeforeMain; inputTextDelayBeforeMain.setAttribute('backup-def', 300); inputTextDelayBeforeMain.setAttribute('backup-min', 50); inputTextDelayBeforeMain.setAttribute('backup-max', 1000); inputTextDelayBeforeMain.setAttribute('backup-setting', 'delayBeforeMain'); inputTextDelayBeforeMain.addEventListener('blur', validateInputText); labelDelayBeforeMain.appendChild(document.createTextNode('开始处理视频前等待')); labelDelayBeforeMain.appendChild(inputTextDelayBeforeMain); labelDelayBeforeMain.appendChild(document.createTextNode('毫秒')); const divLabelAppendDropdownCover = document.createElement('div'); divLabelAppendDropdownCover.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divLabelAppendDropdownCover.setAttribute('title', '默认: 开启\n' + '控制是否在各个视频右下角的下拉列表中添加查看封面原图的功能。'); divControls.appendChild(divLabelAppendDropdownCover); const labelAppendDropdownCover = document.createElement('label'); labelAppendDropdownCover.classList.add('backup-label' + classAppendNewFreshSpace); labelAppendDropdownCover.textContent = '下拉列表: 封面原图'; divLabelAppendDropdownCover.appendChild(labelAppendDropdownCover); const checkboxAppendDropdownCover = document.createElement('input'); checkboxAppendDropdownCover.type = 'checkbox'; checkboxAppendDropdownCover.checked = settings.appendDropdownCover; checkboxAppendDropdownCover.addEventListener('change', () => { try { settings.appendDropdownCover = checkboxAppendDropdownCover.checked; GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelAppendDropdownCover.insertAdjacentElement('afterbegin', checkboxAppendDropdownCover); const divLabelAppendDropdownLocal = document.createElement('div'); divLabelAppendDropdownLocal.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divLabelAppendDropdownLocal.setAttribute('title', '默认: 开启'); divControls.appendChild(divLabelAppendDropdownLocal); const labelAppendDropdownLocal = document.createElement('label'); labelAppendDropdownLocal.classList.add('backup-label' + classAppendNewFreshSpace); labelAppendDropdownLocal.textContent = '下拉列表: 本地备份数据'; divLabelAppendDropdownLocal.appendChild(labelAppendDropdownLocal); const checkboxAppendDropdownLocal = document.createElement('input'); checkboxAppendDropdownLocal.type = 'checkbox'; checkboxAppendDropdownLocal.checked = settings.appendDropdownLocal; checkboxAppendDropdownLocal.addEventListener('change', () => { try { settings.appendDropdownLocal = checkboxAppendDropdownLocal.checked; GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelAppendDropdownLocal.insertAdjacentElement('afterbegin', checkboxAppendDropdownLocal); const divLabelAppendDropdownJump = document.createElement('div'); divLabelAppendDropdownJump.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divLabelAppendDropdownJump.setAttribute('title', '默认: 开启'); divControls.appendChild(divLabelAppendDropdownJump); const labelAppendDropdownJump = document.createElement('label'); labelAppendDropdownJump.classList.add('backup-label' + classAppendNewFreshSpace); labelAppendDropdownJump.textContent = '下拉列表: 跳转至BJX'; divLabelAppendDropdownJump.appendChild(labelAppendDropdownJump); const checkboxAppendDropdownJump = document.createElement('input'); checkboxAppendDropdownJump.type = 'checkbox'; checkboxAppendDropdownJump.checked = settings.appendDropdownJump; checkboxAppendDropdownJump.addEventListener('change', () => { try { settings.appendDropdownJump = checkboxAppendDropdownJump.checked; GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelAppendDropdownJump.insertAdjacentElement('afterbegin', checkboxAppendDropdownJump); const divLabelAppendDropdownReset = document.createElement('div'); divLabelAppendDropdownReset.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divLabelAppendDropdownReset.setAttribute('title', '默认: 开启'); divControls.appendChild(divLabelAppendDropdownReset); const labelAppendDropdownReset = document.createElement('label'); labelAppendDropdownReset.classList.add('backup-label' + classAppendNewFreshSpace); labelAppendDropdownReset.textContent = '下拉列表: 重置备份数据'; divLabelAppendDropdownReset.appendChild(labelAppendDropdownReset); const checkboxAppendDropdownReset = document.createElement('input'); checkboxAppendDropdownReset.type = 'checkbox'; checkboxAppendDropdownReset.checked = settings.appendDropdownReset; checkboxAppendDropdownReset.addEventListener('change', () => { try { settings.appendDropdownReset = checkboxAppendDropdownReset.checked; GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelAppendDropdownReset.insertAdjacentElement('afterbegin', checkboxAppendDropdownReset); 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 = '显示高级选项和功能'; divLabelDisplayAdvancedControls.appendChild(labelDisplayAdvancedControls); const checkboxDisplayAdvancedControls = document.createElement('input'); checkboxDisplayAdvancedControls.type = 'checkbox'; checkboxDisplayAdvancedControls.checked = settings.displayAdvancedControls; checkboxDisplayAdvancedControls.addEventListener('change', () => { try { settings.displayAdvancedControls = checkboxDisplayAdvancedControls.checked; 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) }); } GM_setValue('settings', settings); } 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 currentTs = getCurrentTs(); // 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(currentTs)}.json`; link.click(); URL.revokeObjectURL(link.href); if (settings.exportBackupWithoutTsFrom) { removeTsFromInBackup(backupsToExport); // 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(currentTs)}_without_ts_from.json`; link.click(); URL.revokeObjectURL(link.href); } } catch (error) { catchUnknownError(error); } }); divButtonExportBackup.appendChild(buttonExportBackup); const divLabelExportBackupWithoutTsFrom = document.createElement('div'); divLabelExportBackupWithoutTsFrom.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divLabelExportBackupWithoutTsFrom.setAttribute('title', '默认: 关闭\n' + '本地备份数据中各个信息的ts代表上一次从B站接口获取到该信息的时间戳或第三方网站备份该信息的时间戳, from代表该信息的获取来源。\n' + '如果您想要对比两个备份数据文件内容的差异, 对比两个文件去除ts和from的副本会更容易一些。\n' + '导入本地备份数据时请导入原始文件, 不要导入去除ts和from的副本。'); divControls.appendChild(divLabelExportBackupWithoutTsFrom); const labelExportBackupWithoutTsFrom = document.createElement('label'); labelExportBackupWithoutTsFrom.classList.add('backup-label' + classAppendNewFreshSpace); labelExportBackupWithoutTsFrom.textContent = '同时导出去除ts和from的副本'; divLabelExportBackupWithoutTsFrom.appendChild(labelExportBackupWithoutTsFrom); const checkboxExportBackupWithoutTsFrom = document.createElement('input'); checkboxExportBackupWithoutTsFrom.type = 'checkbox'; checkboxExportBackupWithoutTsFrom.checked = settings.exportBackupWithoutTsFrom; checkboxExportBackupWithoutTsFrom.addEventListener('change', () => { try { settings.exportBackupWithoutTsFrom = checkboxExportBackupWithoutTsFrom.checked; GM_setValue('settings', settings); } catch (error) { catchUnknownError(error); } }); labelExportBackupWithoutTsFrom.insertAdjacentElement('afterbegin', checkboxExportBackupWithoutTsFrom); 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'; inputFile.accept = '.json'; 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.r###lt); if (typeof backupsToImport !== 'object') { addMessage('文件内容有误, 无法导入', false, true); return; } for (const BVOfBackupToImport in backupsToImport) { const backupToImport = backupsToImport[BVOfBackupToImport]; try { formatBackup(backupToImport, false, undefined); const backup = GM_getValue(BVOfBackupToImport, { 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, biliplusExtra: null, jijidown: null, jijidownExtra: null, xbeibeix: null, }); formatBackup(backup, false, undefined); 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.thumbnails, el.cid, el.ts, el.from); }); } ['api', 'apiExtra', 'biliplus', 'biliplusExtra', '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(BVOfBackupToImport, sortedBackup); } catch (error) { addMessage('导入该视频失败', false, true); addMessage(`BV号: ${BVOfBackupToImport}`, 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); console.error('本地已有的数据'); console.error(GM_getValue(BVOfBackupToImport, {})); } } addMessage('导入完成'); } catch (error) { catchUnknownError(error); } }; reader.readAsText(file); } catch (error) { catchUnknownError(error); } }); const divButtonGetFromApiLegacy = document.createElement('div'); divButtonGetFromApiLegacy.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced'); divButtonGetFromApiLegacy.setAttribute('title', '地址: https://api.bilibili.com/medialist/gateway/base/spaceDetail?media_id={收藏夹fid}&pn={页码}&ps={每页展示视频数量}\n' + '数据: AV号, 标题 (失效视频无法获取), 简介 (仅能获取前255个字符), 封面地址 (失效视频无法获取), UP主UID, UP主昵称, UP主头像地址, 上传时间, 发布时间, 添加到当前收藏夹的时间, 每个分集的标题, cid (均为最新版本)\n' + '此功能将会从旧版B站接口获取当前收藏夹内所有视频的数据。与目前的B站接口相比, 旧版接口可以获取到每个分集的标题和cid, 无论视频是否失效。\n' + '您需要将当前收藏夹设置为公开后才能获取到数据。如果收藏夹内第一个视频不是失效视频, 修改可见性会导致收藏夹的封面被固定为该视频的封面, 建议修改可见性之前先复制一个失效视频到当前收藏夹的首位。'); divControls.appendChild(divButtonGetFromApiLegacy); const buttonGetFromApiLegacy = document.createElement('button'); buttonGetFromApiLegacy.type = 'button'; buttonGetFromApiLegacy.classList.add('backup-button' + classAppendNewFreshSpace); buttonGetFromApiLegacy.textContent = '从旧版B站接口获取数据'; buttonGetFromApiLegacy.addEventListener('click', async () => { try { clearMessage(); let currentFavlist; if (newFreshSpace) { currentFavlist = document.querySelector('div.vui_sidebar-item--active'); if (!document.querySelector('div.fav-collapse').contains(currentFavlist)) { throw ['不支持处理特殊收藏夹']; } } else { currentFavlist = document.querySelector('.fav-item.cur'); if (!document.querySelector('div.nav-container').contains(currentFavlist)) { throw ['不支持处理特殊收藏夹']; } } let fid; if (newFreshSpace) { const getFidFromURLMatch = location.href.match(getFidFromURLRegex); if (getFidFromURLMatch) { fid = parseInt(getFidFromURLMatch[1], 10); } else if (settings.defaultFavlistFid) { fid = settings.defaultFavlistFid; } else { throw ['无法获取当前收藏夹的fid, 刷新页面可能有帮助']; } } else { fid = parseInt(currentFavlist.getAttribute('fid'), 10); } let pageNumber = 1; let count = 0; while (true) { const response = await new Promise((resolve, reject) => { GM.xmlHttpRequest({ method: 'GET', url: `https://api.bilibili.com/medialist/gateway/base/spaceDetail?media_id=${fid}&pn=${pageNumber}&ps=20&keyword=&order=mtime&type=0&tid=0&jsonp=jsonp`, timeout: 1000 * settings.requestTimeout, responseType: 'json', onload: (res) => resolve(res), onerror: (res) => reject(['请求失败', 'api.bilibili.com/medialist/gateway/base/spaceDetail', res.error]), ontimeout: () => reject(['请求超时', 'api.bilibili.com/medialist/gateway/base/spaceDetail']) }); }); if (response.response.code === -403 || response.response.code === 7201004) { throw ['不支持处理私密收藏夹']; } else if (response.response.code) { throw ['发生未知错误, 请反馈该问题', JSON.stringify(response.response)]; } if (!response.response.data.medias) { addMessage('已完成'); return; } response.response.data.medias.forEach(media => { const backup = GM_getValue(media.bvid, { 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, biliplusExtra: null, jijidown: null, jijidownExtra: null, xbeibeix: null, }); formatBackup(backup, false, undefined); let disabled = false; if (media.title === '已失效视频') { disabled = true; } if (!backup.BV) { backup.BV = media.bvid; } if (!backup.AV) { backup.AV = media.id; } if (!disabled) { updateArrayDataInBackup(backup, 'title', media.title, getCurrentTs(), 'api.bilibili.com/medialist/gateway/base/spaceDetail'); updateArrayDataInBackup(backup, 'cover', media.cover, getCurrentTs(), 'api.bilibili.com/medialist/gateway/base/spaceDetail'); } updateArrayDataInBackup(backup, 'intro', media.intro, getCurrentTs(), 'api.bilibili.com/medialist/gateway/base/spaceDetail'); if (!backup.upperUID) { backup.upperUID = media.upper.mid; } updateArrayDataInBackup(backup, 'upperName', media.upper.name, getCurrentTs(), 'api.bilibili.com/medialist/gateway/base/spaceDetail'); updateArrayDataInBackup(backup, 'upperAvatar', media.upper.face, getCurrentTs(), 'api.bilibili.com/medialist/gateway/base/spaceDetail'); if (!backup.timeUpload) { backup.timeUpload = media.ctime; } if (!backup.timePublish) { backup.timePublish = media.pubtime; } updateTimeFavoriteInBackup(backup, media.fav_time, fid); if (Array.isArray(media.pages)) { media.pages.forEach(el => { updatePagesInBackup(backup, el.page, el.title, undefined, undefined, el.id, getCurrentTs(), 'api.bilibili.com/medialist/gateway/base/spaceDetail'); }); } else { if (enableDebug) { addMessage('getFromApiLegacy 无法获取pages'); addMessage(media.bvid); console.warn('getFromApiLegacy 无法获取pages'); console.warn(media); } } const sortedBackup = {}; for (const sortedKey of sortedKeys) { sortedBackup[sortedKey] = backup[sortedKey]; } GM_setValue(media.bvid, sortedBackup); if (enableDebug) console.log('保存旧版B站接口的数据至本地'); if (enableDebug) console.debug(media.bvid); if (enableDebug) console.debug(sortedBackup); }); count += response.response.data.medias.length; addMessage(`已处理视频个数: ${count}`, true); pageNumber++; } } catch (error) { if (error instanceof Error) { catchUnknownError(error); } else { addMessage(error[0], false, true); for (let i = 1; i < error.length; i++) { addMessage(error[i], true); } } } }); divButtonGetFromApiLegacy.appendChild(buttonGetFromApiLegacy); 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 = '重置timeFavorite'; button.addEventListener('click', () => { try { const backups = GM_getValues(GM_listValues()); delete backups.settings; for (const BVOfBackup in backups) { const backup = backups[BVOfBackup]; backup.timeFavorite = null; GM_setValue(BVOfBackup, backup); } addMessage('已完成'); } catch (error) { catchUnknownError(error); } }); divButton.appendChild(button); } di#####age = document.createElement('div'); di#####age.classList.add('backup-di#####age' + classAppendNewFreshSpace); divControls.appendChild(di#####age); // if (displayUpdate) { // setTimeout(() => { // addMessage(updates); // }, 300); // } if (!settings.processNormal && !settings.processDisabled) { divLabelEnableGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { if (!settings.enableGetFromApi) { divLabelEnableUpdateGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { if (!settings.enableUpdateGetFromApi) { divLabelIntervalGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace); } if (!settings.enableGetFromApiExtra) { divLabelEnableGetThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { if (!settings.enableUpdateGetFromApiExtra) { divLabelIntervalGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } } } if (!settings.enableGetFromBiliplus) { divLabelEnableUpdateGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { if (!settings.enableUpdateGetFromBiliplus) { divLabelIntervalGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace); } } if (!settings.enableGetFromApi || !settings.enableGetFromBiliplus) { divLabelEnableGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { if (!settings.enableGetFromBiliplusExtra) { divLabelEnableUpdateGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { if (!settings.enableUpdateGetFromBiliplusExtra) { divLabelIntervalGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } } } if (!settings.enableGetFromJijidown) { divLabelEnableUpdateGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelEnableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { if (!settings.enableUpdateGetFromJijidown) { divLabelIntervalGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace); } if (!settings.enableGetFromJijidownExtra) { divLabelEnableUpdateGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { if (!settings.enableUpdateGetFromJijidownExtra) { divLabelIntervalGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace); } } } if (!settings.enableGetFromXbeibeix) { divLabelEnableUpdateGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divLabelIntervalGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace); divSwitchGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace); } else { if (!settings.enableUpdateGetFromXbeibeix) { divLabelIntervalGetFromXbeibeix.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) { if (dropdownContainer.childElementCount === 1) { return; } 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; } if (settings.appendDropdownCover || settings.appendDropdownLocal || settings.appendDropdownJump || settings.appendDropdownReset) { dropdownContainer.lastElementChild.classList.add('be-dropdown-item-delimiter'); } } const backup = GM_getValue(BV, {}); if (settings.appendDropdownCover && 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(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(backup.cover[i].value, { insert: false, setParent: true }); } } catch (error) { catchUnknownError(error); } }); dropdownContainer.appendChild(dropdownCover); } if (settings.appendDropdownLocal) { 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); } if (settings.appendDropdownJump) { 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); } if (settings.appendDropdownReset) { 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 urlWithParams = await appendParamsForGetFromApi(fid, pageNumber, pageSize); const response = await new Promise(async (resolve, reject) => { GM.xmlHttpRequest({ method: 'GET', url: urlWithParams, timeout: 1000 * settings.requestTimeout, 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) addMessage('getFromApi 从B站接口获取的数据中没有该视频'); 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.enableUpdateGetFromApiExtra && getCurrentTs() - backup.apiExtra.ts > 3600 * 24 * settings.intervalGetFromApiExtra))) { } 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: 1000 * settings.requestTimeout, 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; if (updateTimeFavoriteNeeded()) { updateTimeFavoriteInBackup(backup, apiDetail.fav_time, fid); } if (apiDetail.ugc && apiDetail.ugc.first_cid) { updatePagesInBackup(backup, 1, undefined, undefined, undefined, apiDetail.ugc.first_cid, getCurrentTs(), undefined); } if (newFreshSpace) { spanFavTime.textContent = `投稿于:${formatTsTimePublish(1000 * apiDetail.pubtime)}`; spanFavTime.setAttribute('title', new Date(1000 * apiDetail.pubtime).toLocaleString()); } else { spanFavTime.textContent = `收藏于:${formatTsTimeFavorite(new Date(1000 * apiDetail.fav_time))}`; spanFavTime.setAttribute('title', new Date(1000 * apiDetail.fav_time).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, controller) { 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: 1000 * settings.requestTimeout, 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']) }); }); const currentTs = getCurrentTs(); updateArrayDataInBackup(backup, 'intro', response.response.data.desc, currentTs, '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) addMessage(`getFromApiExtra desc_v2未知type: ${desc.type}`); if (enableDebug) console.warn(`getFromApiExtra desc_v2未知type: ${desc.type}`); } } updateArrayDataInBackup(backup, 'intro', introWithUID, currentTs, '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, undefined, el.cid, getCurrentTs(), 'api.bilibili.com/x/web-interface/view'); }); if (settings.enableGetThumbnails && backup.AV && backup.pages) { for (const page of backup.pages) { if (controller.signal.aborted) { throw new DOMException('', 'AbortError'); } if (!page.cid) { continue; } let getThumbnails = true; if (page.thumbnails) { for (const thumbnail of page.thumbnails) { if (thumbnail.includes('videoshotpvhdboss')) { getThumbnails = false; break; } } } if (getThumbnails) { const response = await new Promise((resolve, reject) => { GM.xmlHttpRequest({ method: 'GET', url: `https://api.bilibili.com/x/player/videoshot?aid=${backup.AV}&cid=${page.cid}`, timeout: 1000 * settings.requestTimeout, responseType: 'json', onload: (res) => resolve(res), onerror: (res) => reject(['请求失败', 'api.bilibili.com/x/player/videoshot', res.error]), ontimeout: () => reject(['请求超时', 'api.bilibili.com/x/player/videoshot']) }); }); if (!response.response.data.image || !response.response.data.image.length) { if (enableDebug) { addMessage('getFromApiExtra 无法获取thumbnails'); addMessage(response.response.message, true); addMessage(`https://api.bilibili.com/x/player/videoshot?aid=${backup.AV}&cid=${page.cid}`, true); console.warn('getFromApiExtra 无法获取thumbnails'); console.warn(response.response.message); console.warn(`https://api.bilibili.com/x/player/videoshot?aid=${backup.AV}&cid=${page.cid}`); } continue; } response.response.data.image.forEach(el => { updatePagesInBackup(backup, undefined, undefined, undefined, el, page.cid, undefined, undefined); }); } } } 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: 1000 * settings.requestTimeout, 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, undefined, undefined, 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 (enableDebug) { if (json.v2_app_api.cid && json.v2_app_api.cid !== json.list[0].cid) { addMessage('getFromBiliplus cid 不一致1'); addMessage(json.v2_app_api.cid, true); addMessage(json.list[0].cid, true); console.warn('getFromBiliplus cid 不一致1'); console.warn(json.v2_app_api.cid); console.warn(json.list[0].cid); } if (json.v2_app_api.cid && json.v2_app_api.cid !== json.v2_app_api.pages[0].cid) { addMessage('getFromBiliplus cid 不一致2'); addMessage(json.v2_app_api.cid, true); addMessage(json.v2_app_api.pages[0].cid, true); console.warn('getFromBiliplus cid 不一致2'); console.warn(json.v2_app_api.cid); console.warn(json.v2_app_api.pages[0].cid); } if (json.list[0].cid !== json.v2_app_api.pages[0].cid) { addMessage('getFromBiliplus cid 不一致3'); addMessage(json.list[0].cid, true); addMessage(json.v2_app_api.pages[0].cid, true); console.warn('getFromBiliplus cid 不一致3'); console.warn(json.list[0].cid); console.warn(json.v2_app_api.pages[0].cid); } } if (json.v2_app_api.first_frame !== json.v2_app_api.pages[0].first_frame) { if (enableDebug) { addMessage('getFromBiliplus firstFrame 不一致'); addMessage(json.v2_app_api.first_frame, true); addMessage(json.v2_app_api.pages[0].first_frame, true); console.warn('getFromBiliplus firstFrame 不一致'); console.warn(json.v2_app_api.first_frame); console.warn(json.v2_app_api.pages[0].first_frame); } updatePagesInBackup(backup, 0, undefined, json.v2_app_api.first_frame, undefined, 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, undefined, 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 getFromBiliplusExtra(AVBVTitle, backup, spanB) { if (!backup.biliplus.value) { backup.biliplusExtra = { value: false, ts: getCurrentTs() }; spanB.style.color = '#800000'; } else { const response1 = await new Promise((resolve, reject) => { GM.xmlHttpRequest({ method: 'GET', url: `https://www.biliplus.com/all/video/av${AVBVTitle.AV}/`, timeout: 1000 * settings.requestTimeout, onload: (res) => resolve(res), onerror: (res) => reject(['请求失败', 'www.biliplus.com/all/video', res.error]), ontimeout: () => reject(['请求超时', 'www.biliplus.com/all/video']) }); }); const paramsWithSign = response1.response.match(getParamsWithSignFromBiliplusRegex)[1]; const response2 = await new Promise((resolve, reject) => { GM.xmlHttpRequest({ method: 'GET', url: `https://www.biliplus.com/api/view_all${paramsWithSign}`, timeout: 1000 * settings.requestTimeout, responseType: 'json', onload: (res) => resolve(res), onerror: (res) => reject(['请求失败', 'www.biliplus.com/api/view_all', res.error]), ontimeout: () => reject(['请求超时', 'www.biliplus.com/api/view_all']) }); }); if (response2.response.code === -503) { throw ['从BiliPlus获取额外数据的频率过快']; } await delay(2500); if (response2.response.code === 0) { if (enableDebug) console.log('从BiliPlus获取有效额外数据'); if (enableDebug) consoleAVBVTitle('debug', AVBVTitle); if (enableDebug) console.debug(response2.response); updateArrayDataInBackup(backup, 'title', response2.response.data.info.title, undefined, 'www.biliplus.com/api/view_all'); updateArrayDataInBackup(backup, 'intro', response2.response.data.info.description, undefined, 'www.biliplus.com/api/view_all'); updateArrayDataInBackup(backup, 'cover', response2.response.data.info.pic, undefined, 'www.biliplus.com/api/view_all'); updateArrayDataInBackup(backup, 'upperName', response2.response.data.info.author, undefined, 'www.biliplus.com/api/view_all'); response2.response.data.parts.forEach(el => { updatePagesInBackup(backup, el.page, el.part, undefined, undefined, el.cid, undefined, 'www.biliplus.com/api/view_all'); }); backup.biliplusExtra = { value: true, ts: getCurrentTs() }; spanB.style.color = '#008000'; } else if (response2.response.code === -404) { if (enableDebug) { addMessage('getFromBiliplusExtra 无法获取额外数据'); addMessage(AVBVTitle.AV, true); console.warn('getFromBiliplusExtra 无法获取额外数据'); console.warn(AVBVTitle.AV); } backup.biliplusExtra = { value: false, ts: getCurrentTs() }; spanB.style.color = '#800000'; } else { if (enableDebug) { addMessage('getFromBiliplusExtra 未知错误'); addMessage(JSON.stringify(response2.response), true); addMessage(AVBVTitle.AV, true); console.warn('getFromBiliplusExtra 未知错误'); console.warn(response2.response); console.warn(AVBVTitle.AV); } backup.biliplusExtra = { value: false, ts: getCurrentTs() }; spanB.style.color = '#800000'; } } const sortedBackup = {}; for (const sortedKey of sortedKeys) { sortedBackup[sortedKey] = backup[sortedKey]; } GM_setValue(AVBVTitle.BV, sortedBackup); if (enableDebug) console.log('保存BiliPlus的额外数据至本地'); if (enableDebug) consoleAVBVTitle('debug', AVBVTitle); if (enableDebug) console.debug(sortedBackup); } 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: 1000 * settings.requestTimeout, 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.enableUpdateGetFromJijidownExtra && getCurrentTs() - backup.jijidownExtra.ts > 3600 * 24 * 7 * settings.intervalGetFromJijidownExtra))) { 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.enableUpdateGetFromJijidownExtra && getCurrentTs() - backup.jijidownExtra.ts > 3600 * 24 * 7 * settings.intervalGetFromJijidownExtra))) { 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: 1000 * settings.requestTimeout, 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, 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: 1000 * settings.requestTimeout, 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'; } di#####age.appendChild(p); if (di#####ageHeightFixed) { di#####age.scrollTop = di#####age.scrollHeight; } else { if (newFreshSpace) { if (di#####age.scrollHeight > 320) { di#####age.classList.add('backup-di#####age-heightFixed-newFreshSpace'); di#####ageHeightFixed = true; di#####age.scrollTop = di#####age.scrollHeight; } } else { if (di#####age.scrollHeight > 280) { di#####age.classList.add('backup-di#####age-heightFixed'); di#####ageHeightFixed = true; di#####age.scrollTop = di#####age.scrollHeight; } } } di#####age.scrollIntoView({ behavior: 'instant', block: 'nearest' }); } function clearMessage() { while (di#####age.firstChild) { di#####age.removeChild(di#####age.firstChild); } di#####age.classList.remove('backup-di#####age-heightFixed' + classAppendNewFreshSpace); di#####ageHeightFixed = 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(1000 * ts); 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) { const n = new Date(e); const 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 '昨天'; } const l = n.getFullYear(); const c = '0'.concat(n.getMonth() + 1).slice(-2); const 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 = 'https://' + 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, thumbnails, cid, ts, from) { if (!index && index !== 0) { index = null; } if (title) { if (!Array.isArray(title)) { title = [title]; } } else { title = null; } if (firstFrame) { firstFrame = 'https://' + firstFrame.replace(getHttpsFromURLRegex, '').replace(getAvifFromURLRegex, ''); } else { firstFrame = null; } if (thumbnails) { if (!Array.isArray(thumbnails)) { thumbnails = ['https://' + thumbnails.replace(getHttpsFromURLRegex, '').replace(getAvifFromURLRegex, '')]; } else { thumbnails = thumbnails.map(el => 'https://' + el.replace(getHttpsFromURLRegex, '').replace(getAvifFromURLRegex, '')); } } else { thumbnails = null; } if (!cid && cid !== 0) { cid = null; } if (!ts) { ts = 0; } if (!from) { from = null; } if (!backup.pages) { backup.pages = []; const data = { index, title, firstFrame, thumbnails, 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 && target.ts <= ts) { 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)) { target.title.push(el); modified = true; } }); } } if (firstFrame) { if (!target.firstFrame) { target.firstFrame = firstFrame; modified = true; } else if (target.firstFrame !== firstFrame) { if (enableDebug) { addMessage('updatePagesInBackup firstFrame 不一致'); addMessage(`旧: ${target.firstFrame}`, true); addMessage(`新: ${firstFrame}`, true); console.warn('updatePagesInBackup firstFrame 不一致'); console.warn(`旧: ${target.firstFrame}`); console.warn(`新: ${firstFrame}`); } // target.firstFrame = firstFrame; // modified = true; } } if (thumbnails) { if (!target.thumbnails) { target.thumbnails = thumbnails; modified = true; } else { thumbnails.forEach(el => { if (!target.thumbnails.find(ele => ele === el)) { target.thumbnails.push(el); modified = true; } }); } } if (target.ts <= ts) { target.ts = ts; modified = true; } if (modified) { if (from) { 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 { const data = { index, title, firstFrame, thumbnails, 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); let divFilterOrder; let divTid; if (!newFreshSpace) { const divDropdownFilterItems = document.querySelectorAll('div.fav-filters > div.be-dropdown.filter-item'); if (divDropdownFilterItems.length === 2) { divFilterOrder = divDropdownFilterItems[1].querySelector('span'); divTid = divDropdownFilterItems[0].querySelector('span'); } else if (divDropdownFilterItems.length === 1) { divFilterOrder = divDropdownFilterItems[0].querySelector('span'); divTid = null; } else { divFilterOrder = null; divTid = null; } } if (!newFreshSpace) { 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 (!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}`); if (newFreshSpace) { divTid = document.querySelector('div.fav-list-header-collapse div.radio-filter__item--active'); } 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: 1000 * settings.requestTimeout, 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 target = response.response.data.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) { try { 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); } catch (error) { catchUnknownError(error); } } function removeTsFromInBackup(obj) { if (Array.isArray(obj)) { obj.forEach(el => removeTsFromInBackup(el)); } else if (obj && typeof obj === 'object') { for (const key in obj) { if (key === 'ts' || key === 'from') { delete obj[key]; } else { removeTsFromInBackup(obj[key]); } } } } function formatBackup(backup, setValue, BV) { let modified = false; // v9 if (backup.timeFavorite) { backup.timeFavorite.forEach(el => { if (typeof el.fid === 'string') { el.fid = parseInt(el.fid, 10); modified = true; } }); } // v9 if (Array.isArray(backup.timeUpload)) { if (backup.timeUpload.length === 1) { backup.timeUpload = backup.timeUpload[0].value; } else { backup.timeUpload = null; } modified = true; } // v9 if (Array.isArray(backup.timePublish)) { if (backup.timePublish.length === 1) { backup.timePublish = backup.timePublish[0].value; } else { backup.timePublish = null; } modified = true; } // v10 if (backup.hasOwnProperty('jiji')) { backup.jijidown = backup.jiji; delete backup.jiji; modified = true; } // v10 if (backup.hasOwnProperty('bbdownloader')) { backup.xbeibeix = backup.bbdownloader; delete backup.bbdownloader; modified = true; } // v14 if (backup.hasOwnProperty('firstFrame')) { delete backup.firstFrame; modified = true; } // 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; modified = true; } // v21 ['cover', 'upperAvatar'].forEach(key => { if (backup[key]) { const tempBackup = {}; backup[key].forEach(el => { updateArrayDataInBackup(tempBackup, key, el.value, el.ts, el.from); }); backup[key] = tempBackup[key]; modified = true; } }); // v21 if (backup.pages) { const tempBackup = {}; backup.pages.forEach(el => { updatePagesInBackup(tempBackup, el.index, el.title, el.firstFrame, el.thumbnails, el.cid, el.ts, el.from); }); backup.pages = tempBackup.pages; modified = true; } if (setValue && modified) { GM_setValue(BV, backup); } } function updateTimeFavoriteNeeded() { const divType = document.querySelector(newFreshSpace ? 'div.vui_input__prepend' : 'div.search-types'); let typeText = '当前'; if (divType) { typeText = divType.innerText; } const inputKeyword = document.querySelector(newFreshSpace ? 'input.fav-list-header-filter__search' : 'input.search-fav-input'); if (!inputKeyword || !inputKeyword.value) { typeText = '当前'; } if (typeText.includes('当前')) { console.warn(true); return true; } else if (typeText.includes('全部')) { console.error(false); return false; } else { throw ['无法确定搜索的范围为当前收藏夹还是全部收藏夹, 请反馈该问题']; } } })();