// ==UserScript==
// @name bilibili favlist backup
// @name:zh-CN 哔哩哔哩(B站|Bilibili)收藏夹Fix (备份视频信息)
// @name:zh-TW 哔哩哔哩(B站|Bilibili)收藏夹Fix (备份视频信息)
// @namespace http://tampermonkey.net/
// @version 31
// @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 beibeigame.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 = 31;
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 autoNextPage = false;
let autoNextFavlist = false;
let debug = false;
let newFreshSpace;
let classAppendNewFreshSpace;
let pageSize;
let firstTimeMain = true;
let divMessage;
let divMessageHeightFixed = false;
let order = 'mtime';
const activeControllers = new Set();
let getFromApiExtraDelay = true;
let getFromBiliplusExtraCounter = 0;
setInterval(() => {
if (getFromBiliplusExtraCounter > 0) {
getFromBiliplusExtraCounter--;
}
}, 1000);
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,
getFromApi: true,
getFromApiUpdate: true,
getFromApiUpdateInterval: 5,
getFromApiExtra: false,
getFromApiExtraThumbnails: false,
getFromApiExtraUpdate: true,
getFromApiExtraUpdateAll: false,
getFromApiExtraUpdateInterval: 5,
getFromBiliplus: false,
getFromBiliplusUpdate: false,
getFromBiliplusUpdateInterval: 10,
getFromBiliplusExtra: false,
getFromBiliplusExtraUpdate: false,
getFromBiliplusExtraUpdateInterval: 10,
getFromJijidown: false,
getFromJijidownUpdate: false,
getFromJijidownUpdateInterval: 10,
getFromJijidownExtra: false,
getFromJijidownExtraUpdate: false,
getFromJijidownExtraUpdateInterval: 10,
getFromJijidownURL: 'www.jijidown.com',
getFromXbeibeix: false,
getFromXbeibeixUpdate: false,
getFromXbeibeixUpdateInterval: 10,
getFromXbeibeixURL: 'xbeibeix.com',
autoNextPageInterval: 5,
requestTimeout: 10,
delayBeforeMain: 300,
appendDropdownCover: true,
appendDropdownLocal: true,
appendDropdownJump: true,
appendDropdownReset: true,
TCABJXOpacity: 100,
displayAdvancedControls: false,
exportBackupWithoutTsFrom: false,
version: 0,
defaultUID: null,
defaultFavlistFid: null,
});
///////////////////////////////////////////////////////////////////////////////////
// debug = true;
// getFromApiExtraDelay = false;
// settings.delayBeforeMain = 0;
// settings.processNormal = false;
// settings.processDisabled = false;
// settings.getFromApi = 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);
}
// v28
if (!settings.hasOwnProperty('TCABJXOpacity')) {
settings.TCABJXOpacity = 100;
settings.enableDelayGetFromBiliplusExtra = true;
GM_setValue('settings', settings);
}
// v31
if (!settings.hasOwnProperty('getFromApiExtraUpdateAll')) {
settings.getFromApiExtraUpdateAll = false;
settings.getFromApi = settings.enableGetFromApi;
settings.getFromApiUpdate = settings.enableUpdateGetFromApi;
settings.getFromApiUpdateInterval = settings.intervalGetFromApi;
settings.getFromApiExtra = settings.enableGetFromApiExtra;
settings.getFromApiExtraThumbnails = settings.enableGetThumbnails;
settings.getFromApiExtraUpdate = settings.enableUpdateGetFromApiExtra;
settings.getFromApiExtraUpdateInterval = settings.intervalGetFromApiExtra;
settings.getFromBiliplus = settings.enableGetFromBiliplus;
settings.getFromBiliplusUpdate = settings.enableUpdateGetFromBiliplus;
settings.getFromBiliplusUpdateInterval = settings.intervalGetFromBiliplus;
settings.getFromBiliplusExtra = settings.enableGetFromBiliplusExtra;
settings.getFromBiliplusExtraUpdate = settings.enableUpdateGetFromBiliplusExtra;
settings.getFromBiliplusExtraUpdateInterval = settings.intervalGetFromBiliplusExtra;
settings.getFromJijidown = settings.enableGetFromJijidown;
settings.getFromJijidownUpdate = settings.enableUpdateGetFromJijidown;
settings.getFromJijidownUpdateInterval = settings.intervalGetFromJijidown;
settings.getFromJijidownExtra = settings.enableGetFromJijidownExtra;
settings.getFromJijidownExtraUpdate = settings.enableUpdateGetFromJijidownExtra;
settings.getFromJijidownExtraUpdateInterval = settings.intervalGetFromJijidownExtra;
settings.getFromXbeibeix = settings.enableGetFromXbeibeix;
settings.getFromXbeibeixUpdate = settings.enableUpdateGetFromXbeibeix;
settings.getFromXbeibeixUpdateInterval = settings.intervalGetFromXbeibeix;
settings.autoNextPageInterval = settings.intervalAutoNextPage;
delete settings.enableGetFromApi;
delete settings.enableUpdateGetFromApi;
delete settings.intervalGetFromApi;
delete settings.enableGetFromApiExtra;
delete settings.enableGetThumbnails;
delete settings.enableUpdateGetFromApiExtra;
delete settings.intervalGetFromApiExtra;
delete settings.enableGetFromBiliplus;
delete settings.enableUpdateGetFromBiliplus;
delete settings.intervalGetFromBiliplus;
delete settings.enableGetFromBiliplusExtra;
delete settings.enableDelayGetFromBiliplusExtra;
delete settings.enableUpdateGetFromBiliplusExtra;
delete settings.intervalGetFromBiliplusExtra;
delete settings.enableGetFromJijidown;
delete settings.enableUpdateGetFromJijidown;
delete settings.intervalGetFromJijidown;
delete settings.enableGetFromJijidownExtra;
delete settings.enableUpdateGetFromJijidownExtra;
delete settings.intervalGetFromJijidownExtra;
delete settings.enableGetFromXbeibeix;
delete settings.enableUpdateGetFromXbeibeix;
delete settings.intervalGetFromXbeibeix;
delete settings.intervalAutoNextPage;
GM_setValue('settings', settings);
}
///////////////////////////////////////////////////////////////////////////////////
const favlistObserver = new MutationObserver(async (_mutations, observer) => {
if (debug) console.debug('callback favlistObserver');
if (document.querySelector('div.items')) {
if (debug) console.debug('disconnect favlistObserver');
observer.disconnect();
newFreshSpace = true;
classAppendNewFreshSpace = '-newFreshSpace';
pageSize = window.innerWidth < 1760 ? 40 : 36;
initControls();
if (!firstTimeMain) {
await delay(settings.delayBeforeMain + 300);
main();
}
if (debug) console.debug('observe itemsObserver');
itemsObserver.observe(document.querySelector('div.items'), { childList: true, attributes: false, characterData: false });
if (debug) console.debug('observe bodyChildListObserver');
bodyChildListObserver.observe(document.body, { childList: true, attributes: false, characterData: false });
if (debug) console.debug('observe radioFilterObserver');
radioFilterObserver.observe(document.querySelector('div.fav-list-header-filter__left > div'), { subtree: true, characterData: false, attributeFilter: ['class'] });
if (debug) 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 (debug) console.debug('disconnect favlistObserver');
observer.disconnect();
newFreshSpace = false;
classAppendNewFreshSpace = '';
pageSize = 20;
initControls();
if (debug) console.debug('observe favContentSectionObserver');
favContentSectionObserver.observe(document.querySelector('div.fav-content.section'), { characterData: false, attributeFilter: ['class'] });
return;
}
});
const itemsObserver = new MutationObserver(async () => {
abortActiveControllers();
if (debug) console.debug('callback itemsObserver');
if (settings.delayBeforeMain) {
await delay(settings.delayBeforeMain);
}
main();
});
const bodyChildListObserver = new MutationObserver(mutations => {
if (debug) console.debug('callback bodyChildListObserver');
if (debug) 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 (debug) 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 (debug) console.debug('observe itemsObserver');
// itemsObserver.observe(document.querySelector('div.items'), { childList: true, attributes: false, characterData: false });
// // return;
// }
// }
}
});
const radioFilterObserver = new MutationObserver(mutations => {
if (debug) console.debug('callback radioFilterObserver');
if (debug) 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, 'red');
}
if (debug) console.log(`order: ${order}`);
}
}
});
const headerFilterLeftChildListObserver = new MutationObserver(mutations => {
if (debug) console.debug('callback headerFilterLeftChildListObserver');
if (debug) 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 (debug) console.log(`order: ${order}`);
if (debug) 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 (debug) console.debug('disconncet radioFilterObserver');
radioFilterObserver.disconnect();
}
}
}
});
const favContentSectionObserver = new MutationObserver(mutations => {
if (debug) 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 (debug) console.debug('checkURL');
if (favlistURLRegex.test(location.href)) {
if (!onFavlistPage) {
onFavlistPage = true;
autoNextPage = false;
autoNextFavlist = false;
if (debug) console.debug('observe favlistObserver');
favlistObserver.observe(document.body, { subtree: true, childList: true, attributes: false, characterData: false });
}
} else {
if (onFavlistPage) {
abortActiveControllers();
onFavlistPage = false;
if (debug) console.debug('disconnect favlistObserver');
favlistObserver.disconnect();
if (debug) console.debug('disconncet itemsObserver');
itemsObserver.disconnect();
if (debug) console.debug('disconncet bodyChildListObserver');
bodyChildListObserver.disconnect();
if (debug) console.debug('disconncet radioFilterObserver');
radioFilterObserver.disconnect();
if (debug) console.debug('disconncet headerFilterLeftChildListObserver');
headerFilterLeftChildListObserver.disconnect();
if (debug) console.debug('disconncet favContentSectionObserver');
favContentSectionObserver.disconnect();
}
}
}
async function main() {
if (debug) 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 (debug) console.log('不处理特殊收藏夹');
return;
}
} else {
currentFavlist = document.querySelector('.fav-item.cur');
if (!document.querySelector('div.nav-container').contains(currentFavlist)) {
if (debug) 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);
}
let searchKeyword = '';
const inputKeyword = document.querySelector(newFreshSpace ? 'input.fav-list-header-filter__search' : 'input.search-fav-input');
if (inputKeyword) {
searchKeyword = inputKeyword.value;
}
let searchType;
const divType = document.querySelector(newFreshSpace ? 'div.vui_input__prepend' : 'div.search-types');
let typeText = '当前';
if (divType) {
typeText = divType.innerText;
}
if (!searchKeyword) {
typeText = '当前';
}
if (typeText.includes('当前')) {
searchType = 0;
} else if (typeText.includes('全部')) {
searchType = 1;
} else {
throw ['无法确定搜索的范围为当前收藏夹还是全部收藏夹, 请反馈该问题'];
}
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 (debug) console.log('不处理特殊视频');
continue;
}
let disabled = false;
if (newFreshSpace) {
const divStats = video.querySelector('div.bili-cover-card__stats');
if (!searchKeyword && !divStats) {
disabled = true;
}
if (searchKeyword && video.querySelector('img').getAttribute('src').includes('be27fd62c99036dce67efface486fb0a88ffed06')) {
disabled = true;
if (divStats) {
divStats.remove();
} else {
if (debug) {
addMessage('divStats已移除', false, 'red');
console.warn('divStats已移除');
}
}
}
} 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 (debug) {
console.log('========video========');
console.log(`收藏夹fid: ${fid}`);
console.log(`位置: 第${pageNumber}页的第${index + 1}个`);
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';
spanX.style.opacity = settings.TCABJXOpacity / 100;
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.opacity = settings.TCABJXOpacity / 100;
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 (debug) {
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.opacity = settings.TCABJXOpacity / 100;
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 (debug) {
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.opacity = settings.TCABJXOpacity / 100;
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 (debug) {
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 (!searchType && 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');
}
const getFromApiExtraNeeded = { value: false };
if (settings.getFromApi) {
if (!backup.api || (settings.getFromApiUpdate && getCurrentTs() - backup.api.ts > 3600 * settings.getFromApiUpdateInterval)) {
if (await getFromApi(AVBVTitle, backup, spanA, apiDetails, fid, pageNumber, disabled, spanFavTime, searchType, getFromApiExtraNeeded)) {
continue;
}
} else {
spanA.style.color = backup.api.value ? '#00ff00' : '#ff0000';
if (!searchType && 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.getFromApiExtra) {
if (!backup.apiExtra) {
await getFromApiExtra(AVBVTitle, backup, spanA, disabled);
} else if (settings.getFromApiExtraUpdate && settings.getFromApiExtraUpdateAll && getCurrentTs() - backup.apiExtra.ts > 3600 * 24 * settings.getFromApiExtraUpdateInterval) {
await getFromApiExtra(AVBVTitle, backup, spanA, disabled);
} else if (settings.getFromApiExtraUpdate && !settings.getFromApiExtraUpdateAll && getFromApiExtraNeeded.value) {
await getFromApiExtra(AVBVTitle, backup, spanA, disabled);
} else {
spanA.style.color = backup.apiExtra.value ? '#008000' : '#800000';
}
}
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (settings.getFromApiExtraThumbnails && !disabled && backup.AV && backup.pages) {
await getFromApiExtraThumbnails(AVBVTitle, backup, as, controller);
}
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (settings.getFromJijidown) {
if (!backup.jijidown || (settings.getFromJijidownUpdate && getCurrentTs() - backup.jijidown.ts > 3600 * 24 * 7 * settings.getFromJijidownUpdateInterval)) {
functions.push(getFromJijidown(AVBVTitle, backup, spanJ));
} else {
if (settings.getFromJijidownExtra) {
if (!backup.jijidownExtra || (settings.getFromJijidownExtraUpdate && getCurrentTs() - backup.jijidownExtra.ts > 3600 * 24 * 7 * settings.getFromJijidownExtraUpdateInterval)) {
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.getFromXbeibeix) {
if (!backup.xbeibeix || (settings.getFromXbeibeixUpdate && getCurrentTs() - backup.xbeibeix.ts > 3600 * 24 * 7 * settings.getFromXbeibeixUpdateInterval)) {
functions.push(getFromXbeibeix(AVBVTitle, backup, spanX));
} else {
spanX.style.color = backup.xbeibeix.value ? '#00ff00' : '#ff0000';
}
}
if (settings.getFromBiliplus) {
if (!backup.biliplus || (settings.getFromBiliplusUpdate && getCurrentTs() - backup.biliplus.ts > 3600 * 24 * 7 * settings.getFromBiliplusUpdateInterval)) {
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 (debug) {
console.log('保存第三方网站的数据至本地');
consoleAVBVTitle('debug', AVBVTitle);
console.debug(sortedBackup);
}
}
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (settings.getFromBiliplusExtra) {
if (!backup.biliplusExtra || (settings.getFromBiliplusExtraUpdate && getCurrentTs() - backup.biliplusExtra.ts > 3600 * 24 * 7 * settings.getFromBiliplusExtraUpdateInterval)) {
await getFromBiliplusExtra(AVBVTitle, backup, spanB, as, controller);
} else {
spanB.style.color = backup.biliplusExtra.value ? '#008000' : '#800000';
}
}
} catch (error) {
if (error instanceof Error) {
if (error.name === 'AbortError') {
throw error;
}
addMessage('发生未知错误, 请反馈该问题', false, 'red');
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, 'red');
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 (debug) {
if (!img.getAttribute('src').endsWith('@672w_378h_1c.avif')) {
addMessage('封面avif已更改', false, 'red');
console.warn('封面avif已更改');
}
if (disabled && !searchKeyword && !img.getAttribute('src').includes('be27fd62c99036dce67efface486fb0a88ffed06')) {
addMessage('失效视频封面已更改', false, 'red');
console.warn('失效视频封面已更改');
}
}
} 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.opacity = settings.TCABJXOpacity / 100;
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.opacity = settings.TCABJXOpacity / 100;
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, 'red');
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, 'red');
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 (autoNextPage) {
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.autoNextPageInterval);
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (autoNextPage) {
pager.click();
}
} else if (autoNextFavlist) {
if (!currentFavlist.parentNode.getAttribute('id')) {
if (document.querySelector('div.fav-sortable-list').childElementCount) {
await delay(1000 * settings.autoNextPageInterval);
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (autoNextFavlist) {
document.querySelector('div.fav-sortable-list').firstElementChild.querySelector('div').click();
}
}
} else {
const nextFavlist = currentFavlist.parentNode.nextElementSibling;
if (nextFavlist) {
await delay(1000 * settings.autoNextPageInterval);
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (autoNextFavlist) {
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.autoNextPageInterval);
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (autoNextPage) {
pager.click();
}
} else if (autoNextFavlist) {
if (currentFavlist.nodeName === 'DIV') {
if (document.querySelector('ul.fav-list').childElementCount) {
await delay(1000 * settings.autoNextPageInterval);
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (autoNextFavlist) {
document.querySelector('ul.fav-list').firstElementChild.querySelector('a').click();
}
}
} else {
const nextFavlist = currentFavlist.nextElementSibling;
if (nextFavlist) {
await delay(1000 * settings.autoNextPageInterval);
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (autoNextFavlist) {
nextFavlist.querySelector('a').click();
}
}
}
}
}
}
} catch (error) {
if (error instanceof Error) {
if (error.name === 'AbortError') {
return;
}
catchUnknownError(error);
} else {
addMessage(error[0], false, 'red');
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-inputCheckbox, .backup-inputCheckbox-newFreshSpace {
margin-left: 0;
}
.backup-inputCheckbox {
margin-right: 1px;
}
.backup-inputCheckbox-newFreshSpace {
margin-right: 3px;
}
.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-inputRadio, .backup-inputRadio-newFreshSpace {
margin-left: 0;
}
.backup-inputRadio {
margin-right: 1px;
}
.backup-inputRadio-newFreshSpace {
margin-right: 3px;
}
.backup-hidden, .backup-hidden-newFreshSpace {
display: none;
}
.backup-button, .backup-button-newFreshSpace {
border: 1px solid #cccccc;
line-height: 1;
cursor: pointer;
}
.backup-button {
border-radius: 2px;
padding: 2px;
font-size: 14px;
}
.backup-button-newFreshSpace {
border-radius: 3px;
padding: 3px;
font-size: 16px;
}
.backup-divMessage, .backup-divMessage-newFreshSpace {
overflow-y: auto;
background-color: #eeeeee;
line-height: 1.5;
scrollbar-width: none;
}
.backup-divMessage {
margin: 2px;
}
.backup-divMessage-heightFixed {
height: 280px;
}
.backup-divMessage::-webkit-scrollbar {
display: none;
}
.backup-divMessage-newFreshSpace {
margin: 2px 0;
}
.backup-divMessage-heightFixed-newFreshSpace {
height: 320px;
}
.backup-divMessage-newFreshSpace::-webkit-scrollbar {
display: none;
}
`;
document.head.appendChild(style);
const divSide = document.querySelector(newFreshSpace ? 'div.favlist-aside' : 'div.fav-sidenav');
if (!newFreshSpace && divSide.querySelector('a.watch-later')) {
divSide.querySelector('a.watch-later').style.borderBottom = '1px solid #eeeeee';
}
const divControls = document.createElement('div');
divControls.classList.add('backup-div-first' + classAppendNewFreshSpace);
if (!newFreshSpace) {
divControls.style.borderTop = '1px solid #e4e9f0';
}
divSide.appendChild(divControls);
const divLabelProcessNormal = document.createElement('div');
divLabelProcessNormal.classList.add('backup-div-first' + classAppendNewFreshSpace);
divLabelProcessNormal.setAttribute('title',
'默认: 开启\n' +
'由于新视频的BV号随机生成, 各个第三方网站无法自动地爬取新视频的信息。\n' +
'开启该选项的同时开启下面的从第三方网站获取数据, 脚本将代替您访问相应的第三方网站。\n' +
'如果处理的视频第三方网站还没有备份, 这将使其备份该视频当前版本的信息。\n' +
'如果处理的视频之前有人备份过了, 这将获取到该视频的信息备份到第三方网站时的版本。');
divControls.appendChild(divLabelProcessNormal);
const labelProcessNormal = document.createElement('label');
labelProcessNormal.classList.add('backup-label' + classAppendNewFreshSpace);
labelProcessNormal.textContent = '处理正常视频';
divLabelProcessNormal.appendChild(labelProcessNormal);
const checkboxProcessNormal = document.createElement('input');
checkboxProcessNormal.type = 'checkbox';
checkboxProcessNormal.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxProcessNormal.checked = settings.processNormal;
checkboxProcessNormal.addEventListener('change', () => {
try {
settings.processNormal = checkboxProcessNormal.checked;
if (!settings.processNormal && !settings.processDisabled) {
divLabelGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdatePart.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL3.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApi) {
divLabelGetFromApiUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiUpdate) {
divLabelGetFromApiUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtra) {
divLabelGetFromApiExtraThumbnails.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdate) {
divLabelGetFromApiExtraUpdatePart.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdateAll) {
divLabelGetFromApiExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
}
divLabelGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplus) {
divLabelGetFromBiliplusUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusUpdate) {
divLabelGetFromBiliplusUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
if (settings.getFromApi) {
divLabelGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtra) {
divLabelGetFromBiliplusExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtraUpdate) {
divLabelGetFromBiliplusExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
}
divLabelGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidown) {
divLabelGetFromJijidownUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownUpdate) {
divLabelGetFromJijidownUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownExtra) {
divLabelGetFromJijidownExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownExtraUpdate) {
divLabelGetFromJijidownExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
divLabelGetFromJijidownURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromXbeibeix) {
divLabelGetFromXbeibeixUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromXbeibeixUpdate) {
divLabelGetFromXbeibeixUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL3.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.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxProcessDisabled.checked = settings.processDisabled;
checkboxProcessDisabled.addEventListener('change', () => {
try {
settings.processDisabled = checkboxProcessDisabled.checked;
if (!settings.processNormal && !settings.processDisabled) {
divLabelGetFromApi.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdatePart.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplus.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidown.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeix.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL3.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApi) {
divLabelGetFromApiUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiUpdate) {
divLabelGetFromApiUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtra) {
divLabelGetFromApiExtraThumbnails.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdate) {
divLabelGetFromApiExtraUpdatePart.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdateAll) {
divLabelGetFromApiExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
}
divLabelGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplus) {
divLabelGetFromBiliplusUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusUpdate) {
divLabelGetFromBiliplusUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
if (settings.getFromApi) {
divLabelGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtra) {
divLabelGetFromBiliplusExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtraUpdate) {
divLabelGetFromBiliplusExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
}
divLabelGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidown) {
divLabelGetFromJijidownUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownUpdate) {
divLabelGetFromJijidownUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownExtra) {
divLabelGetFromJijidownExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownExtraUpdate) {
divLabelGetFromJijidownExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
divLabelGetFromJijidownURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromXbeibeix) {
divLabelGetFromXbeibeixUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromXbeibeixUpdate) {
divLabelGetFromXbeibeixUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL3.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelProcessDisabled.insertAdjacentElement('afterbegin', checkboxProcessDisabled);
const divLabelGetFromApi = document.createElement('div');
divLabelGetFromApi.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApi.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' +
'上述接口一次请求即可获取当前页所有视频的数据。\n' +
'地址: https://api.bilibili.com/x/web-interface/archive/desc?bvid={BV号}\n' +
'数据: 完整简介 (最新版本, 非必要不会调用该接口)');
divControls.appendChild(divLabelGetFromApi);
const labelGetFromApi = document.createElement('label');
labelGetFromApi.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromApi.textContent = '从B站接口获取数据';
divLabelGetFromApi.appendChild(labelGetFromApi);
const checkboxGetFromApi = document.createElement('input');
checkboxGetFromApi.type = 'checkbox';
checkboxGetFromApi.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromApi.checked = settings.getFromApi;
checkboxGetFromApi.addEventListener('change', () => {
try {
settings.getFromApi = checkboxGetFromApi.checked;
if (!settings.getFromApi) {
settings.getFromApiExtra = false;
checkboxGetFromApiExtra.checked = false;
settings.getFromApiExtraThumbnails = false;
checkboxGetFromApiExtraThumbnails.checked = false;
settings.getFromBiliplusExtra = false;
checkboxGetFromBiliplusExtra.checked = false;
divLabelGetFromApiUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdatePart.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromApiUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiUpdate) {
divLabelGetFromApiUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtra) {
divLabelGetFromApiExtraThumbnails.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdate) {
divLabelGetFromApiExtraUpdatePart.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdateAll) {
divLabelGetFromApiExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
if (settings.getFromBiliplus) {
divLabelGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtra) {
divLabelGetFromBiliplusExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtraUpdate) {
divLabelGetFromBiliplusExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromApi.insertAdjacentElement('afterbegin', checkboxGetFromApi);
const divLabelGetFromApiUpdate = document.createElement('div');
divLabelGetFromApiUpdate.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiUpdate.setAttribute('title',
'默认: 开启\n' +
'关闭后每个视频从B站接口只会获取一次数据。\n' +
'不建议关闭, 因为某些视频的信息可能会经常更新。');
divControls.appendChild(divLabelGetFromApiUpdate);
const labelGetFromApiUpdate = document.createElement('label');
labelGetFromApiUpdate.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromApiUpdate.textContent = '启用更新';
divLabelGetFromApiUpdate.appendChild(labelGetFromApiUpdate);
const checkboxGetFromApiUpdate = document.createElement('input');
checkboxGetFromApiUpdate.type = 'checkbox';
checkboxGetFromApiUpdate.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromApiUpdate.checked = settings.getFromApiUpdate;
checkboxGetFromApiUpdate.addEventListener('change', () => {
try {
settings.getFromApiUpdate = checkboxGetFromApiUpdate.checked;
if (!settings.getFromApiUpdate) {
divLabelGetFromApiUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromApiUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromApiUpdate.insertAdjacentElement('afterbegin', checkboxGetFromApiUpdate);
const divLabelGetFromApiUpdateInterval = document.createElement('div');
divLabelGetFromApiUpdateInterval.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiUpdateInterval.setAttribute('title',
'默认: 5小时\n' +
'脚本处理某个视频时, 如果发现距离上次从B站接口获取到该视频的数据已经超过了设定的时间间隔, 则会再次从B站接口获取该视频的数据。');
divControls.appendChild(divLabelGetFromApiUpdateInterval);
const labelGetFromApiUpdateInterval = document.createElement('label');
labelGetFromApiUpdateInterval.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelGetFromApiUpdateInterval.appendChild(labelGetFromApiUpdateInterval);
const inputTextGetFromApiUpdateInterval = document.createElement('input');
inputTextGetFromApiUpdateInterval.type = 'text';
inputTextGetFromApiUpdateInterval.classList.add('backup-inputText' + classAppendNewFreshSpace);
inputTextGetFromApiUpdateInterval.value = settings.getFromApiUpdateInterval;
inputTextGetFromApiUpdateInterval.setAttribute('backup-def', 5);
inputTextGetFromApiUpdateInterval.setAttribute('backup-min', 0);
inputTextGetFromApiUpdateInterval.setAttribute('backup-max', 100);
inputTextGetFromApiUpdateInterval.setAttribute('backup-setting', 'getFromApiUpdateInterval');
inputTextGetFromApiUpdateInterval.addEventListener('blur', validateInputText);
labelGetFromApiUpdateInterval.appendChild(document.createTextNode('最小更新间隔'));
labelGetFromApiUpdateInterval.appendChild(inputTextGetFromApiUpdateInterval);
labelGetFromApiUpdateInterval.appendChild(document.createTextNode('小时'));
const divLabelGetFromApiExtra = document.createElement('div');
divLabelGetFromApiExtra.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtra.setAttribute('title',
'默认: 关闭\n' +
'地址: https://api.bilibili.com/x/web-interface/view?bvid={BV号}\n' +
'数据: 完整简介, 视频发布动态内容, 每个分集的标题, 第1帧截图地址 (旧视频无法获取), cid (均为最新版本, 失效视频均无法获取)\n' +
'目前接口 "api.bilibili.com/x/v3/fav/resource/list" 已经设置调用频率限制, 每次请求之间需要至少间隔300毫秒左右。在未来接口 "api.bilibili.com/x/web-interface/view" 也可能会设置类似的限制, 届时频繁从B站接口获取额外数据将会出现问题。');
divControls.appendChild(divLabelGetFromApiExtra);
const labelGetFromApiExtra = document.createElement('label');
labelGetFromApiExtra.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromApiExtra.textContent = '从B站接口获取额外数据(可能频率受限)';
divLabelGetFromApiExtra.appendChild(labelGetFromApiExtra);
const checkboxGetFromApiExtra = document.createElement('input');
checkboxGetFromApiExtra.type = 'checkbox';
checkboxGetFromApiExtra.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromApiExtra.checked = settings.getFromApiExtra;
checkboxGetFromApiExtra.addEventListener('change', () => {
try {
settings.getFromApiExtra = checkboxGetFromApiExtra.checked;
if (!settings.getFromApiExtra) {
settings.getFromApiExtraThumbnails = false;
checkboxGetFromApiExtraThumbnails.checked = false;
divLabelGetFromApiExtraThumbnails.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdatePart.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromApiExtraThumbnails.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdate) {
divLabelGetFromApiExtraUpdatePart.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdateAll) {
divLabelGetFromApiExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromApiExtra.insertAdjacentElement('afterbegin', checkboxGetFromApiExtra);
const divLabelGetFromApiExtraThumbnails = document.createElement('div');
divLabelGetFromApiExtraThumbnails.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraThumbnails.setAttribute('title',
'默认: 关闭\n' +
'地址: https://api.bilibili.com/x/player/videoshot?aid={AV号}&cid={分集cid}\n' +
'数据: 进度条缩略图地址 (失效视频以及部分旧视频无法获取)\n' +
'如果UP主对某个视频进行了换源, 只要该视频的本地备份数据中保存了旧源的cid, 就可以尝试获取旧源的进度条缩略图地址。\n' +
'一次请求只能获取一个分集的进度条缩略图地址, 如果某个视频的分集较多, 则需要等待一段时间。');
divControls.appendChild(divLabelGetFromApiExtraThumbnails);
const labelGetFromApiExtraThumbnails = document.createElement('label');
labelGetFromApiExtraThumbnails.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromApiExtraThumbnails.textContent = '获取进度条缩略图地址';
divLabelGetFromApiExtraThumbnails.appendChild(labelGetFromApiExtraThumbnails);
const checkboxGetFromApiExtraThumbnails = document.createElement('input');
checkboxGetFromApiExtraThumbnails.type = 'checkbox';
checkboxGetFromApiExtraThumbnails.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromApiExtraThumbnails.checked = settings.getFromApiExtraThumbnails;
checkboxGetFromApiExtraThumbnails.addEventListener('change', () => {
try {
settings.getFromApiExtraThumbnails = checkboxGetFromApiExtraThumbnails.checked;
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromApiExtraThumbnails.insertAdjacentElement('afterbegin', checkboxGetFromApiExtraThumbnails);
const divLabelGetFromApiExtraDelay = document.createElement('div');
divLabelGetFromApiExtraDelay.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.setAttribute('title',
'默认: 开启');
if (debug) divControls.appendChild(divLabelGetFromApiExtraDelay);
const labelGetFromApiExtraDelay = document.createElement('label');
labelGetFromApiExtraDelay.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromApiExtraDelay.textContent = '停留500毫秒';
if (debug) divLabelGetFromApiExtraDelay.appendChild(labelGetFromApiExtraDelay);
const checkboxGetFromApiExtraDelay = document.createElement('input');
checkboxGetFromApiExtraDelay.type = 'checkbox';
checkboxGetFromApiExtraDelay.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromApiExtraDelay.checked = getFromApiExtraDelay;
checkboxGetFromApiExtraDelay.addEventListener('change', () => {
try {
getFromApiExtraDelay = checkboxGetFromApiExtraDelay.checked;
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
if (debug) labelGetFromApiExtraDelay.insertAdjacentElement('afterbegin', checkboxGetFromApiExtraDelay);
const divLabelGetFromApiExtraUpdate = document.createElement('div');
divLabelGetFromApiExtraUpdate.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.setAttribute('title',
'默认: 开启');
divControls.appendChild(divLabelGetFromApiExtraUpdate);
const labelGetFromApiExtraUpdate = document.createElement('label');
labelGetFromApiExtraUpdate.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromApiExtraUpdate.textContent = '启用更新';
divLabelGetFromApiExtraUpdate.appendChild(labelGetFromApiExtraUpdate);
const checkboxGetFromApiExtraUpdate = document.createElement('input');
checkboxGetFromApiExtraUpdate.type = 'checkbox';
checkboxGetFromApiExtraUpdate.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromApiExtraUpdate.checked = settings.getFromApiExtraUpdate;
checkboxGetFromApiExtraUpdate.addEventListener('change', () => {
try {
settings.getFromApiExtraUpdate = checkboxGetFromApiExtraUpdate.checked;
if (!settings.getFromApiExtraUpdate) {
divLabelGetFromApiExtraUpdatePart.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromApiExtraUpdatePart.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdateAll) {
divLabelGetFromApiExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromApiExtraUpdate.insertAdjacentElement('afterbegin', checkboxGetFromApiExtraUpdate);
const divLabelGetFromApiExtraUpdatePart = document.createElement('div');
divLabelGetFromApiExtraUpdatePart.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdatePart.setAttribute('title',
'默认: 只更新可能换源的视频\n' +
'只更新可能换源的视频: 脚本处理某个视频时, 从接口 "api.bilibili.com/x/v3/fav/resource/list" 中可以获取到该视频的分集数量以及第1个分集的cid, 如果发现该视频可能进行了换源 (获取的第1个分集的cid在本地备份数据中找不到, 或者获取的分集数量大于1), 才会再次从接口 "api.bilibili.com/x/web-interface/view" 获取该视频的数据。\n' +
'总是更新所有视频: 脚本处理某个视频时, 如果发现距离上次从接口 "api.bilibili.com/x/web-interface/view" 获取到该视频的数据已经超过了设定的时间间隔, 则会再次从该接口获取该视频的数据。一次请求只能获取一个视频的数据, 频繁调用该接口不仅耗费时间, 如果该接口设置了调用频率限制还可能出现问题。');
divControls.appendChild(divLabelGetFromApiExtraUpdatePart);
const labelGetFromApiExtraUpdatePart = document.createElement('label');
labelGetFromApiExtraUpdatePart.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromApiExtraUpdatePart.textContent = '只更新可能换源的视频';
divLabelGetFromApiExtraUpdatePart.appendChild(labelGetFromApiExtraUpdatePart);
const radioGetFromApiExtraUpdatePart = document.createElement('input');
radioGetFromApiExtraUpdatePart.type = 'radio';
radioGetFromApiExtraUpdatePart.classList.add('backup-inputRadio' + classAppendNewFreshSpace);
radioGetFromApiExtraUpdatePart.name = 'getFromApiExtraUpdateAll';
radioGetFromApiExtraUpdatePart.value = false;
radioGetFromApiExtraUpdatePart.checked = !settings.getFromApiExtraUpdateAll;
radioGetFromApiExtraUpdatePart.addEventListener('change', () => {
try {
settings.getFromApiExtraUpdateAll = false;
divLabelGetFromApiExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromApiExtraUpdatePart.insertAdjacentElement('afterbegin', radioGetFromApiExtraUpdatePart);
const divLabelGetFromApiExtraUpdateAll = document.createElement('div');
divLabelGetFromApiExtraUpdateAll.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.setAttribute('title',
'默认: 只更新可能换源的视频\n' +
'只更新可能换源的视频: 脚本处理某个视频时, 从接口 "api.bilibili.com/x/v3/fav/resource/list" 中可以获取到该视频的分集数量以及第1个分集的cid, 如果发现该视频可能进行了换源 (获取的第1个分集的cid在本地备份数据中找不到, 或者获取的分集数量大于1), 才会再次从接口 "api.bilibili.com/x/web-interface/view" 获取该视频的数据。\n' +
'总是更新所有视频: 脚本处理某个视频时, 如果发现距离上次从接口 "api.bilibili.com/x/web-interface/view" 获取到该视频的数据已经超过了设定的时间间隔, 则会再次从该接口获取该视频的数据。一次请求只能获取一个视频的数据, 频繁调用该接口不仅耗费时间, 如果该接口设置了调用频率限制还可能出现问题。');
divControls.appendChild(divLabelGetFromApiExtraUpdateAll);
const labelGetFromApiExtraUpdateAll = document.createElement('label');
labelGetFromApiExtraUpdateAll.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromApiExtraUpdateAll.textContent = '总是更新所有视频';
divLabelGetFromApiExtraUpdateAll.appendChild(labelGetFromApiExtraUpdateAll);
const radioGetFromApiExtraUpdateAll = document.createElement('input');
radioGetFromApiExtraUpdateAll.type = 'radio';
radioGetFromApiExtraUpdateAll.classList.add('backup-inputRadio' + classAppendNewFreshSpace);
radioGetFromApiExtraUpdateAll.name = 'getFromApiExtraUpdateAll';
radioGetFromApiExtraUpdateAll.value = true;
radioGetFromApiExtraUpdateAll.checked = settings.getFromApiExtraUpdateAll;
radioGetFromApiExtraUpdateAll.addEventListener('change', () => {
try {
settings.getFromApiExtraUpdateAll = true;
divLabelGetFromApiExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromApiExtraUpdateAll.insertAdjacentElement('afterbegin', radioGetFromApiExtraUpdateAll);
const divLabelGetFromApiExtraUpdateInterval = document.createElement('div');
divLabelGetFromApiExtraUpdateInterval.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateInterval.setAttribute('title',
'默认: 5天');
divControls.appendChild(divLabelGetFromApiExtraUpdateInterval);
const labelGetFromApiExtraUpdateInterval = document.createElement('label');
labelGetFromApiExtraUpdateInterval.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateInterval.appendChild(labelGetFromApiExtraUpdateInterval);
const inputTextGetFromApiExtraUpdateInterval = document.createElement('input');
inputTextGetFromApiExtraUpdateInterval.type = 'text';
inputTextGetFromApiExtraUpdateInterval.classList.add('backup-inputText' + classAppendNewFreshSpace);
inputTextGetFromApiExtraUpdateInterval.value = settings.getFromApiExtraUpdateInterval;
inputTextGetFromApiExtraUpdateInterval.setAttribute('backup-def', 5);
inputTextGetFromApiExtraUpdateInterval.setAttribute('backup-min', 0);
inputTextGetFromApiExtraUpdateInterval.setAttribute('backup-max', 100);
inputTextGetFromApiExtraUpdateInterval.setAttribute('backup-setting', 'getFromApiExtraUpdateInterval');
inputTextGetFromApiExtraUpdateInterval.addEventListener('blur', validateInputText);
labelGetFromApiExtraUpdateInterval.appendChild(document.createTextNode('最小更新间隔'));
labelGetFromApiExtraUpdateInterval.appendChild(inputTextGetFromApiExtraUpdateInterval);
labelGetFromApiExtraUpdateInterval.appendChild(document.createTextNode('天'));
const divLabelGetFromBiliplus = document.createElement('div');
divLabelGetFromBiliplus.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplus.setAttribute('title',
'默认: 关闭\n' +
'从BiliPlus获取数据时可能会出现问题。\n' +
'地址: https://www.biliplus.com/video/{BV号}\n' +
'数据: 标题, 简介, 封面地址, UP主昵称, 每个分集的标题, cid (均为备份时的版本)');
divControls.appendChild(divLabelGetFromBiliplus);
const labelGetFromBiliplus = document.createElement('label');
labelGetFromBiliplus.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromBiliplus.textContent = '从BiliPlus获取数据(不稳定)';
divLabelGetFromBiliplus.appendChild(labelGetFromBiliplus);
const checkboxGetFromBiliplus = document.createElement('input');
checkboxGetFromBiliplus.type = 'checkbox';
checkboxGetFromBiliplus.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromBiliplus.checked = settings.getFromBiliplus;
checkboxGetFromBiliplus.addEventListener('change', () => {
try {
settings.getFromBiliplus = checkboxGetFromBiliplus.checked;
if (!settings.getFromBiliplus) {
settings.getFromBiliplusExtra = false;
checkboxGetFromBiliplusExtra.checked = false;
divLabelGetFromBiliplusUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromBiliplusUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusUpdate) {
divLabelGetFromBiliplusUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
if (settings.getFromApi) {
divLabelGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtra) {
divLabelGetFromBiliplusExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtraUpdate) {
divLabelGetFromBiliplusExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromBiliplus.insertAdjacentElement('afterbegin', checkboxGetFromBiliplus);
const divLabelGetFromBiliplusUpdate = document.createElement('div');
divLabelGetFromBiliplusUpdate.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusUpdate.setAttribute('title',
'默认: 关闭');
divControls.appendChild(divLabelGetFromBiliplusUpdate);
const labelGetFromBiliplusUpdate = document.createElement('label');
labelGetFromBiliplusUpdate.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromBiliplusUpdate.textContent = '启用更新';
divLabelGetFromBiliplusUpdate.appendChild(labelGetFromBiliplusUpdate);
const checkboxGetFromBiliplusUpdate = document.createElement('input');
checkboxGetFromBiliplusUpdate.type = 'checkbox';
checkboxGetFromBiliplusUpdate.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromBiliplusUpdate.checked = settings.getFromBiliplusUpdate;
checkboxGetFromBiliplusUpdate.addEventListener('change', () => {
try {
settings.getFromBiliplusUpdate = checkboxGetFromBiliplusUpdate.checked;
if (!settings.getFromBiliplusUpdate) {
divLabelGetFromBiliplusUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromBiliplusUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromBiliplusUpdate.insertAdjacentElement('afterbegin', checkboxGetFromBiliplusUpdate);
const divLabelGetFromBiliplusUpdateInterval = document.createElement('div');
divLabelGetFromBiliplusUpdateInterval.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusUpdateInterval.setAttribute('title',
'默认: 10星期');
divControls.appendChild(divLabelGetFromBiliplusUpdateInterval);
const labelGetFromBiliplusUpdateInterval = document.createElement('label');
labelGetFromBiliplusUpdateInterval.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelGetFromBiliplusUpdateInterval.appendChild(labelGetFromBiliplusUpdateInterval);
const inputTextGetFromBiliplusUpdateInterval = document.createElement('input');
inputTextGetFromBiliplusUpdateInterval.type = 'text';
inputTextGetFromBiliplusUpdateInterval.classList.add('backup-inputText' + classAppendNewFreshSpace);
inputTextGetFromBiliplusUpdateInterval.value = settings.getFromBiliplusUpdateInterval;
inputTextGetFromBiliplusUpdateInterval.setAttribute('backup-def', 10);
inputTextGetFromBiliplusUpdateInterval.setAttribute('backup-min', 0);
inputTextGetFromBiliplusUpdateInterval.setAttribute('backup-max', 100);
inputTextGetFromBiliplusUpdateInterval.setAttribute('backup-setting', 'getFromBiliplusUpdateInterval');
inputTextGetFromBiliplusUpdateInterval.addEventListener('blur', validateInputText);
labelGetFromBiliplusUpdateInterval.appendChild(document.createTextNode('最小更新间隔'));
labelGetFromBiliplusUpdateInterval.appendChild(inputTextGetFromBiliplusUpdateInterval);
labelGetFromBiliplusUpdateInterval.appendChild(document.createTextNode('星期'));
const divLabelGetFromBiliplusExtra = document.createElement('div');
divLabelGetFromBiliplusExtra.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtra.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' +
'请注意: 此接口有调用频率限制, 短时间内频繁调用此接口可能会出现请求失败的情况, 之后每次调用此接口需要先等待10秒左右。');
divControls.appendChild(divLabelGetFromBiliplusExtra);
const labelGetFromBiliplusExtra = document.createElement('label');
labelGetFromBiliplusExtra.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromBiliplusExtra.textContent = '从BiliPlus获取额外数据(频率受限)';
divLabelGetFromBiliplusExtra.appendChild(labelGetFromBiliplusExtra);
const checkboxGetFromBiliplusExtra = document.createElement('input');
checkboxGetFromBiliplusExtra.type = 'checkbox';
checkboxGetFromBiliplusExtra.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromBiliplusExtra.checked = settings.getFromBiliplusExtra;
checkboxGetFromBiliplusExtra.addEventListener('change', () => {
try {
settings.getFromBiliplusExtra = checkboxGetFromBiliplusExtra.checked;
if (!settings.getFromBiliplusExtra) {
divLabelGetFromBiliplusExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromBiliplusExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtraUpdate) {
divLabelGetFromBiliplusExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromBiliplusExtra.insertAdjacentElement('afterbegin', checkboxGetFromBiliplusExtra);
const divLabelGetFromBiliplusExtraUpdate = document.createElement('div');
divLabelGetFromBiliplusExtraUpdate.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdate.setAttribute('title',
'默认: 关闭');
divControls.appendChild(divLabelGetFromBiliplusExtraUpdate);
const labelGetFromBiliplusExtraUpdate = document.createElement('label');
labelGetFromBiliplusExtraUpdate.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromBiliplusExtraUpdate.textContent = '启用更新';
divLabelGetFromBiliplusExtraUpdate.appendChild(labelGetFromBiliplusExtraUpdate);
const checkboxGetFromBiliplusExtraUpdate = document.createElement('input');
checkboxGetFromBiliplusExtraUpdate.type = 'checkbox';
checkboxGetFromBiliplusExtraUpdate.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromBiliplusExtraUpdate.checked = settings.getFromBiliplusExtraUpdate;
checkboxGetFromBiliplusExtraUpdate.addEventListener('change', () => {
try {
settings.getFromBiliplusExtraUpdate = checkboxGetFromBiliplusExtraUpdate.checked;
if (!settings.getFromBiliplusExtraUpdate) {
divLabelGetFromBiliplusExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromBiliplusExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromBiliplusExtraUpdate.insertAdjacentElement('afterbegin', checkboxGetFromBiliplusExtraUpdate);
const divLabelGetFromBiliplusExtraUpdateInterval = document.createElement('div');
divLabelGetFromBiliplusExtraUpdateInterval.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdateInterval.setAttribute('title',
'默认: 10星期');
divControls.appendChild(divLabelGetFromBiliplusExtraUpdateInterval);
const labelGetFromBiliplusExtraUpdateInterval = document.createElement('label');
labelGetFromBiliplusExtraUpdateInterval.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelGetFromBiliplusExtraUpdateInterval.appendChild(labelGetFromBiliplusExtraUpdateInterval);
const inputTextGetFromBiliplusExtraUpdateInterval = document.createElement('input');
inputTextGetFromBiliplusExtraUpdateInterval.type = 'text';
inputTextGetFromBiliplusExtraUpdateInterval.classList.add('backup-inputText' + classAppendNewFreshSpace);
inputTextGetFromBiliplusExtraUpdateInterval.value = settings.getFromBiliplusExtraUpdateInterval;
inputTextGetFromBiliplusExtraUpdateInterval.setAttribute('backup-def', 10);
inputTextGetFromBiliplusExtraUpdateInterval.setAttribute('backup-min', 0);
inputTextGetFromBiliplusExtraUpdateInterval.setAttribute('backup-max', 100);
inputTextGetFromBiliplusExtraUpdateInterval.setAttribute('backup-setting', 'getFromBiliplusExtraUpdateInterval');
inputTextGetFromBiliplusExtraUpdateInterval.addEventListener('blur', validateInputText);
labelGetFromBiliplusExtraUpdateInterval.appendChild(document.createTextNode('最小更新间隔'));
labelGetFromBiliplusExtraUpdateInterval.appendChild(inputTextGetFromBiliplusExtraUpdateInterval);
labelGetFromBiliplusExtraUpdateInterval.appendChild(document.createTextNode('星期'));
const divLabelGetFromJijidown = document.createElement('div');
divLabelGetFromJijidown.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidown.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(divLabelGetFromJijidown);
const labelGetFromJijidown = document.createElement('label');
labelGetFromJijidown.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromJijidown.textContent = '从唧唧获取数据(不稳定)';
divLabelGetFromJijidown.appendChild(labelGetFromJijidown);
const checkboxGetFromJijidown = document.createElement('input');
checkboxGetFromJijidown.type = 'checkbox';
checkboxGetFromJijidown.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromJijidown.checked = settings.getFromJijidown;
checkboxGetFromJijidown.addEventListener('change', () => {
try {
settings.getFromJijidown = checkboxGetFromJijidown.checked;
if (!settings.getFromJijidown) {
settings.getFromJijidownExtra = false;
checkboxGetFromJijidownExtra.checked = false;
divLabelGetFromJijidownUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtra.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromJijidownUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownUpdate) {
divLabelGetFromJijidownUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownExtra) {
divLabelGetFromJijidownExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownExtraUpdate) {
divLabelGetFromJijidownExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
divLabelGetFromJijidownURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromJijidown.insertAdjacentElement('afterbegin', checkboxGetFromJijidown);
const divLabelGetFromJijidownUpdate = document.createElement('div');
divLabelGetFromJijidownUpdate.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownUpdate.setAttribute('title',
'默认: 关闭');
divControls.appendChild(divLabelGetFromJijidownUpdate);
const labelGetFromJijidownUpdate = document.createElement('label');
labelGetFromJijidownUpdate.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromJijidownUpdate.textContent = '启用更新';
divLabelGetFromJijidownUpdate.appendChild(labelGetFromJijidownUpdate);
const checkboxGetFromJijidownUpdate = document.createElement('input');
checkboxGetFromJijidownUpdate.type = 'checkbox';
checkboxGetFromJijidownUpdate.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromJijidownUpdate.checked = settings.getFromJijidownUpdate;
checkboxGetFromJijidownUpdate.addEventListener('change', () => {
try {
settings.getFromJijidownUpdate = checkboxGetFromJijidownUpdate.checked;
if (!settings.getFromJijidownUpdate) {
divLabelGetFromJijidownUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromJijidownUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromJijidownUpdate.insertAdjacentElement('afterbegin', checkboxGetFromJijidownUpdate);
const divLabelGetFromJijidownUpdateInterval = document.createElement('div');
divLabelGetFromJijidownUpdateInterval.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownUpdateInterval.setAttribute('title',
'默认: 10星期');
divControls.appendChild(divLabelGetFromJijidownUpdateInterval);
const labelGetFromJijidownUpdateInterval = document.createElement('label');
labelGetFromJijidownUpdateInterval.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelGetFromJijidownUpdateInterval.appendChild(labelGetFromJijidownUpdateInterval);
const inputTextGetFromJijidownUpdateInterval = document.createElement('input');
inputTextGetFromJijidownUpdateInterval.type = 'text';
inputTextGetFromJijidownUpdateInterval.classList.add('backup-inputText' + classAppendNewFreshSpace);
inputTextGetFromJijidownUpdateInterval.value = settings.getFromJijidownUpdateInterval;
inputTextGetFromJijidownUpdateInterval.setAttribute('backup-def', 10);
inputTextGetFromJijidownUpdateInterval.setAttribute('backup-min', 0);
inputTextGetFromJijidownUpdateInterval.setAttribute('backup-max', 100);
inputTextGetFromJijidownUpdateInterval.setAttribute('backup-setting', 'getFromJijidownUpdateInterval');
inputTextGetFromJijidownUpdateInterval.addEventListener('blur', validateInputText);
labelGetFromJijidownUpdateInterval.appendChild(document.createTextNode('最小更新间隔'));
labelGetFromJijidownUpdateInterval.appendChild(inputTextGetFromJijidownUpdateInterval);
labelGetFromJijidownUpdateInterval.appendChild(document.createTextNode('星期'));
const divLabelGetFromJijidownExtra = document.createElement('div');
divLabelGetFromJijidownExtra.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtra.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(divLabelGetFromJijidownExtra);
const labelGetFromJijidownExtra = document.createElement('label');
labelGetFromJijidownExtra.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromJijidownExtra.textContent = '从唧唧获取额外数据(不稳定)';
divLabelGetFromJijidownExtra.appendChild(labelGetFromJijidownExtra);
const checkboxGetFromJijidownExtra = document.createElement('input');
checkboxGetFromJijidownExtra.type = 'checkbox';
checkboxGetFromJijidownExtra.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromJijidownExtra.checked = settings.getFromJijidownExtra;
checkboxGetFromJijidownExtra.addEventListener('change', () => {
try {
settings.getFromJijidownExtra = checkboxGetFromJijidownExtra.checked;
if (!settings.getFromJijidownExtra) {
divLabelGetFromJijidownExtraUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromJijidownExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownExtraUpdate) {
divLabelGetFromJijidownExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromJijidownExtra.insertAdjacentElement('afterbegin', checkboxGetFromJijidownExtra);
const divLabelGetFromJijidownExtraUpdate = document.createElement('div');
divLabelGetFromJijidownExtraUpdate.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdate.setAttribute('title',
'默认: 关闭');
divControls.appendChild(divLabelGetFromJijidownExtraUpdate);
const labelGetFromJijidownExtraUpdate = document.createElement('label');
labelGetFromJijidownExtraUpdate.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromJijidownExtraUpdate.textContent = '启用更新';
divLabelGetFromJijidownExtraUpdate.appendChild(labelGetFromJijidownExtraUpdate);
const checkboxGetFromJijidownExtraUpdate = document.createElement('input');
checkboxGetFromJijidownExtraUpdate.type = 'checkbox';
checkboxGetFromJijidownExtraUpdate.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromJijidownExtraUpdate.checked = settings.getFromJijidownExtraUpdate;
checkboxGetFromJijidownExtraUpdate.addEventListener('change', () => {
try {
settings.getFromJijidownExtraUpdate = checkboxGetFromJijidownExtraUpdate.checked;
if (!settings.getFromJijidownExtraUpdate) {
divLabelGetFromJijidownExtraUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromJijidownExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromJijidownExtraUpdate.insertAdjacentElement('afterbegin', checkboxGetFromJijidownExtraUpdate);
const divLabelGetFromJijidownExtraUpdateInterval = document.createElement('div');
divLabelGetFromJijidownExtraUpdateInterval.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdateInterval.setAttribute('title',
'默认: 10星期');
divControls.appendChild(divLabelGetFromJijidownExtraUpdateInterval);
const labelGetFromJijidownExtraUpdateInterval = document.createElement('label');
labelGetFromJijidownExtraUpdateInterval.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelGetFromJijidownExtraUpdateInterval.appendChild(labelGetFromJijidownExtraUpdateInterval);
const inputTextGetFromJijidownExtraUpdateInterval = document.createElement('input');
inputTextGetFromJijidownExtraUpdateInterval.type = 'text';
inputTextGetFromJijidownExtraUpdateInterval.classList.add('backup-inputText' + classAppendNewFreshSpace);
inputTextGetFromJijidownExtraUpdateInterval.value = settings.getFromJijidownExtraUpdateInterval;
inputTextGetFromJijidownExtraUpdateInterval.setAttribute('backup-def', 10);
inputTextGetFromJijidownExtraUpdateInterval.setAttribute('backup-min', 0);
inputTextGetFromJijidownExtraUpdateInterval.setAttribute('backup-max', 100);
inputTextGetFromJijidownExtraUpdateInterval.setAttribute('backup-setting', 'getFromJijidownExtraUpdateInterval');
inputTextGetFromJijidownExtraUpdateInterval.addEventListener('blur', validateInputText);
labelGetFromJijidownExtraUpdateInterval.appendChild(document.createTextNode('最小更新间隔'));
labelGetFromJijidownExtraUpdateInterval.appendChild(inputTextGetFromJijidownExtraUpdateInterval);
labelGetFromJijidownExtraUpdateInterval.appendChild(document.createTextNode('星期'));
const divLabelGetFromJijidownURL1 = document.createElement('div');
divLabelGetFromJijidownURL1.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL1.setAttribute('title',
'默认: www.jijidown.com\n' +
'www.jiji.moe为唧唧的新域名。\n' +
'如果脚本从唧唧获取数据时反复出现问题, 切换至另一域名可能有帮助。');
divControls.appendChild(divLabelGetFromJijidownURL1);
const labelGetFromJijidownURL1 = document.createElement('label');
labelGetFromJijidownURL1.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromJijidownURL1.textContent = 'www.jijidown.com';
divLabelGetFromJijidownURL1.appendChild(labelGetFromJijidownURL1);
const radioGetFromJijidownURL1 = document.createElement('input');
radioGetFromJijidownURL1.type = 'radio';
radioGetFromJijidownURL1.classList.add('backup-inputRadio' + classAppendNewFreshSpace);
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 divLabelGetFromJijidownURL2 = document.createElement('div');
divLabelGetFromJijidownURL2.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL2.setAttribute('title',
'默认: www.jijidown.com\n' +
'www.jiji.moe为唧唧的新域名。\n' +
'如果脚本从唧唧获取数据时反复出现问题, 切换至另一域名可能有帮助。');
divControls.appendChild(divLabelGetFromJijidownURL2);
const labelGetFromJijidownURL2 = document.createElement('label');
labelGetFromJijidownURL2.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromJijidownURL2.textContent = 'www.jiji.moe';
divLabelGetFromJijidownURL2.appendChild(labelGetFromJijidownURL2);
const radioGetFromJijidownURL2 = document.createElement('input');
radioGetFromJijidownURL2.type = 'radio';
radioGetFromJijidownURL2.classList.add('backup-inputRadio' + classAppendNewFreshSpace);
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 divLabelGetFromXbeibeix = document.createElement('div');
divLabelGetFromXbeibeix.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeix.setAttribute('title',
'默认: 关闭\n' +
'从贝贝工具站获取数据时可能会出现请求超时和请求失败的情况。\n' +
'地址: https://xbeibeix.com/video/{BV号}\n' +
'或 https://beibeigame.com/video/{BV号}\n' +
'或 https://bbdownloader.com/video/{BV号} (取决于下面的单选项)\n' +
'数据: 标题, 简介, 封面地址, UP主昵称 (均为备份时的版本)');
divControls.appendChild(divLabelGetFromXbeibeix);
const labelGetFromXbeibeix = document.createElement('label');
labelGetFromXbeibeix.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromXbeibeix.textContent = '从贝贝工具站获取数据(不稳定)';
divLabelGetFromXbeibeix.appendChild(labelGetFromXbeibeix);
const checkboxGetFromXbeibeix = document.createElement('input');
checkboxGetFromXbeibeix.type = 'checkbox';
checkboxGetFromXbeibeix.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromXbeibeix.checked = settings.getFromXbeibeix;
checkboxGetFromXbeibeix.addEventListener('change', () => {
try {
settings.getFromXbeibeix = checkboxGetFromXbeibeix.checked;
if (!settings.getFromXbeibeix) {
divLabelGetFromXbeibeixUpdate.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL1.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL2.classList.add('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL3.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromXbeibeixUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromXbeibeixUpdate) {
divLabelGetFromXbeibeixUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL3.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromXbeibeix.insertAdjacentElement('afterbegin', checkboxGetFromXbeibeix);
const divLabelGetFromXbeibeixUpdate = document.createElement('div');
divLabelGetFromXbeibeixUpdate.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixUpdate.setAttribute('title',
'默认: 关闭');
divControls.appendChild(divLabelGetFromXbeibeixUpdate);
const labelGetFromXbeibeixUpdate = document.createElement('label');
labelGetFromXbeibeixUpdate.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromXbeibeixUpdate.textContent = '启用更新';
divLabelGetFromXbeibeixUpdate.appendChild(labelGetFromXbeibeixUpdate);
const checkboxGetFromXbeibeixUpdate = document.createElement('input');
checkboxGetFromXbeibeixUpdate.type = 'checkbox';
checkboxGetFromXbeibeixUpdate.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxGetFromXbeibeixUpdate.checked = settings.getFromXbeibeixUpdate;
checkboxGetFromXbeibeixUpdate.addEventListener('change', () => {
try {
settings.getFromXbeibeixUpdate = checkboxGetFromXbeibeixUpdate.checked;
if (!settings.getFromXbeibeixUpdate) {
divLabelGetFromXbeibeixUpdateInterval.classList.add('backup-disabled' + classAppendNewFreshSpace);
} else {
divLabelGetFromXbeibeixUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromXbeibeixUpdate.insertAdjacentElement('afterbegin', checkboxGetFromXbeibeixUpdate);
const divLabelGetFromXbeibeixUpdateInterval = document.createElement('div');
divLabelGetFromXbeibeixUpdateInterval.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced', 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixUpdateInterval.setAttribute('title',
'默认: 10星期');
divControls.appendChild(divLabelGetFromXbeibeixUpdateInterval);
const labelGetFromXbeibeixUpdateInterval = document.createElement('label');
labelGetFromXbeibeixUpdateInterval.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixUpdateInterval.appendChild(labelGetFromXbeibeixUpdateInterval);
const inputTextGetFromXbeibeixUpdateInterval = document.createElement('input');
inputTextGetFromXbeibeixUpdateInterval.type = 'text';
inputTextGetFromXbeibeixUpdateInterval.classList.add('backup-inputText' + classAppendNewFreshSpace);
inputTextGetFromXbeibeixUpdateInterval.value = settings.getFromXbeibeixUpdateInterval;
inputTextGetFromXbeibeixUpdateInterval.setAttribute('backup-def', 10);
inputTextGetFromXbeibeixUpdateInterval.setAttribute('backup-min', 0);
inputTextGetFromXbeibeixUpdateInterval.setAttribute('backup-max', 100);
inputTextGetFromXbeibeixUpdateInterval.setAttribute('backup-setting', 'getFromXbeibeixUpdateInterval');
inputTextGetFromXbeibeixUpdateInterval.addEventListener('blur', validateInputText);
labelGetFromXbeibeixUpdateInterval.appendChild(document.createTextNode('最小更新间隔'));
labelGetFromXbeibeixUpdateInterval.appendChild(inputTextGetFromXbeibeixUpdateInterval);
labelGetFromXbeibeixUpdateInterval.appendChild(document.createTextNode('星期'));
const divLabelGetFromXbeibeixURL1 = document.createElement('div');
divLabelGetFromXbeibeixURL1.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL1.setAttribute('title',
'默认: xbeibeix.com\n' +
'beibeigame.com和bbdownloader.com为贝贝工具站的新域名。\n' +
'如果脚本从贝贝工具站获取数据时反复出现问题, 切换至另一域名可能有帮助。');
divControls.appendChild(divLabelGetFromXbeibeixURL1);
const labelGetFromXbeibeixURL1 = document.createElement('label');
labelGetFromXbeibeixURL1.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromXbeibeixURL1.textContent = 'xbeibeix.com';
divLabelGetFromXbeibeixURL1.appendChild(labelGetFromXbeibeixURL1);
const radioGetFromXbeibeixURL1 = document.createElement('input');
radioGetFromXbeibeixURL1.type = 'radio';
radioGetFromXbeibeixURL1.classList.add('backup-inputRadio' + classAppendNewFreshSpace);
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 divLabelGetFromXbeibeixURL2 = document.createElement('div');
divLabelGetFromXbeibeixURL2.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL2.setAttribute('title',
'默认: xbeibeix.com\n' +
'beibeigame.com和bbdownloader.com为贝贝工具站的新域名。\n' +
'如果脚本从贝贝工具站获取数据时反复出现问题, 切换至另一域名可能有帮助。');
divControls.appendChild(divLabelGetFromXbeibeixURL2);
const labelGetFromXbeibeixURL2 = document.createElement('label');
labelGetFromXbeibeixURL2.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromXbeibeixURL2.textContent = 'beibeigame.com';
divLabelGetFromXbeibeixURL2.appendChild(labelGetFromXbeibeixURL2);
const radioGetFromXbeibeixURL2 = document.createElement('input');
radioGetFromXbeibeixURL2.type = 'radio';
radioGetFromXbeibeixURL2.classList.add('backup-inputRadio' + classAppendNewFreshSpace);
radioGetFromXbeibeixURL2.name = 'getFromXbeibeixURL';
radioGetFromXbeibeixURL2.value = 'beibeigame.com';
radioGetFromXbeibeixURL2.checked = settings.getFromXbeibeixURL === 'beibeigame.com';
radioGetFromXbeibeixURL2.addEventListener('change', () => {
try {
settings.getFromXbeibeixURL = 'beibeigame.com';
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromXbeibeixURL2.insertAdjacentElement('afterbegin', radioGetFromXbeibeixURL2);
const divLabelGetFromXbeibeixURL3 = document.createElement('div');
divLabelGetFromXbeibeixURL3.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL3.setAttribute('title',
'默认: xbeibeix.com\n' +
'beibeigame.com和bbdownloader.com为贝贝工具站的新域名。\n' +
'如果脚本从贝贝工具站获取数据时反复出现问题, 切换至另一域名可能有帮助。');
divControls.appendChild(divLabelGetFromXbeibeixURL3);
const labelGetFromXbeibeixURL3 = document.createElement('label');
labelGetFromXbeibeixURL3.classList.add('backup-label' + classAppendNewFreshSpace);
labelGetFromXbeibeixURL3.textContent = 'bbdownloader.com';
divLabelGetFromXbeibeixURL3.appendChild(labelGetFromXbeibeixURL3);
const radioGetFromXbeibeixURL3 = document.createElement('input');
radioGetFromXbeibeixURL3.type = 'radio';
radioGetFromXbeibeixURL3.classList.add('backup-inputRadio' + classAppendNewFreshSpace);
radioGetFromXbeibeixURL3.name = 'getFromXbeibeixURL';
radioGetFromXbeibeixURL3.value = 'bbdownloader.com';
radioGetFromXbeibeixURL3.checked = settings.getFromXbeibeixURL === 'bbdownloader.com';
radioGetFromXbeibeixURL3.addEventListener('change', () => {
try {
settings.getFromXbeibeixURL = 'bbdownloader.com';
GM_setValue('settings', settings);
} catch (error) {
catchUnknownError(error);
}
});
labelGetFromXbeibeixURL3.insertAdjacentElement('afterbegin', radioGetFromXbeibeixURL3);
const divLabelAutoNextPage = document.createElement('div');
divLabelAutoNextPage.classList.add('backup-div-first' + classAppendNewFreshSpace);
divLabelAutoNextPage.setAttribute('title',
'开启后脚本将在当前页的视频都处理完毕之后点击下一页, 继续处理下一页的视频。');
divControls.appendChild(divLabelAutoNextPage);
const labelAutoNextPage = document.createElement('label');
labelAutoNextPage.classList.add('backup-label' + classAppendNewFreshSpace);
labelAutoNextPage.textContent = '自动点击下一页';
divLabelAutoNextPage.appendChild(labelAutoNextPage);
const checkboxAutoNextPage = document.createElement('input');
checkboxAutoNextPage.type = 'checkbox';
checkboxAutoNextPage.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxAutoNextPage.checked = autoNextPage;
checkboxAutoNextPage.addEventListener('change', async () => {
try {
autoNextPage = checkboxAutoNextPage.checked;
if (autoNextPage) {
divLabelAutoNextFavlist.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 (autoNextPage) {
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 (autoNextPage) {
pager.click();
}
}
}
}
} else {
autoNextFavlist = false;
checkboxAutoNextFavlist.checked = false;
divLabelAutoNextFavlist.classList.add('backup-disabled' + classAppendNewFreshSpace);
}
} catch (error) {
catchUnknownError(error);
}
});
labelAutoNextPage.insertAdjacentElement('afterbegin', checkboxAutoNextPage);
const divLabelAutoNextFavlist = document.createElement('div');
divLabelAutoNextFavlist.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-disabled' + classAppendNewFreshSpace);
divLabelAutoNextFavlist.setAttribute('title',
'开启后脚本将在当前收藏夹的视频都处理完毕之后点击下一收藏夹, 继续处理下一收藏夹的视频。');
divControls.appendChild(divLabelAutoNextFavlist);
const labelAutoNextFavlist = document.createElement('label');
labelAutoNextFavlist.classList.add('backup-label' + classAppendNewFreshSpace);
labelAutoNextFavlist.textContent = '自动点击下一收藏夹';
divLabelAutoNextFavlist.appendChild(labelAutoNextFavlist);
const checkboxAutoNextFavlist = document.createElement('input');
checkboxAutoNextFavlist.type = 'checkbox';
checkboxAutoNextFavlist.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
checkboxAutoNextFavlist.checked = autoNextFavlist;
checkboxAutoNextFavlist.addEventListener('change', async () => {
try {
autoNextFavlist = checkboxAutoNextFavlist.checked;
if (autoNextFavlist && !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 (autoNextFavlist) {
document.querySelector('div.fav-sortable-list').firstElementChild.querySelector('div').click();
}
}
} else {
const nextFavlist = currentFavlist.parentNode.nextElementSibling;
if (nextFavlist) {
await delay(500);
if (autoNextFavlist) {
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 (autoNextFavlist) {
document.querySelector('ul.fav-list').firstElementChild.querySelector('a').click();
}
}
} else {
const nextFavlist = currentFavlist.nextElementSibling;
if (nextFavlist) {
await delay(500);
if (autoNextFavlist) {
nextFavlist.querySelector('a').click();
}
}
}
}
}
}
} catch (error) {
catchUnknownError(error);
}
});
labelAutoNextFavlist.insertAdjacentElement('afterbegin', checkboxAutoNextFavlist);
const divLabelAutoNextPageInterval = document.createElement('div');
divLabelAutoNextPageInterval.classList.add('backup-div-second' + classAppendNewFreshSpace, 'backup-advanced');
divLabelAutoNextPageInterval.setAttribute('title',
'默认: 5秒\n' +
'每次点击下一页或下一收藏夹之前停留在当前页的时间。');
divControls.appendChild(divLabelAutoNextPageInterval);
const labelAutoNextPageInterval = document.createElement('label');
labelAutoNextPageInterval.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelAutoNextPageInterval.appendChild(labelAutoNextPageInterval);
const inputTextAutoNextPageInterval = document.createElement('input');
inputTextAutoNextPageInterval.type = 'text';
inputTextAutoNextPageInterval.classList.add('backup-inputText' + classAppendNewFreshSpace);
inputTextAutoNextPageInterval.value = settings.autoNextPageInterval;
inputTextAutoNextPageInterval.setAttribute('backup-def', 5);
inputTextAutoNextPageInterval.setAttribute('backup-min', 1);
inputTextAutoNextPageInterval.setAttribute('backup-max', 500);
inputTextAutoNextPageInterval.setAttribute('backup-setting', 'autoNextPageInterval');
inputTextAutoNextPageInterval.addEventListener('blur', validateInputText);
labelAutoNextPageInterval.appendChild(document.createTextNode('停留间隔'));
labelAutoNextPageInterval.appendChild(inputTextAutoNextPageInterval);
labelAutoNextPageInterval.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 divLabelDelayBeforeMain = document.createElement('div');
divLabelDelayBeforeMain.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced');
divLabelDelayBeforeMain.setAttribute('title',
'默认: 300毫秒\n' +
'如果您使用的是新版个人空间, 并且遇到了视频标题下方的信息展示出来后又突然消失的情况, 请将这个时长调大一些。\n' +
'如果您想将其设置为0, 则需要避免取消收藏, 指定排序方式或筛选条件等操作, 否则可能会出现问题。');
divControls.appendChild(divLabelDelayBeforeMain);
const labelDelayBeforeMain = document.createElement('label');
labelDelayBeforeMain.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelDelayBeforeMain.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', 0);
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.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
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.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
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.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
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.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
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 divLabelTCABJXOpacity = document.createElement('div');
divLabelTCABJXOpacity.classList.add('backup-div-first' + classAppendNewFreshSpace, 'backup-advanced');
divLabelTCABJXOpacity.setAttribute('title',
'默认: 100%\n' +
'如果您觉得视频标题下方的TCABJX太显眼, 可以将其不透明度调低一些。');
divControls.appendChild(divLabelTCABJXOpacity);
const labelTCABJXOpacity = document.createElement('label');
labelTCABJXOpacity.classList.add('backup-label' + classAppendNewFreshSpace);
divLabelTCABJXOpacity.appendChild(labelTCABJXOpacity);
const inputTextTCABJXOpacity = document.createElement('input');
inputTextTCABJXOpacity.type = 'text';
inputTextTCABJXOpacity.classList.add('backup-inputText' + classAppendNewFreshSpace);
inputTextTCABJXOpacity.value = settings.TCABJXOpacity;
inputTextTCABJXOpacity.setAttribute('backup-def', 100);
inputTextTCABJXOpacity.setAttribute('backup-min', 0);
inputTextTCABJXOpacity.setAttribute('backup-max', 100);
inputTextTCABJXOpacity.setAttribute('backup-setting', 'TCABJXOpacity');
inputTextTCABJXOpacity.addEventListener('blur', validateInputText);
labelTCABJXOpacity.appendChild(document.createTextNode('TCABJX不透明度'));
labelTCABJXOpacity.appendChild(inputTextTCABJXOpacity);
labelTCABJXOpacity.appendChild(document.createTextNode('%'));
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.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
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.classList.add('backup-inputCheckbox' + classAppendNewFreshSpace);
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.result);
if (typeof backupsToImport !== 'object') {
addMessage('文件内容有误, 无法导入', false, 'red');
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, 'red');
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('导入完成', false, 'green');
} 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('已完成', false, 'green');
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.cover.includes('be27fd62c99036dce67efface486fb0a88ffed06')) {
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 (debug) {
addMessage('getFromApiLegacy 无法获取pages', false, 'red');
addMessage(media.bvid, true);
console.warn('getFromApiLegacy 无法获取pages');
console.warn(media);
}
}
const sortedBackup = {};
for (const sortedKey of sortedKeys) {
sortedBackup[sortedKey] = backup[sortedKey];
}
GM_setValue(media.bvid, sortedBackup);
if (debug) {
console.log('保存旧版B站接口的数据至本地');
console.debug(media.bvid);
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, 'red');
for (let i = 1; i < error.length; i++) {
addMessage(error[i], true);
}
}
}
});
divButtonGetFromApiLegacy.appendChild(buttonGetFromApiLegacy);
if (debug) {
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 (debug) {
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('已完成', false, 'green');
} catch (error) {
catchUnknownError(error);
}
});
divButton.appendChild(button);
}
if (debug) {
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为null';
button.addEventListener('click', () => {
try {
const backups = GM_getValues(GM_listValues());
delete backups.settings;
for (const BVOfBackup in backups) {
if (!backups[BVOfBackup].timeFavorite) {
GM_deleteValue(BVOfBackup);
}
}
addMessage('已完成', false, 'green');
} catch (error) {
catchUnknownError(error);
}
});
divButton.appendChild(button);
}
if (debug) {
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为null';
button.addEventListener('click', () => {
try {
const backups = GM_getValues(GM_listValues());
delete backups.settings;
for (const BVOfBackup in backups) {
if (backups[BVOfBackup].timeFavorite) {
GM_deleteValue(BVOfBackup);
}
}
addMessage('已完成', false, 'green');
} catch (error) {
catchUnknownError(error);
}
});
divButton.appendChild(button);
}
if (debug) {
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 = '删除指定BV';
button.addEventListener('click', () => {
try {
const BVs = [
"BV17x411w7KC",
];
const backups = GM_getValues(GM_listValues());
delete backups.settings;
for (const BVOfBackup in backups) {
if (BVs.includes(BVOfBackup)) {
GM_deleteValue(BVOfBackup);
}
}
addMessage('已完成', false, 'green');
} catch (error) {
catchUnknownError(error);
}
});
divButton.appendChild(button);
}
if (debug) {
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 = '保留指定BV';
button.addEventListener('click', () => {
try {
const BVs = [
"BV17x411w7KC",
];
const backups = GM_getValues(GM_listValues());
delete backups.settings;
for (const BVOfBackup in backups) {
if (!BVs.includes(BVOfBackup)) {
GM_deleteValue(BVOfBackup);
}
}
addMessage('已完成', false, 'green');
} catch (error) {
catchUnknownError(error);
}
});
divButton.appendChild(button);
}
// @grant GM_cookie
if (debug) {
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 {
GM_cookie.list({ name: 'bili_jct' }, async (cookies, error) => {
if (error) {
throw ['无法读取cookie, 更新Tampermonkey可能有帮助'];
}
try {
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 searchKeyword = '';
const inputKeyword = document.querySelector(newFreshSpace ? 'input.fav-list-header-filter__search' : 'input.search-fav-input');
if (inputKeyword) {
searchKeyword = inputKeyword.value;
}
const fidSource = fid;
const fidTarget = parseInt(searchKeyword, 10);
const order = 'pubtime';
let pageNumber = 1;
const BVsFavlistVisable = [];
while (true) {
const response = await new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'GET',
url: `https://api.bilibili.com/x/v3/fav/resource/list?media_id=${fidSource}&pn=${pageNumber}&ps=40&keyword=&order=${order}&type=0&tid=0&platform=web&web_location=333.1387`,
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'])
});
});
if (response.response.data.medias) {
BVsFavlistVisable.push(...response.response.data.medias.filter(el => el.type === 2).map(el => `${el.id}:2`));
}
addMessage(`已获取可见视频个数: ${BVsFavlistVisable.length}`, true);
if (!response.response.data.has_more) {
break;
}
pageNumber++;
}
BVsFavlistVisable.reverse();
let start = 0;
while (true) {
const sl = BVsFavlistVisable.slice(start, start + 40);
if (!sl.length) {
addMessage('已完成', false, 'green');
break;
}
const csrf = cookies[0].value;
const data = `resources=${sl.join()}&src_media_id=${fidSource}&tar_media_id=${fidTarget}&mid=${settings.defaultUID}&platform=web&csrf=${csrf}`;
const response2 = await new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
url: 'https://api.bilibili.com/x/v3/fav/resource/move',
data: data,
timeout: 1000 * settings.requestTimeout,
headers: {
'Content-Length': data.length,
'Content-Type': 'application/x-www-form-urlencoded'
},
onload: (res) => resolve(res),
onerror: (res) => reject(['请求失败', 'api.bilibili.com/x/v3/fav/resource/move', res.error]),
ontimeout: () => reject(['请求超时', 'api.bilibili.com/x/v3/fav/resource/move'])
});
});
addMessage('B站接口响应内容:');
addMessage(response2.response, true);
start += 40;
await delay(1000);
}
} catch (error) {
if (error instanceof Error) {
catchUnknownError(error);
} else {
addMessage(error[0], false, 'red');
for (let i = 1; i < error.length; i++) {
addMessage(error[i], true);
}
}
}
});
} catch (error) {
catchUnknownError(error);
}
});
divButton.appendChild(button);
}
if (debug) {
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', async () => {
try {
const videos = [
{
"AV": 170001,
"BV": "BV17x411w7KC"
},
];
for (const video of videos) {
const AVBVTitle = {
AV: null,
BV: null,
title: null
};
try {
AVBVTitle.AV = video.AV;
AVBVTitle.BV = video.BV;
AVBVTitle.title = '';
const spanX = document.createElement('span');
const spanJ = document.createElement('span');
const spanB = document.createElement('span');
const spanA = document.createElement('span');
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,
});
const functions = [];
functions.push(getFromJijidown(AVBVTitle, backup, spanJ));
functions.push(getFromXbeibeix(AVBVTitle, backup, spanX));
functions.push(getFromBiliplus(AVBVTitle, backup, spanB));
await Promise.all(functions);
} catch (error) {
if (error instanceof Error) {
if (error.name === 'AbortError') {
throw error;
}
addMessage('发生未知错误, 请反馈该问题', false, 'red');
addMessageAVBVTitle(AVBVTitle);
addMessage(error.stack, true);
consoleAVBVTitle('error', AVBVTitle);
console.error(error);
} else {
addMessage(error[0], false, 'red');
for (let i = 1; i < error.length; i++) {
addMessage(error[i], true);
}
addMessageAVBVTitle(AVBVTitle);
}
}
}
addMessage('已完成', false, 'green');
} catch (error) {
if (error instanceof Error) {
if (error.name === 'AbortError') {
return;
}
catchUnknownError(error);
} else {
addMessage(error[0], false, 'red');
for (let i = 1; i < error.length; i++) {
addMessage(error[i], true);
}
}
}
});
divButton.appendChild(button);
}
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);
divMessage = document.createElement('div');
divMessage.classList.add('backup-divMessage' + classAppendNewFreshSpace);
divControls.appendChild(divMessage);
// if (displayUpdate) {
// setTimeout(() => {
// addMessage(updates);
// }, 300);
// }
if (settings.processNormal || settings.processDisabled) {
divLabelGetFromApi.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApi) {
divLabelGetFromApiUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiUpdate) {
divLabelGetFromApiUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromApiExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtra) {
divLabelGetFromApiExtraThumbnails.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraDelay.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdate) {
divLabelGetFromApiExtraUpdatePart.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromApiExtraUpdateAll.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromApiExtraUpdateAll) {
divLabelGetFromApiExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
}
divLabelGetFromBiliplus.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplus) {
divLabelGetFromBiliplusUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusUpdate) {
divLabelGetFromBiliplusUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
if (settings.getFromApi) {
divLabelGetFromBiliplusExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtra) {
divLabelGetFromBiliplusExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromBiliplusExtraUpdate) {
divLabelGetFromBiliplusExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
}
}
divLabelGetFromJijidown.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidown) {
divLabelGetFromJijidownUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownUpdate) {
divLabelGetFromJijidownUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromJijidownExtra.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownExtra) {
divLabelGetFromJijidownExtraUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromJijidownExtraUpdate) {
divLabelGetFromJijidownExtraUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
}
divLabelGetFromJijidownURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromJijidownURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromXbeibeix.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromXbeibeix) {
divLabelGetFromXbeibeixUpdate.classList.remove('backup-disabled' + classAppendNewFreshSpace);
if (settings.getFromXbeibeixUpdate) {
divLabelGetFromXbeibeixUpdateInterval.classList.remove('backup-disabled' + classAppendNewFreshSpace);
}
divLabelGetFromXbeibeixURL1.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL2.classList.remove('backup-disabled' + classAppendNewFreshSpace);
divLabelGetFromXbeibeixURL3.classList.remove('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, 'red');
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, 'red');
return;
}
if (divTargetVideo.querySelector('div.bili-cover-card__tags')) {
if (debug) 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, 'red');
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, searchType, getFromApiExtraNeeded) {
if (!apiDetails.value) {
const urlWithParams = await appendParamsForGetFromApi(fid, pageNumber, pageSize);
const response = await new Promise((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'])
});
});
if (response.status !== 200) {
throw ['请求失败', 'api.bilibili.com/x/v3/fav/resource/list', `${response.status} ${response.statusText}`];
}
apiDetails.value = response.response.data.medias;
}
const apiDetail = apiDetails.value.find(el => el.bvid === AVBVTitle.BV);
if (!apiDetail) {
if (debug) {
addMessage('getFromApi 从B站接口获取的数据中没有该视频', false, 'red');
addMessage(AVBVTitle.BV, true);
console.warn('getFromApi 从B站接口获取的数据中没有该视频');
console.warn(AVBVTitle.BV);
}
return true;
}
if (!AVBVTitle.AV) {
AVBVTitle.AV = apiDetail.id;
backup.AV = apiDetail.id;
}
if (debug) {
console.log('从B站接口获取数据');
consoleAVBVTitle('debug', AVBVTitle);
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');
} else {
if (debug) {
if (apiDetail.title !== '已失效视频') {
addMessage('失效视频标题已更改', false, 'red');
console.warn('失效视频标题已更改');
}
if (!apiDetail.cover.includes('be27fd62c99036dce67efface486fb0a88ffed06')) {
addMessage('失效视频封面已更改', false, 'red');
console.warn('失效视频封面已更改');
}
}
}
updateArrayDataInBackup(backup, 'intro', apiDetail.intro, getCurrentTs(), 'api.bilibili.com/x/v3/fav/resource/list');
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 (!searchType) {
updateTimeFavoriteInBackup(backup, apiDetail.fav_time, fid);
}
if (apiDetail.ugc && apiDetail.ugc.first_cid) {
if (updatePagesInBackup(backup, 1, undefined, undefined, undefined, apiDetail.ugc.first_cid, getCurrentTs(), 'api.bilibili.com/x/v3/fav/resource/list')) {
getFromApiExtraNeeded.value = true;
}
} else if (!disabled) {
if (debug) {
addMessage('getFromApi 无first_cid', false, 'red');
addMessage(AVBVTitle.BV, true);
console.warn('getFromApi 无first_cid');
console.warn(AVBVTitle.BV);
}
}
if (apiDetail.page) {
if (apiDetail.page > 1) {
getFromApiExtraNeeded.value = true;
}
} else if (!disabled) {
if (debug) {
addMessage('getFromApi 无page', false, 'red');
addMessage(AVBVTitle.BV, true);
console.warn('getFromApi 无page');
console.warn(AVBVTitle.BV);
}
}
if (!disabled && apiDetail.intro.length >= 255) {
let getIntroNeeded = true;
if (settings.getFromApiExtra) {
if (!backup.apiExtra) {
getIntroNeeded = false;
} else if (settings.getFromApiExtraUpdate && settings.getFromApiExtraUpdateAll && getCurrentTs() - backup.apiExtra.ts > 3600 * 24 * settings.getFromApiExtraUpdateInterval) {
getIntroNeeded = false;
} else if (settings.getFromApiExtraUpdate && !settings.getFromApiExtraUpdateAll && getFromApiExtraNeeded.value) {
getIntroNeeded = false;
}
}
if (getIntroNeeded) {
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'])
});
});
if (response.status !== 200) {
throw ['请求失败', 'api.bilibili.com/x/web-interface/archive/desc', `${response.status} ${response.statusText}`];
}
updateArrayDataInBackup(backup, 'intro', response.response.data, getCurrentTs(), 'api.bilibili.com/x/web-interface/archive/desc');
}
}
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 (debug) {
console.log('保存B站接口的数据至本地');
consoleAVBVTitle('debug', AVBVTitle);
console.debug(sortedBackup);
}
}
async function getFromApiExtra(AVBVTitle, backup, spanA, disabled) {
if (disabled) {
backup.apiExtra = { value: false, ts: getCurrentTs() };
spanA.style.color = '#800000';
} else {
if (getFromApiExtraDelay) {
await delay(500);
}
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'])
});
});
if (response.status !== 200) {
throw ['请求失败', 'api.bilibili.com/x/web-interface/view', `${response.status} ${response.statusText}`];
}
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 (debug) {
addMessage(`getFromApiExtra desc_v2未知type: ${desc.type}`, false, 'red');
addMessage(AVBVTitle.BV, true);
console.warn(`getFromApiExtra desc_v2未知type: ${desc.type}`);
console.warn(AVBVTitle.BV);
}
}
}
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');
});
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 (debug) {
console.log('保存B站接口的额外数据至本地');
consoleAVBVTitle('debug', AVBVTitle);
console.debug(sortedBackup);
}
}
async function getFromApiExtraThumbnails(AVBVTitle, backup, as, controller) {
let setValueNeeded = false;
for (const [index, page] of backup.pages.entries()) {
if (controller.signal.aborted) {
throw new DOMException('', 'AbortError');
}
if (!page.cid) {
continue;
}
let getThumbnailsNeeded = true;
if (page.thumbnails) {
// for (const thumbnail of page.thumbnails) {
// if (thumbnail.includes('videoshotpvhdboss')) {
// getThumbnailsNeeded = false;
// break;
// }
// }
getThumbnailsNeeded = false;
}
if (getThumbnailsNeeded) {
if (backup.pages.length > 10) {
as[1].textContent = `获取缩略图${index + 1}/${backup.pages.length} | ${AVBVTitle.title}`;
}
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.status !== 200) {
throw ['请求失败', 'api.bilibili.com/x/player/videoshot', `${response.status} ${response.statusText}`];
}
if (!response.response.data.image || !response.response.data.image.length) {
if (debug) {
addMessage('getFromApiExtra 无法获取thumbnails', false, 'red');
addMessage(JSON.stringify(response.response), 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);
});
setValueNeeded = true;
}
}
if (backup.pages.length > 10) {
as[1].textContent = AVBVTitle.title;
}
if (setValueNeeded) {
const sortedBackup = {};
for (const sortedKey of sortedKeys) {
sortedBackup[sortedKey] = backup[sortedKey];
}
GM_setValue(AVBVTitle.BV, sortedBackup);
if (debug) {
console.log('保存进度条缩略图地址至本地');
consoleAVBVTitle('debug', AVBVTitle);
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'])
});
});
let json;
const getJsonFromBiliplusMatch = response.response.match(getJsonFromBiliplusRegex);
if (getJsonFromBiliplusMatch) {
json = JSON.parse(getJsonFromBiliplusMatch[1]);
}
if (!json) {
if (debug) {
addMessage('getFromBiliplus 获取数据为空', false, 'red');
addMessage(AVBVTitle.BV, true);
console.warn('getFromBiliplus 获取数据为空');
console.warn(AVBVTitle.BV);
}
}
if (json && json.title) {
if (debug) {
console.log('从BiliPlus获取有效数据');
consoleAVBVTitle('debug', AVBVTitle);
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');
if (Array.isArray(json.list)) {
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 (debug) {
// if (json.v2_app_api.cid && json.v2_app_api.cid !== json.list[0].cid) {
// addMessage('getFromBiliplus cid 不一致1', false, 'red');
// 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', false, 'red');
// 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', false, 'red');
// 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 (debug) {
// addMessage('getFromBiliplus firstFrame 不一致', false, 'red');
// 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 (debug) {
console.log('从BiliPlus获取无效数据');
consoleAVBVTitle('debug', AVBVTitle);
console.debug(json);
}
backup.biliplus = { value: false, ts: getCurrentTs() };
spanB.style.color = '#ff0000';
}
}
async function getFromBiliplusExtra(AVBVTitle, backup, spanB, as, controller) {
if (getFromBiliplusExtraCounter > 350) {
as[1].textContent = `等待${getFromBiliplusExtraCounter - 350}秒 | ${AVBVTitle.title}`;
await new Promise((resolve, reject) => {
const timer = setInterval(() => {
if (controller.signal.aborted) {
clearInterval(timer);
reject(new DOMException('', 'AbortError'));
return;
}
if (getFromBiliplusExtraCounter <= 350) {
clearInterval(timer);
resolve();
return;
}
as[1].textContent = `等待${getFromBiliplusExtraCounter - 350}秒 | ${AVBVTitle.title}`;
}, 1000);
});
as[1].textContent = AVBVTitle.title;
}
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) {
getFromBiliplusExtraCounter = 372;
throw ['从BiliPlus获取额外数据的频率过快'];
}
getFromBiliplusExtraCounter += 12;
if (response2.response.code === 0) {
if (debug) {
console.log('从BiliPlus获取有效额外数据');
consoleAVBVTitle('debug', AVBVTitle);
console.debug(response2.response);
if (!backup.biliplus.value) {
addMessage('getFromBiliplusExtra 无法获取数据但可获取额外数据', false, 'red');
addMessage(AVBVTitle.BV, true);
console.warn('getFromBiliplusExtra 无法获取数据但可获取额外数据');
console.warn(AVBVTitle.BV);
}
}
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 (debug) {
// addMessage('getFromBiliplusExtra 无法获取额外数据', false, 'red');
// addMessage(AVBVTitle.BV, true);
// console.warn('getFromBiliplusExtra 无法获取额外数据');
// console.warn(AVBVTitle.BV);
// }
backup.biliplusExtra = { value: false, ts: getCurrentTs() };
spanB.style.color = '#800000';
} else {
if (debug) {
addMessage('getFromBiliplusExtra 未知错误', false, 'red');
addMessage(JSON.stringify(response2.response), true);
addMessage(AVBVTitle.BV, true);
console.warn('getFromBiliplusExtra 未知错误');
console.warn(response2.response);
console.warn(AVBVTitle.BV);
}
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 (debug) {
console.log('保存BiliPlus的额外数据至本地');
consoleAVBVTitle('debug', AVBVTitle);
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 (debug) 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 (debug) {
console.log('从唧唧获取有效数据');
consoleAVBVTitle('debug', AVBVTitle);
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.getFromJijidownExtra && (!backup.jijidownExtra || (settings.getFromJijidownExtraUpdate && getCurrentTs() - backup.jijidownExtra.ts > 3600 * 24 * 7 * settings.getFromJijidownExtraUpdateInterval))) {
await getFromJijidownExtra(AVBVTitle, backup, spanJ, response.response.ltime);
}
return;
} else if (response.response.msg === 'loading') {
retryCount++;
if (debug) {
console.log('从唧唧获取无效数据');
consoleAVBVTitle('debug', AVBVTitle);
console.log(`请求重试次数: ${retryCount}`);
console.debug(response.response);
}
if (retryCount > 4) {
throw ['请求重试次数过多', `${settings.getFromJijidownURL}/api/v1/video_bv/get_info`];
}
} else {
if (debug) {
console.log('从唧唧获取无效数据');
consoleAVBVTitle('debug', AVBVTitle);
console.debug(response.response);
}
backup.jijidown = { value: false, ts: getCurrentTs() };
if (settings.getFromJijidownExtra && (!backup.jijidownExtra || (settings.getFromJijidownExtraUpdate && getCurrentTs() - backup.jijidownExtra.ts > 3600 * 24 * 7 * settings.getFromJijidownExtraUpdateInterval))) {
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 (debug) 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 (debug) {
console.log('从唧唧获取有效额外数据');
consoleAVBVTitle('debug', AVBVTitle);
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 (debug) {
console.log('从唧唧获取无效额外数据');
consoleAVBVTitle('debug', AVBVTitle);
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 (debug) console.debug(response);
if (response.status !== 200) {
throw ['请求失败', `${settings.getFromXbeibeixURL}/video`, `${response.status} ${response.statusText}`];
}
if (response.finalUrl !== `https://${settings.getFromXbeibeixURL}/`) {
if (debug) {
console.log('从贝贝工具站获取有效数据');
consoleAVBVTitle('debug', AVBVTitle);
console.debug(response);
}
if (!response.responseXML) {
throw ['请您使用版本为 5.3.0 及以上的 <a href="https://www.tampermonkey.net/" target="_blank" style="text-decoration-line: underline;">Tampermonkey</a> 运行此脚本'];
}
updateArrayDataInBackup(backup, 'title', response.responseXML.querySelector('h5.fw-bold').innerText, undefined, `${settings.getFromXbeibeixURL}/video`);
if (response.responseXML.querySelector('div.col-8 > textarea').value) {
updateArrayDataInBackup(backup, 'intro', decodeHTMLEntities(response.responseXML.querySelector('div.col-8 > textarea').value), 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 (debug) {
console.log('从贝贝工具站获取无效数据');
consoleAVBVTitle('debug', AVBVTitle);
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 === 'red') {
p.style.borderTop = '1px solid #800000';
} else if (border === 'green') {
p.style.borderTop = '1px solid #008000';
}
divMessage.appendChild(p);
if (divMessageHeightFixed) {
divMessage.scrollTop = divMessage.scrollHeight;
} else {
if (newFreshSpace) {
if (divMessage.scrollHeight > 320) {
divMessage.classList.add('backup-divMessage-heightFixed-newFreshSpace');
divMessageHeightFixed = true;
divMessage.scrollTop = divMessage.scrollHeight;
}
} else {
if (divMessage.scrollHeight > 280) {
divMessage.classList.add('backup-divMessage-heightFixed');
divMessageHeightFixed = true;
divMessage.scrollTop = divMessage.scrollHeight;
}
}
}
divMessage.scrollIntoView({ behavior: 'instant', block: 'nearest' });
}
function clearMessage() {
while (divMessage.firstChild) {
divMessage.removeChild(divMessage.firstChild);
}
divMessage.classList.remove('backup-divMessage-heightFixed' + classAppendNewFreshSpace);
divMessageHeightFixed = false;
}
function addMessageAVBVTitle(AVBVTitle) {
addMessage(`AV号: ${AVBVTitle.AV}`, true);
addMessage(`BV号: ${AVBVTitle.BV}`, true);
if (AVBVTitle.title) {
addMessage(`标题: ${AVBVTitle.title.slice(0, 13)}`, true);
}
}
function consoleAVBVTitle(type, AVBVTitle) {
switch (type) {
case 'debug':
console.debug(`AV号: ${AVBVTitle.AV}`);
console.debug(`BV号: ${AVBVTitle.BV}`);
console.debug(`标题: ${AVBVTitle.title.slice(0, 13)}`);
break;
case 'log':
console.log(`AV号: ${AVBVTitle.AV}`);
console.log(`BV号: ${AVBVTitle.BV}`);
console.log(`标题: ${AVBVTitle.title.slice(0, 13)}`);
break;
case 'warn':
console.warn(`AV号: ${AVBVTitle.AV}`);
console.warn(`BV号: ${AVBVTitle.BV}`);
console.warn(`标题: ${AVBVTitle.title.slice(0, 13)}`);
break;
case 'error':
console.error(`AV号: ${AVBVTitle.AV}`);
console.error(`BV号: ${AVBVTitle.BV}`);
if (AVBVTitle.title) {
console.error(`标题: ${AVBVTitle.title.slice(0, 13)}`);
}
break;
default:
throw Error('invalid type');
}
}
function catchUnknownError(error) {
addMessage('发生未知错误, 请反馈该问题', false, 'red');
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') || from.includes('beibeigame')) && 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);
return true;
} 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 (debug) {
addMessage('updatePagesInBackup firstFrame 不一致', false, 'red');
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;
}
});
return true;
}
}
}
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 (debug) {
console.log(`keyword: ${decodeURIComponent(keyword)}`);
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 (debug) 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 (debug) console.log(`typeText: ${typeText}`);
let type;
if (typeText.includes('当前')) {
type = 0;
} else if (typeText.includes('全部')) {
type = 1;
} else {
throw ['无法确定搜索的范围为当前收藏夹还是全部收藏夹, 请反馈该问题'];
}
if (debug) 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 (debug) 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'])
});
});
if (response.status !== 200) {
throw ['请求失败', 'api.bilibili.com/x/v3/fav/resource/partition', `${response.status} ${response.statusText}`];
}
const target = response.response.data.find(el => tidText.includes(el.name));
if (target) {
tid = target.tid;
} else {
throw ['无法确定选择的分区, 请反馈该问题'];
}
}
if (debug) console.log(`tid: ${tid}`);
if (debug) 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);
}
}
})();