diff --git a/bilibili-evolved.offline.user.js b/bilibili-evolved.offline.user.js index 314073593..6e322ba19 100644 --- a/bilibili-evolved.offline.user.js +++ b/bilibili-evolved.offline.user.js @@ -1,1241 +1,1242 @@ -// ==UserScript== -// @name Bilibili Evolved (Offline) -// @version 672.00 -// @description Bilibili Evolved 的离线版, 所有功能都已内置于脚本中. -// @author Grant Howard, Coulomb-G -// @copyright 2020, Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G) -// @license MIT -// @match *://*.bilibili.com/* -// @exclude *://api.bilibili.com/* -// @exclude *://*.bilibili.com/api/* -// @exclude *://member.bilibili.com/studio/bs-editor/* -// @run-at document-start -// @updateURL https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.offline.user.js -// @downloadURL https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.offline.user.js -// @supportURL https://github.com/the1812/Bilibili-Evolved/issues -// @homepage https://github.com/the1812/Bilibili-Evolved -// @grant unsafeWindow -// @grant GM_getValue -// @grant GM_setValue -// @grant GM_setClipboard -// @grant GM_info -// @grant GM_xmlhttpRequest -// @grant GM.getValue -// @grant GM.setValue -// @grant GM.setClipboard -// @grant GM.info -// @grant GM.xmlHttpRequest -// @connect raw.githubusercontent.com -// @connect cdn.jsdelivr.net -// @connect cn.bing.com -// @connect www.bing.com -// @connect translate.google.cn -// @connect translate.google.com -// @connect * -// @require https://cdn.jsdelivr.net/npm/jquery@3.4.0/dist/jquery.min.js -// @require https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js -// @require https://cdn.jsdelivr.net/npm/jszip@3.1.5/dist/jszip.min.js -// @require https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js -// @require https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.js -// @icon https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/images/logo-small.png -// @icon64 https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/images/logo.png +// ==UserScript== +// @name Bilibili Evolved (Offline) +// @version 672.06 +// @description Bilibili Evolved 的离线版, 所有功能都已内置于脚本中. +// @author Grant Howard, Coulomb-G +// @copyright 2020, Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G) +// @license MIT +// @match *://*.bilibili.com/* +// @exclude *://api.bilibili.com/* +// @exclude *://*.bilibili.com/api/* +// @exclude *://member.bilibili.com/studio/bs-editor/* +// @run-at document-start +// @updateURL https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.offline.user.js +// @downloadURL https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.offline.user.js +// @supportURL https://github.com/the1812/Bilibili-Evolved/issues +// @homepage https://github.com/the1812/Bilibili-Evolved +// @grant unsafeWindow +// @grant GM_getValue +// @grant GM_setValue +// @grant GM_setClipboard +// @grant GM_info +// @grant GM_xmlhttpRequest +// @grant GM.getValue +// @grant GM.setValue +// @grant GM.setClipboard +// @grant GM.info +// @grant GM.xmlHttpRequest +// @connect raw.githubusercontent.com +// @connect cdn.jsdelivr.net +// @connect cn.bing.com +// @connect www.bing.com +// @connect translate.google.cn +// @connect translate.google.com +// @connect * +// @require https://cdn.jsdelivr.net/npm/jquery@3.4.0/dist/jquery.min.js +// @require https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js +// @require https://cdn.jsdelivr.net/npm/jszip@3.1.5/dist/jszip.min.js +// @require https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js +// @require https://cdn.jsdelivr.net/npm/vuex@3.1.2/dist/vuex.js +// @icon https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/images/logo-small.png +// @icon64 https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/images/logo.png // ==/UserScript== -/* eslint-disable */ /* spell-checker: disable */ -Vue.config.productionTip = false -Vue.config.devtools = false -// if (unsafeWindow.Vue === undefined) { -// unsafeWindow.Vue = Vue -// } - -// GM4 polyfill start -if (typeof GM == 'undefined') { - this.GM = {} -} -Object.entries({ - 'log': console.log.bind(console), - 'info': GM_info, -}).forEach(([newKey, old]) => { - if (old && (typeof GM[newKey] == 'undefined')) { - GM[newKey] = old - } -}) -Object.entries({ - 'GM_getValue': 'getValue', - 'GM_setClipboard': 'setClipboard', - 'GM_setValue': 'setValue', - 'GM_xmlhttpRequest': 'xmlHttpRequest', -}).forEach(([oldKey, newKey]) => { - let old = this[oldKey] - if (old && (typeof GM[newKey] == 'undefined')) { - GM[newKey] = function (...args) { - return new Promise((resolve, reject) => { - try { - resolve(old.apply(this, args)) - } catch (e) { - reject(e) - } - }) - } - } -}) -// GM4 polyfill end - -// Safari EventTarget polyfill -window.EventTarget = class EventTarget { - constructor() { - this.listeners = {} - } - addEventListener(type, callback) { - if (!(type in this.listeners)) { - this.listeners[type] = [] - } - this.listeners[type].push(callback) - } - removeEventListener(type, callback) { - if (!(type in this.listeners)) { - return - } - let stack = this.listeners[type] - for (let i = 0, l = stack.length; i < l; i++) { - if (stack[i] === callback) { - stack.splice(i, 1) - return - } - } - } - dispatchEvent(event) { - if (!(event.type in this.listeners)) { - return true - } - let stack = this.listeners[event.type].slice() - for (let i = 0, l = stack.length; i < l; i++) { - stack[i].call(this, event) - } - return !event.defaultPrevented - } -} -// Safari EventTarget polyfill end - -function logError (error) { - let finalMessage = error - if (typeof error === 'object' && 'stack' in error) { - if (settings.toastInternalError) { - finalMessage = `${error.message}\n${error.stack}` - } else { - finalMessage = error.message - } - } - Toast.error(finalMessage, '错误') - console.error(error) -} -function raiseEvent (element, eventName) { - const event = document.createEvent('HTMLEvents') - event.initEvent(eventName, true, true) - element.dispatchEvent(event) -} -async function loadLazyPanel (selector) { - await SpinQuery.unsafeJquery() - const panel = await SpinQuery.any(() => unsafeWindow.$(selector)) - if (!panel) { - throw new Error(`Panel not found: ${selector}`) - } - panel.mouseover() - // 懒加载面板带有 300ms 的 denounce - return new Promise(resolve => { - setTimeout(() => { - panel.mouseout() - resolve() - }, 310) - }) -} -async function loadLazyPlayerSettingsPanel (buttonSelector, panelSelector) { - // 暂时隐藏面板 - const style = document.createElement('style') - style.innerText = `${panelSelector} { display: none !important; }` - document.body.insertAdjacentElement('beforeend', style) - await loadLazyPanel(buttonSelector) - // 有些面板有 300ms 的 transition delay - setTimeout(() => style.remove(), 300) - return dq(panelSelector) -} -async function loadDanmakuSettingsPanel () { - return await loadLazyPlayerSettingsPanel('.bilibili-player-video-danmaku-setting', '.bilibili-player-video-danmaku-setting-wrap') -} -async function loadSubtitleSettingsPanel () { - return await loadLazyPlayerSettingsPanel('.bilibili-player-video-btn-subtitle', '.bilibili-player-video-subtitle-setting-wrap') -} -function contentLoaded (callback) { - if (/complete|interactive|loaded/.test(document.readyState)) { - callback() - } else { - document.addEventListener('DOMContentLoaded', () => callback()) - } -} -function fullyLoaded (callback) { - if (document.readyState === 'complete') { - callback() - } else { - unsafeWindow.addEventListener('load', () => callback()) - } -} -function fixed (number, precision = 1) { - const str = number.toString() - const index = str.indexOf('.') - if (index !== -1) { - if (str.length - index > precision + 1) { - return str.substring(0, index + precision + 1) - } else { - return str - } - } else { - return str + '.0' - } -} -function isEmbeddedPlayer () { - return location.host === 'player.bilibili.com' || document.URL.startsWith('https://www.bilibili.com/html/player.html') -} -function isIframe () { - return document.body && unsafeWindow.parent.window !== unsafeWindow -} -const languageNameToCode = { - '日本語': 'ja-JP', - 'English': 'en-US', - 'Deutsch': 'de-DE' -} -const languageCodeToName = { - 'ja-JP': '日本語', - 'en-US': 'English', - 'de-DE': 'Deutsch' -} -function getI18nKey () { - return settings.i18n ? languageNameToCode[settings.i18nLanguage] : 'zh-CN' -} -const dq = (selector, scopedSelector) => { - if (!scopedSelector) { - return document.querySelector(selector) - } - return selector.querySelector(scopedSelector) -} -const dqa = (selector, scopedSelector) => { - if (!scopedSelector) { - return [...document.querySelectorAll(selector)] - } - return [...selector.querySelectorAll(scopedSelector)] -} -const UserAgent = `Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0` -const EmptyImageUrl = 'data:image/svg+xml;utf-8,' -const ascendingSort = (itemProp) => { - return (a, b) => itemProp(a) - itemProp(b) -} -const descendingSort = (itemProp) => { - return (a, b) => itemProp(b) - itemProp(a) -} -const formatFileSize = (bytes, fixed = 1) => { - const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] - let number = bytes - let unitIndex = 0 - while (number >= 1024) { - number /= 1024 - unitIndex++ - } - return `${Math.round(number * (10 ** fixed)) / (10 ** fixed)}${units[unitIndex]}` -} -const formatDuration = (time, fixed = 0) => { - const second = (time % 60).toFixed(fixed) - const minute = (Math.trunc(time / 60) % 60).toString() - const hour = Math.trunc(time / 3600).toString() - if (hour === '0') { - return `${minute.padStart(2, '0')}:${second.padStart(2, '0')}` - } - return `${hour}:${minute.padStart(2, '0')}:${second.padStart(2, '0')}` -} -const getDpiSourceSet = (src, baseSize, extension = 'jpg') => { - const dpis = [1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4] - if (extension.startsWith('.')) { - extension = extension.substring(1) - } - return dpis.map(dpi => { - if (typeof baseSize === 'object') { - if ('width' in baseSize && 'height' in baseSize) { - return `${src}@${Math.trunc(baseSize.width * dpi)}w_${Math.trunc(baseSize.height * dpi)}h.${extension} ${dpi}x` - } else if ('width' in baseSize) { - return `${src}@${Math.trunc(baseSize.width * dpi)}w.${extension} ${dpi}x` - } else if ('height' in baseSize) { - return `${src}@${Math.trunc(baseSize.height * dpi)}h.${extension} ${dpi}x` - } - } else { - return `${src}@${Math.trunc(baseSize * dpi)}w_${Math.trunc(baseSize * dpi)}h.${extension} ${dpi}x` - } - }).join(",") -} -const isOffline = () => typeof offlineData !== 'undefined' -const getUID = () => document.cookie.replace(/(?:(?:^|.*;\s*)DedeUserID\s*\=\s*([^;]*).*$)|^.*$/, '$1') -const scriptVersion = (() => { - const match = GM.info.script.name.match(/Evolved \((.*)\)/) - return match ? match[1] : 'Stable' -})() -const getCsrf = () => document.cookie.replace(/(?:(?:^|.*;\s*)bili_jct\s*\=\s*([^;]*).*$)|^.*$/, '$1') -const formatCount = (count) => { - if (typeof count === 'string') { - count = parseInt(count) - } - if (count > 100000000) { - return Math.round(count / 10000000) / 10 + '亿' - } - if (count > 10000) { - return Math.round(count / 1000) / 10 + '万' - } - return count + '' -} -const escapeFilename = (filename, replacement = '') => { - return filename.replace(/[\/\\:\*\?"<>\|]/g, replacement) -} -function html (strings, ...values) { - return [...strings].reduce((previous, current, index) => { - const value = values[index] - return previous + current + (value === undefined ? '' : value) - }, '') -} -const dashExtensions = ['.mp4', '.m4a'] -const dashFragmentExtension = 'm4s' -const videoCondition = async () => { - let cid = await SpinQuery.select(() => (unsafeWindow || window).cid) - return Boolean(cid) -} -const matchPattern = (str, pattern) => { - if (typeof pattern === 'string') { - return str.includes(pattern) - } - return pattern.test(str) -} -const customNavbarDefaultOrders = { - blank1: 0, - logo: 1, - category: 2, - rankingLink: 3, - drawingLink: 4, - musicLink: 5, - gamesIframe: 6, - livesIframe: 7, - shopLink: 8, - mangaLink: 9, - blank2: 10, - search: 11, - blank3: 12, - userInfo: 13, - messages: 14, - activities: 15, - bangumi: 16, - watchlaterList: 17, - favoritesList: 18, - historyList: 19, - upload: 20, - darkMode: 21, -} -const simpleHomeCategoryDefaultOrders = { - anime: 0, - bangumi: 1, - china: 2, - manga: 3, - music: 4, - dance: 5, - game: 6, - tech: 7, - digital: 8, - life: 9, - kichiku: 10, - fashion: 11, - information: 12, - entertainment: 13, - column: 14, - movie: 15, - tv: 16, - film: 17, - documentary: 18, -} -const aria2RpcDefaultOption = { - secretKey: '', - dir: '', - host: '127.0.0.1', - port: '6800', - method: 'get', - skipByDefault: false, - maxDownloadLimit: '', - baseDir: '', -} -const settings = { - useDarkStyle: false, - // showBanner: true, - hideBanner: false, - expandDanmakuList: true, - expandDescription: true, - watchLaterRedirect: true, - touchNavBar: false, - touchVideoPlayer: false, - customControlBackgroundOpacity: 0.64, - customControlBackground: false, - darkScheduleStart: '18:00', - darkScheduleEnd: '6:00', - darkSchedule: false, - toast: true, - fullTweetsTitle: true, - fullPageTitle: false, - removeVideoTopMask: false, - removeLiveWatermark: true, - harunaScale: true, - removeAds: true, - showBlockedAdsTip: false, - hideTopSearch: false, - touchVideoPlayerDoubleTapControl: false, - customStyleColor: '#00A0D8', - preserveRank: true, - blurBackgroundOpacity: 0.382, - useDefaultPlayerMode: false, - applyPlayerModeOnPlay: true, - defaultPlayerMode: '常规', - useDefaultVideoQuality: false, - defaultVideoQuality: '自动', - useDefaultDanmakuSettings: false, - enableDanmaku: true, - rememberDanmakuSettings: false, - danmakuSettings: { - subtitlesPreserve: false, - smartMask: false, - }, - defaultPlayerLayout: '新版', - defaultBangumiLayout: '新版', - skipChargeList: false, - comboLike: false, - autoLightOff: false, - useCache: true, - autoContinue: false, - allowJumpContinue: false, - deadVideoTitleProvider: '稍后再看', - useBiliplusRedirect: false, - biliplusRedirect: false, - framePlayback: true, - useCommentStyle: true, - imageResolution: false, - imageResolutionScale: 'auto', - toastInternalError: false, - i18n: false, - i18nLanguage: '日本語', - playerFocus: false, - playerFocusOffset: -10, - simplifyLiveroom: false, - simplifyLiveroomSettings: { - vip: true, - fansMedal: true, - title: true, - userLevel: true, - guard: true, - systemMessage: true, - welcomeMessage: true, - giftMessage: true, - guardPurchase: true, - giftPanel: true, - kanban: true, - userEffect: true, - eventsBanner: false, - rankList: false, - popup: false, - skin: false, - }, - customNavbar: true, - customNavbarFill: false, - customNavbarTransparent: true, - customNavbarShadow: true, - customNavbarBlur: false, - customNavbarBlurOpacity: 0.7, - customNavbarOrder: { ...customNavbarDefaultOrders }, - customNavbarHidden: ['blank1', 'drawingLink', 'musicLink', 'gamesIframe', 'darkMode'], - customNavbarBoundsPadding: 10, - playerShadow: false, - narrowDanmaku: true, - outerWatchlater: true, - videoScreenshot: false, - hideBangumiReviews: false, - filenameFormat: '[title][ - ep]', - batchFilenameFormat: '[n - ][ep]', - sideBarOffset: 0, - noLiveAutoplay: false, - hideHomeLive: false, - noMiniVideoAutoplay: false, - useDefaultVideoSpeed: false, - defaultVideoSpeed: '1.0', - hideCategory: false, - foldComment: true, - downloadVideoDefaultDanmaku: '无', - downloadVideoDefaultSubtitle: '无', - aria2RpcOption: { ...aria2RpcDefaultOption }, - aria2RpcOptionSelectedProfile: '', - aria2RpcOptionProfiles: [], - searchHistory: [], - seedsToCoins: true, - autoSeedsToCoins: true, - lastSeedsToCoinsDate: 0, - autoDraw: false, - keymap: false, - doubleClickFullscreen: false, - doubleClickFullscreenPreventSingleClick: false, - simplifyHome: false, - simplifyHomeStyle: '清爽', - minimalHomeSettings: { - showSearch: true, - backgroundImage: '', - }, - ajaxHook: false, - scriptLoadingMode: '延后(自动)', - scriptDownloadMode: 'bundle', - guiSettingsDockSide: '左侧', - fullActivityContent: true, - feedsFilter: false, - feedsFilterPatterns: [], - feedsFilterTypes: [], - feedsFilterSideCards: [], - activityImageSaver: false, - scriptBlockPatterns: [], - customNavbarSeasonLogo: false, - selectableColumnText: true, - downloadVideoFormat: 'flv', - downloadVideoDashCodec: 'AVC/H.264', - watchlaterExpireWarningDays: 14, - superchatTranslate: false, - miniPlayerTouchMove: false, - hideBangumiSponsors: false, - hideRecommendLive: false, - hideRelatedVideos: false, - defaultMedalID: 0, - autoMatchMedal: false, - customStyles: [], - simpleHomeCategoryOrders: { ...simpleHomeCategoryDefaultOrders }, - simpleHomeBangumiLayout: '时间表', - keymapJumpSeconds: 85, - urlParamsClean: true, - collapseLiveSideBar: true, - removeGameMatchModule: false, - noDarkOnMember: true, - feedsTranslate: false, - feedsTranslateProvider: 'Bing', - feedsTranslateLanguage: '', - downloadVideoQuality: 120, - defaultLiveQuality: '原画', - useDefaultLiveQuality: false, - recordLiveDanmaku: false, - foregroundColorMode: '自动', - preserveEventBanner: false, - about: true, - bvidConvert: true, - fixedSidebars: false, - updateCdn: 'jsDelivr', - lastNewVersionCheck: 0, - newVersionCheckInterval: 1000 * 3600 * 6, // 6 hours - useDarkStyleAsUserStyle: false, - darkColorScheme: false, - autoHideSideBar: false, - livePip: true, - extendFeedsLive: true, - userImages: [], - playerOnTop: false, - restoreFloors: false, - quickFavorite: false, - quickFavoriteID: 0, - bilibiliSimpleNewHomeCompatible: false, - preferAvUrl: false, - elegantScrollbar: true, - cache: {}, -} -const fixedSettings = { - autoPlay: false, - favoritesRedirect: false, - compactLayout: false, - hideOldEntry: false, - guiSettings: true, - viewCover: true, - notifyNewVersion: true, - clearCache: true, - downloadVideo: true, - enableDashDownload: true, - downloadDanmaku: true, - downloadSubtitle: true, - downloadAudio: true, - downloadLiveRecords: true, - medalHelper: true, - playerLayout: false, - forceWide: false, - useNewStyle: false, - overrideNavBar: false, - touchVideoPlayerAnimation: false, - allNavbarFill: false, - showDeadVideoTitle: false, - blurVideoControl: false, - oldTweets: false, - customNavbarCompact: false, - watchlaterExpireWarnings: false, - latestVersionLink: 'https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.offline.user.js', - currentVersion: GM.info.script.version, -} -const settingsChangeHandlers = {} -function addSettingsListener (key, handler, initCall) { - if (!settingsChangeHandlers[key]) { - settingsChangeHandlers[key] = [handler] - } else { - settingsChangeHandlers[key].push(handler) - } - if (initCall) { - const value = settings[key] - handler(value, value) - } -} -function removeSettingsListener (key, handler) { - const handlers = settingsChangeHandlers[key] - if (!handlers) { - return - } - handlers.splice(handlers.indexOf(handler), 1) -} -async function loadSettings () { - for (const key in fixedSettings) { - settings[key] = fixedSettings[key] - await GM.setValue(key, fixedSettings[key]) - } - if (Object.keys(languageCodeToName).includes(navigator.language)) { - settings.i18n = true - settings.i18nLanguage = languageCodeToName[navigator.language] - } - for (const key in settings) { - let value = await GM.getValue(key) - if (key === 'batchFilenameFormat' && value === '[n - ][title]') { - value = '[n - ][ep]' - GM.setValue(key, value) - } - if (value === undefined) { - value = settings[key] - GM.setValue(key, settings[key]) - } else if (settings[key] !== undefined && value.constructor === Object) { - value = Object.assign(settings[key], value) - } - Object.defineProperty(settings, key, { - get () { - return value - }, - set (newValue) { - value = newValue - GM.setValue(key, newValue) - - const handlers = settingsChangeHandlers[key] - if (handlers) { - if (key === 'useDarkStyle') { - setTimeout(() => handlers.forEach(h => h(newValue, value)), 200) - } else { - handlers.forEach(h => h(newValue, value)) - } - } - const input = document.querySelector(`input[key=${key}]`) - if (input !== null) { - if (input.type === 'checkbox') { - input.checked = newValue - } else if (input.type === 'text' && !input.parentElement.classList.contains('gui-settings-dropdown')) { - input.value = newValue - } - } - } - }) - } -} - -class Ajax { - static send (xhr, body, text = true) { - return new Promise((resolve, reject) => { - xhr.addEventListener('load', () => { - // if (xhr.status.toString().match(/^[45]/)) { - // reject(xhr.status) - // } else { - resolve(text ? xhr.responseText : xhr.response) - // } - }) - xhr.addEventListener('error', () => reject(xhr.status)) - xhr.send(body) - }) - } - static getBlob (url) { - const xhr = new XMLHttpRequest() - xhr.responseType = 'blob' - xhr.open('GET', url) - return this.send(xhr, undefined, false) - } - static getBlobWithCredentials (url) { - const xhr = new XMLHttpRequest() - xhr.responseType = 'blob' - xhr.open('GET', url) - xhr.withCredentials = true - return this.send(xhr, undefined, false) - } - static async getJson (url) { - return JSON.parse(await this.getText(url)) - } - static async getJsonWithCredentials (url) { - return JSON.parse(await this.getTextWithCredentials(url)) - } - static getText (url) { - const xhr = new XMLHttpRequest() - xhr.open('GET', url) - return this.send(xhr) - } - static getTextWithCredentials (url) { - const xhr = new XMLHttpRequest() - xhr.open('GET', url) - xhr.withCredentials = true - return this.send(xhr) - } - static postText (url, body) { - const xhr = new XMLHttpRequest() - xhr.open('POST', url) - xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') - return this.send(xhr, body) - } - static postTextWithCredentials (url, body) { - const xhr = new XMLHttpRequest() - xhr.open('POST', url) - xhr.withCredentials = true - xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') - return this.send(xhr, body) - } - static postJson (url, json) { - const xhr = new XMLHttpRequest() - xhr.open('POST', url) - xhr.setRequestHeader('Content-Type', 'application/json') - return this.send(xhr, JSON.stringify(json), false) - } - static postJsonWithCredentials (url, json) { - const xhr = new XMLHttpRequest() - xhr.open('POST', url) - xhr.withCredentials = true - xhr.setRequestHeader('Content-Type', 'application/json') - return this.send(xhr, JSON.stringify(json), false) - } - static getHandlers (name) { - name = name.toLowerCase() - let handlers = Ajax[name] - if (handlers === undefined) { - handlers = Ajax[name] = [] - } - return handlers - } - static addEventListener (type, handler) { - const handlers = Ajax.getHandlers(type) - handlers.push(handler) - } - static removeEventListener (type, handler) { - const handlers = Ajax.getHandlers(type) - handlers.splice(handlers.indexOf(handler), 1) - } - static monkey (details) { - return new Promise((resolve, reject) => { - const fullDetails = { - ...details, - onload: r => resolve(r.response), - onerror: r => reject(r), - } - if (!('method' in fullDetails)) { - fullDetails.method = 'GET' - } - GM.xmlHttpRequest(fullDetails) - }) - } - static async getPages({api, getList, getTotal}) { - let page = 1 - let total = Infinity - const result = [] - while (result.length < total) { - const json = await api(page) - if (json.code !== 0) { - console.warn(`api failed in Ajax.getPages. message = ${json.message}, page = ${page}, total = ${total}, api = `, api) - } - const list = getList(json) - result.push(...list) - if (total === Infinity) { - total = getTotal(json) - } - } - return result - } -} -// https://github.com/the1812/Bilibili-Evolved/issues/84 -let ajaxHooked = false -function setupAjaxHook () { - if (ajaxHooked) { - return - } - ajaxHooked = true - const original = { - open: XMLHttpRequest.prototype.open, - send: XMLHttpRequest.prototype.send - } - const fireHandlers = (name, thisArg, ...args) => Ajax.getHandlers(name).forEach(it => it.call(thisArg, ...args)) - const hook = (name, thisArgs, ...args) => { - fireHandlers('before' + name, thisArgs, ...args) - const returnValue = original[name].call(thisArgs, ...args) - fireHandlers('after' + name, thisArgs, ...args) - return returnValue - } - const hookOnEvent = (name, thisArg) => { - if (thisArg[name]) { - const originalHandler = thisArg[name] - thisArg[name] = (...args) => { - fireHandlers('before' + name, thisArg, ...args) - originalHandler.apply(thisArg, args) - fireHandlers('after' + name, thisArg, ...args) - } - } else { - thisArg[name] = (...args) => { - fireHandlers('before' + name, thisArg, ...args) - fireHandlers('after' + name, thisArg, ...args) - } - } - } - XMLHttpRequest.prototype.open = function (...args) { return hook('open', this, ...args) } - XMLHttpRequest.prototype.send = function (...args) { - hookOnEvent('onreadystatechange', this) - hookOnEvent('onload', this) - return hook('send', this, ...args) - } -} - -async function loadResources () { - Resource.root = 'https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/' - switch (await GM.getValue('updateCdn')) { - case 'jsDelivr': - default: - Resource.cdnRoot = 'https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/' - break - case 'GitHub': - Resource.cdnRoot = Resource.root - break - } - Resource.all = {} - Resource.displayNames = {} - Resource.reloadables = [] - for (const [key, data] of Object.entries(Resource.manifest)) { - const resource = new Resource(data.path, { styles: data.styles, alwaysPreview: data.alwaysPreview }) - resource.key = key - resource.dropdown = data.dropdown - if (data.reloadable) { - Resource.reloadables.push(key) - } - if (data.displayNames) { - resource.displayName = data.displayNames[key] - Object.assign(Resource.displayNames, data.displayNames) - } - if (data.style) { - const styleKey = key + 'Style' - const style = Resource.all[styleKey] = new Resource(data.path.replace('.js', '.css'), { alwaysPreview: data.alwaysPreview }) - style.key = styleKey - switch (data.style) { - case 'instant': - { - resource.styles.push(styleKey) - break - } - case true: - { - resource.dependencies.push(style) - break - } - case 'important': - { - resource.styles.push({ - key: styleKey, - important: true - }) - break - } - default: - { - if (typeof data.style === 'object') { - resource.styles.push(Object.assign({ key: styleKey }, data.style)) - } - break - } - } - } - if (data.html === true) { - const htmlKey = key + 'Html' - const html = Resource.all[htmlKey] = new Resource(data.path.replace('.js', '.html'), { alwaysPreview: data.alwaysPreview }) - html.key = htmlKey - resource.dependencies.push(html) - } - Resource.all[key] = resource - } - for (const [key, data] of Object.entries(Resource.manifest)) { - if (data.dependencies) { - Resource.all[key].dependencies.push(...data.dependencies.map(name => Resource.all[name])) - } - } -} - -// Placeholder class for Toast -class Toast { - show () { } - dismiss () { } - static show () { } - static info () { } - static success () { } - static error () { } -} - -class DoubleClickEvent { - constructor (handler, singleClickHandler = null) { - this.handler = handler - this.singleClickHandler = singleClickHandler - this.elements = [] - this.clickedOnce = false - this.doubleClickHandler = e => { - if (!this.clickedOnce) { - this.clickedOnce = true - setTimeout(() => { - if (this.clickedOnce) { - this.clickedOnce = false - this.singleClickHandler && this.singleClickHandler(e) - } - }, 200) - } else { - this.clickedOnce = false - this.handler && this.handler(e) - } - } - } - bind (element) { - if (this.elements.indexOf(element) === -1) { - this.elements.push(element) - element.addEventListener('click', this.doubleClickHandler) - } - } - unbind (element) { - const index = this.elements.indexOf(element) - if (index === -1) { - return - } - this.elements.splice(index, 1) - element.removeEventListener('click', this.doubleClickHandler) - } -} - -let cidHooked = false -const videoChangeCallbacks = [] -class Observer { - constructor (elements, callback) { - this.elements = elements || [] - this.callback = callback - this.observer = null - this.options = undefined - } - start () { - this.elements.forEach(element => { - this.observer = new MutationObserver(this.callback) - this.observer.observe(element, this.options) - }) - return this - } - add (element) { - this.elements.push(element) - this.observer.observe(element, this.options) - return this - } - stop () { - this.observer && this.observer.disconnect() - return this - } - // 向后兼容的接口, 实际并没有什么遍历 - forEach (callback) { - callback(this) - } - static observe (selector, callback, options) { - callback([]) - let elements = selector - if (typeof selector === 'string') { - elements = [...document.querySelectorAll(selector)] - } else if (!Array.isArray(selector)) { - elements = [selector] - } - const observer = new Observer(elements, callback) - observer.options = options - return observer.start() - } - static childList (selector, callback) { - return Observer.observe(selector, callback, { - childList: true, - subtree: false, - attributes: false - }) - } - static childListSubtree (selector, callback) { - return Observer.observe(selector, callback, { - childList: true, - subtree: true, - attributes: false - }) - } - static attributes (selector, callback) { - return Observer.observe(selector, callback, { - childList: false, - subtree: false, - attributes: true - }) - } - static attributesSubtree (selector, callback) { - return Observer.observe(selector, callback, { - childList: false, - subtree: true, - attributes: true - }) - } - static all (selector, callback) { - return Observer.observe(selector, callback, { - childList: true, - subtree: true, - attributes: true - }) - } - static async videoChange (callback) { - const cid = await SpinQuery.select(() => unsafeWindow.cid) - if (cid === null) { - return - } - if (!cidHooked) { - let hookedCid = cid - Object.defineProperty(unsafeWindow, 'cid', { - get () { - return hookedCid - }, - set (newId) { - hookedCid = newId - if (!Array.isArray(newId)) { - videoChangeCallbacks.forEach(it => it()) - } - } - }) - cidHooked = true - } - // callback(); - const videoContainer = await SpinQuery.select('#bofqi video') - if (videoContainer) { - Observer.childList(videoContainer, callback) - } else { - callback() - } - videoChangeCallbacks.push(callback) - } -} - -class SpinQuery { - constructor (query, condition, action, failed) { - this.maxRetry = 15 - this.retry = 0 - this.queryInterval = 1000 - this.query = query - this.condition = condition - this.action = action - this.failed = failed - } - start () { - this.tryQuery(this.query, this.condition, this.action, this.failed) - } - tryQuery (query, condition, action, failed) { - if (this.retry < this.maxRetry) { - const result = query() - if (condition(result)) { - action(result) - } else { - if (document.hasFocus()) { - this.retry++ - } - setTimeout(() => this.tryQuery(query, condition, action, failed), this.queryInterval) - } - } else { - typeof failed === 'function' && failed() - } - } - static condition (query, condition, action, failed) { - if (action !== undefined) { - new SpinQuery(query, condition, action, failed).start() - } else { - return new Promise((resolve) => { - new SpinQuery(query, condition, it => resolve(it), () => resolve(null)).start() - }) - } - } - static select (query, action, failed) { - if (typeof query === 'string') { - const selector = query - query = () => document.querySelector(selector) - } - return SpinQuery.condition(query, it => it !== null && it !== undefined, action, failed) - } - static any (query, action, failed) { - if (typeof query === 'string') { - const selector = query - query = () => $(selector) - } - return SpinQuery.condition(query, it => it.length > 0, action, failed) - } - static count (query, count, action, failed) { - if (typeof query === 'string') { - const selector = query - query = () => document.querySelectorAll(selector) - } - return SpinQuery.condition(query, it => it.length === count, action, failed) - } - static unsafeJquery (action, failed) { - return SpinQuery.condition(() => unsafeWindow.$, jquery => jquery !== undefined, action, failed) - } -} - -class ColorProcessor { - constructor (hex) { - this.hex = hex - } - get rgb () { - return this.hexToRgb(this.hex) - } - get rgba () { - return this.hexToRgba(this.hex) - } - getHexRegex (alpha, shorthand) { - const repeat = shorthand ? '' : '{2}' - const part = `([a-f\\d]${repeat})` - const count = alpha ? 4 : 3 - const pattern = `#?${part.repeat(count)}` - return new RegExp(pattern, 'ig') - } - hexToRgbOrRgba (hex, alpha) { - const isShortHand = hex.length < 6 - if (isShortHand) { - const shorthandRegex = this.getHexRegex(alpha, true) - hex = hex.replace(shorthandRegex, function (...args) { - let result = '' - let i = 1 - while (args[i]) { - result += args[i].repeat(2) - i++ - } - return result - }) - } - - const regex = this.getHexRegex(alpha, false) - const regexResult = regex.exec(hex) - if (regexResult) { - const color = { - r: parseInt(regexResult[1], 16), - g: parseInt(regexResult[2], 16), - b: parseInt(regexResult[3], 16) - } - if (regexResult[4]) { - color.a = parseInt(regexResult[4], 16) / 255 - } - return color - } else if (alpha) { - const rgb = this.hexToRgbOrRgba(hex, false) - if (rgb) { - rgb.a = 1 - return rgb - } - } - return null - } - hexToRgb (hex) { - return this.hexToRgbOrRgba(hex, false) - } - hexToRgba (hex) { - return this.hexToRgbOrRgba(hex, true) - } - rgbToString (color) { - if (color.a) { - return `rgba(${color.r},${color.g},${color.b},${color.a})` - } - return `rgb(${color.r},${color.g},${color.b})` - } - rgbToHsb (rgb) { - const { r, g, b } = rgb - const max = Math.max(r, g, b) - const min = Math.min(r, g, b) - const delta = max - min - const s = Math.round((max === 0 ? 0 : delta / max) * 100) - const v = Math.round(max / 255 * 100) - - let h - if (delta === 0) { - h = 0 - } else if (r === max) { - h = (g - b) / delta % 6 - } else if (g === max) { - h = (b - r) / delta + 2 - } else if (b === max) { - h = (r - g) / delta + 4 - } - h = Math.round(h * 60) - if (h < 0) { - h += 360 - } - - return { h: h, s: s, b: v } - } - get hsb () { - return this.rgbToHsb(this.rgb) - } - get grey () { - const color = this.rgb - return 1 - (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) / 255 - } - get foreground () { - const color = this.rgb - const mode = settings.foregroundColorMode - if (mode === '自动' || mode === undefined) { - if (color && this.grey < 0.35) { - return '#000' - } - return '#fff' - } else if (mode === '黑色') { - return '#000' - } else if (mode === '白色') { - return '#fff' - } - } - makeImageFilter (originalRgb) { - const { h, s } = this.rgbToHsb(originalRgb) - const targetColor = this.hsb - - const hue = targetColor.h - h - const saturate = ((targetColor.s - s) / 100 + 1) * 100 - // const brightness = ((targetColor.b - b) / 100 + 1) * 100; - const filter = `hue-rotate(${hue}deg) saturate(${saturate}%)` - return filter - } - get blueImageFilter () { - const blueColor = { - r: 0, - g: 160, - b: 213 - } - return this.makeImageFilter(blueColor) - } - get pinkImageFilter () { - const pinkColor = { - r: 251, - g: 113, - b: 152 - } - return this.makeImageFilter(pinkColor) - } - get brightness () { - return `${this.foreground === '#000' ? '100' : '0'}%` - } - get filterInvert () { - return this.foreground === '#000' ? 'invert(0)' : 'invert(1)' - } -} - +/* eslint-disable */ /* spell-checker: disable */ +Vue.config.productionTip = false +Vue.config.devtools = false +// if (unsafeWindow.Vue === undefined) { +// unsafeWindow.Vue = Vue +// } + +// GM4 polyfill start +if (typeof GM == 'undefined') { + this.GM = {} +} +Object.entries({ + 'log': console.log.bind(console), + 'info': GM_info, +}).forEach(([newKey, old]) => { + if (old && (typeof GM[newKey] == 'undefined')) { + GM[newKey] = old + } +}) +Object.entries({ + 'GM_getValue': 'getValue', + 'GM_setClipboard': 'setClipboard', + 'GM_setValue': 'setValue', + 'GM_xmlhttpRequest': 'xmlHttpRequest', +}).forEach(([oldKey, newKey]) => { + let old = this[oldKey] + if (old && (typeof GM[newKey] == 'undefined')) { + GM[newKey] = function (...args) { + return new Promise((resolve, reject) => { + try { + resolve(old.apply(this, args)) + } catch (e) { + reject(e) + } + }) + } + } +}) +// GM4 polyfill end + +// Safari EventTarget polyfill +window.EventTarget = class EventTarget { + constructor() { + this.listeners = {} + } + addEventListener(type, callback) { + if (!(type in this.listeners)) { + this.listeners[type] = [] + } + this.listeners[type].push(callback) + } + removeEventListener(type, callback) { + if (!(type in this.listeners)) { + return + } + let stack = this.listeners[type] + for (let i = 0, l = stack.length; i < l; i++) { + if (stack[i] === callback) { + stack.splice(i, 1) + return + } + } + } + dispatchEvent(event) { + if (!(event.type in this.listeners)) { + return true + } + let stack = this.listeners[event.type].slice() + for (let i = 0, l = stack.length; i < l; i++) { + stack[i].call(this, event) + } + return !event.defaultPrevented + } +} +// Safari EventTarget polyfill end + +function logError (error) { + let finalMessage = error + if (typeof error === 'object' && 'stack' in error) { + if (settings.toastInternalError) { + finalMessage = `${error.message}\n${error.stack}` + } else { + finalMessage = error.message + } + } + Toast.error(finalMessage, '错误') + console.error(error) +} +function raiseEvent (element, eventName) { + const event = document.createEvent('HTMLEvents') + event.initEvent(eventName, true, true) + element.dispatchEvent(event) +} +async function loadLazyPanel (selector) { + await SpinQuery.unsafeJquery() + const panel = await SpinQuery.any(() => unsafeWindow.$(selector)) + if (!panel) { + throw new Error(`Panel not found: ${selector}`) + } + panel.mouseover() + // 懒加载面板带有 300ms 的 denounce + return new Promise(resolve => { + setTimeout(() => { + panel.mouseout() + resolve() + }, 310) + }) +} +async function loadLazyPlayerSettingsPanel (buttonSelector, panelSelector) { + // 暂时隐藏面板 + const style = document.createElement('style') + style.innerText = `${panelSelector} { display: none !important; }` + document.body.insertAdjacentElement('beforeend', style) + await loadLazyPanel(buttonSelector) + // 有些面板有 300ms 的 transition delay + setTimeout(() => style.remove(), 300) + return dq(panelSelector) +} +async function loadDanmakuSettingsPanel () { + return await loadLazyPlayerSettingsPanel('.bilibili-player-video-danmaku-setting', '.bilibili-player-video-danmaku-setting-wrap') +} +async function loadSubtitleSettingsPanel () { + return await loadLazyPlayerSettingsPanel('.bilibili-player-video-btn-subtitle', '.bilibili-player-video-subtitle-setting-wrap') +} +function contentLoaded (callback) { + if (/complete|interactive|loaded/.test(document.readyState)) { + callback() + } else { + document.addEventListener('DOMContentLoaded', () => callback()) + } +} +function fullyLoaded (callback) { + if (document.readyState === 'complete') { + callback() + } else { + unsafeWindow.addEventListener('load', () => callback()) + } +} +function fixed (number, precision = 1) { + const str = number.toString() + const index = str.indexOf('.') + if (index !== -1) { + if (str.length - index > precision + 1) { + return str.substring(0, index + precision + 1) + } else { + return str + } + } else { + return str + '.0' + } +} +function isEmbeddedPlayer () { + return location.host === 'player.bilibili.com' || document.URL.startsWith('https://www.bilibili.com/html/player.html') +} +function isIframe () { + return document.body && unsafeWindow.parent.window !== unsafeWindow +} +const languageNameToCode = { + '日本語': 'ja-JP', + 'English': 'en-US', + 'Deutsch': 'de-DE' +} +const languageCodeToName = { + 'ja-JP': '日本語', + 'en-US': 'English', + 'de-DE': 'Deutsch' +} +function getI18nKey () { + return settings.i18n ? languageNameToCode[settings.i18nLanguage] : 'zh-CN' +} +const dq = (selector, scopedSelector) => { + if (!scopedSelector) { + return document.querySelector(selector) + } + return selector.querySelector(scopedSelector) +} +const dqa = (selector, scopedSelector) => { + if (!scopedSelector) { + return [...document.querySelectorAll(selector)] + } + return [...selector.querySelectorAll(scopedSelector)] +} +const UserAgent = `Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0` +const EmptyImageUrl = 'data:image/svg+xml;utf-8,' +const ascendingSort = (itemProp) => { + return (a, b) => itemProp(a) - itemProp(b) +} +const descendingSort = (itemProp) => { + return (a, b) => itemProp(b) - itemProp(a) +} +const formatFileSize = (bytes, fixed = 1) => { + const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] + let number = bytes + let unitIndex = 0 + while (number >= 1024) { + number /= 1024 + unitIndex++ + } + return `${Math.round(number * (10 ** fixed)) / (10 ** fixed)}${units[unitIndex]}` +} +const formatDuration = (time, fixed = 0) => { + const second = (time % 60).toFixed(fixed) + const minute = (Math.trunc(time / 60) % 60).toString() + const hour = Math.trunc(time / 3600).toString() + if (hour === '0') { + return `${minute.padStart(2, '0')}:${second.padStart(2, '0')}` + } + return `${hour}:${minute.padStart(2, '0')}:${second.padStart(2, '0')}` +} +const getDpiSourceSet = (src, baseSize, extension = 'jpg') => { + const dpis = [1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4] + if (extension.startsWith('.')) { + extension = extension.substring(1) + } + return dpis.map(dpi => { + if (typeof baseSize === 'object') { + if ('width' in baseSize && 'height' in baseSize) { + return `${src}@${Math.trunc(baseSize.width * dpi)}w_${Math.trunc(baseSize.height * dpi)}h.${extension} ${dpi}x` + } else if ('width' in baseSize) { + return `${src}@${Math.trunc(baseSize.width * dpi)}w.${extension} ${dpi}x` + } else if ('height' in baseSize) { + return `${src}@${Math.trunc(baseSize.height * dpi)}h.${extension} ${dpi}x` + } + } else { + return `${src}@${Math.trunc(baseSize * dpi)}w_${Math.trunc(baseSize * dpi)}h.${extension} ${dpi}x` + } + }).join(",") +} +const isOffline = () => typeof offlineData !== 'undefined' +const getUID = () => document.cookie.replace(/(?:(?:^|.*;\s*)DedeUserID\s*\=\s*([^;]*).*$)|^.*$/, '$1') +const scriptVersion = (() => { + const match = GM.info.script.name.match(/Evolved \((.*)\)/) + return match ? match[1] : 'Stable' +})() +const getCsrf = () => document.cookie.replace(/(?:(?:^|.*;\s*)bili_jct\s*\=\s*([^;]*).*$)|^.*$/, '$1') +const formatCount = (count) => { + if (typeof count === 'string') { + count = parseInt(count) + } + if (count > 100000000) { + return Math.round(count / 10000000) / 10 + '亿' + } + if (count > 10000) { + return Math.round(count / 1000) / 10 + '万' + } + return count + '' +} +const escapeFilename = (filename, replacement = '') => { + return filename.replace(/[\/\\:\*\?"<>\|]/g, replacement) +} +function html (strings, ...values) { + return [...strings].reduce((previous, current, index) => { + const value = values[index] + return previous + current + (value === undefined ? '' : value) + }, '') +} +const dashExtensions = ['.mp4', '.m4a'] +const dashFragmentExtension = 'm4s' +const videoCondition = async () => { + let cid = await SpinQuery.select(() => (unsafeWindow || window).cid) + return Boolean(cid) +} +const matchPattern = (str, pattern) => { + if (typeof pattern === 'string') { + return str.includes(pattern) + } + return pattern.test(str) +} + +const customNavbarDefaultOrders = { + blank1: 0, + logo: 1, + category: 2, + rankingLink: 3, + drawingLink: 4, + musicLink: 5, + gamesIframe: 6, + livesIframe: 7, + shopLink: 8, + mangaLink: 9, + blank2: 10, + search: 11, + blank3: 12, + userInfo: 13, + messages: 14, + activities: 15, + bangumi: 16, + watchlaterList: 17, + favoritesList: 18, + historyList: 19, + upload: 20, + darkMode: 21, +} +const simpleHomeCategoryDefaultOrders = { + anime: 0, + bangumi: 1, + china: 2, + manga: 3, + music: 4, + dance: 5, + game: 6, + tech: 7, + digital: 8, + life: 9, + kichiku: 10, + fashion: 11, + information: 12, + entertainment: 13, + column: 14, + movie: 15, + tv: 16, + film: 17, + documentary: 18, +} +const aria2RpcDefaultOption = { + secretKey: '', + dir: '', + host: '127.0.0.1', + port: '6800', + method: 'get', + skipByDefault: false, + maxDownloadLimit: '', + baseDir: '', +} +const settings = { + useDarkStyle: false, + // showBanner: true, + hideBanner: false, + expandDanmakuList: true, + expandDescription: true, + watchLaterRedirect: true, + touchNavBar: false, + touchVideoPlayer: false, + customControlBackgroundOpacity: 0.64, + customControlBackground: false, + darkScheduleStart: '18:00', + darkScheduleEnd: '6:00', + darkSchedule: false, + toast: true, + fullTweetsTitle: true, + fullPageTitle: false, + removeVideoTopMask: false, + removeLiveWatermark: true, + harunaScale: true, + removeAds: true, + showBlockedAdsTip: false, + hideTopSearch: false, + touchVideoPlayerDoubleTapControl: false, + customStyleColor: '#00A0D8', + preserveRank: true, + blurBackgroundOpacity: 0.382, + useDefaultPlayerMode: false, + applyPlayerModeOnPlay: true, + defaultPlayerMode: '常规', + useDefaultVideoQuality: false, + defaultVideoQuality: '自动', + useDefaultDanmakuSettings: false, + enableDanmaku: true, + rememberDanmakuSettings: false, + danmakuSettings: { + subtitlesPreserve: false, + smartMask: false, + }, + defaultPlayerLayout: '新版', + defaultBangumiLayout: '新版', + skipChargeList: false, + comboLike: false, + autoLightOff: false, + useCache: true, + autoContinue: false, + allowJumpContinue: false, + deadVideoTitleProvider: '稍后再看', + useBiliplusRedirect: false, + biliplusRedirect: false, + framePlayback: true, + useCommentStyle: true, + imageResolution: false, + imageResolutionScale: 'auto', + toastInternalError: false, + i18n: false, + i18nLanguage: '日本語', + playerFocus: false, + playerFocusOffset: -10, + simplifyLiveroom: false, + simplifyLiveroomSettings: { + vip: true, + fansMedal: true, + title: true, + userLevel: true, + guard: true, + systemMessage: true, + welcomeMessage: true, + giftMessage: true, + guardPurchase: true, + giftPanel: true, + kanban: true, + userEffect: true, + eventsBanner: false, + rankList: false, + popup: false, + skin: false, + }, + customNavbar: true, + customNavbarFill: false, + customNavbarTransparent: true, + customNavbarShadow: true, + customNavbarBlur: false, + customNavbarBlurOpacity: 0.7, + customNavbarOrder: { ...customNavbarDefaultOrders }, + customNavbarHidden: ['blank1', 'drawingLink', 'musicLink', 'gamesIframe', 'darkMode'], + customNavbarBoundsPadding: 10, + playerShadow: false, + narrowDanmaku: true, + outerWatchlater: true, + videoScreenshot: false, + hideBangumiReviews: false, + filenameFormat: '[title][ - ep]', + batchFilenameFormat: '[n - ][ep]', + sideBarOffset: 0, + noLiveAutoplay: false, + hideHomeLive: false, + noMiniVideoAutoplay: false, + useDefaultVideoSpeed: false, + defaultVideoSpeed: '1.0', + hideCategory: false, + foldComment: true, + downloadVideoDefaultDanmaku: '无', + downloadVideoDefaultSubtitle: '无', + aria2RpcOption: { ...aria2RpcDefaultOption }, + aria2RpcOptionSelectedProfile: '', + aria2RpcOptionProfiles: [], + searchHistory: [], + seedsToCoins: true, + autoSeedsToCoins: true, + lastSeedsToCoinsDate: 0, + autoDraw: false, + keymap: false, + doubleClickFullscreen: false, + doubleClickFullscreenPreventSingleClick: false, + simplifyHome: false, + simplifyHomeStyle: '清爽', + minimalHomeSettings: { + showSearch: true, + backgroundImage: '', + }, + ajaxHook: false, + scriptLoadingMode: '延后(自动)', + scriptDownloadMode: 'bundle', + guiSettingsDockSide: '左侧', + fullActivityContent: true, + feedsFilter: false, + feedsFilterPatterns: [], + feedsFilterTypes: [], + feedsFilterSideCards: [], + activityImageSaver: false, + scriptBlockPatterns: [], + customNavbarSeasonLogo: false, + selectableColumnText: true, + downloadVideoFormat: 'flv', + downloadVideoDashCodec: 'AVC/H.264', + watchlaterExpireWarningDays: 14, + superchatTranslate: false, + miniPlayerTouchMove: false, + hideBangumiSponsors: false, + hideRecommendLive: false, + hideRelatedVideos: false, + defaultMedalID: 0, + autoMatchMedal: false, + customStyles: [], + simpleHomeCategoryOrders: { ...simpleHomeCategoryDefaultOrders }, + simpleHomeBangumiLayout: '时间表', + keymapJumpSeconds: 85, + urlParamsClean: true, + collapseLiveSideBar: true, + removeGameMatchModule: false, + noDarkOnMember: true, + feedsTranslate: false, + feedsTranslateProvider: 'Bing', + feedsTranslateLanguage: '', + downloadVideoQuality: 120, + defaultLiveQuality: '原画', + useDefaultLiveQuality: false, + recordLiveDanmaku: false, + foregroundColorMode: '自动', + preserveEventBanner: false, + about: true, + bvidConvert: true, + fixedSidebars: false, + updateCdn: 'jsDelivr', + lastNewVersionCheck: 0, + newVersionCheckInterval: 1000 * 3600 * 6, // 6 hours + useDarkStyleAsUserStyle: false, + darkColorScheme: false, + autoHideSideBar: false, + livePip: true, + extendFeedsLive: true, + userImages: [], + playerOnTop: false, + restoreFloors: false, + quickFavorite: false, + quickFavoriteID: 0, + bilibiliSimpleNewHomeCompatible: false, + preferAvUrl: false, + elegantScrollbar: true, + cache: {}, +} +const fixedSettings = { + autoPlay: false, + favoritesRedirect: false, + compactLayout: false, + hideOldEntry: false, + guiSettings: true, + viewCover: true, + notifyNewVersion: true, + clearCache: true, + downloadVideo: true, + enableDashDownload: true, + downloadDanmaku: true, + downloadSubtitle: true, + downloadAudio: true, + downloadLiveRecords: true, + medalHelper: true, + playerLayout: false, + forceWide: false, + useNewStyle: false, + overrideNavBar: false, + touchVideoPlayerAnimation: false, + allNavbarFill: false, + showDeadVideoTitle: false, + blurVideoControl: false, + oldTweets: false, + customNavbarCompact: false, + watchlaterExpireWarnings: false, + latestVersionLink: 'https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/bilibili-evolved.offline.user.js', + currentVersion: GM.info.script.version, +} +const settingsChangeHandlers = {} +function addSettingsListener (key, handler, initCall) { + if (!settingsChangeHandlers[key]) { + settingsChangeHandlers[key] = [handler] + } else { + settingsChangeHandlers[key].push(handler) + } + if (initCall) { + const value = settings[key] + handler(value, value) + } +} +function removeSettingsListener (key, handler) { + const handlers = settingsChangeHandlers[key] + if (!handlers) { + return + } + handlers.splice(handlers.indexOf(handler), 1) +} +async function loadSettings () { + for (const key in fixedSettings) { + settings[key] = fixedSettings[key] + await GM.setValue(key, fixedSettings[key]) + } + if (Object.keys(languageCodeToName).includes(navigator.language)) { + settings.i18n = true + settings.i18nLanguage = languageCodeToName[navigator.language] + } + for (const key in settings) { + let value = await GM.getValue(key) + if (key === 'batchFilenameFormat' && value === '[n - ][title]') { + value = '[n - ][ep]' + GM.setValue(key, value) + } + if (value === undefined) { + value = settings[key] + GM.setValue(key, settings[key]) + } else if (settings[key] !== undefined && value.constructor === Object) { + value = Object.assign(settings[key], value) + } + Object.defineProperty(settings, key, { + get () { + return value + }, + set (newValue) { + value = newValue + GM.setValue(key, newValue) + + const handlers = settingsChangeHandlers[key] + if (handlers) { + if (key === 'useDarkStyle') { + setTimeout(() => handlers.forEach(h => h(newValue, value)), 200) + } else { + handlers.forEach(h => h(newValue, value)) + } + } + const input = document.querySelector(`input[key=${key}]`) + if (input !== null) { + if (input.type === 'checkbox') { + input.checked = newValue + } else if (input.type === 'text' && !input.parentElement.classList.contains('gui-settings-dropdown')) { + input.value = newValue + } + } + } + }) + } +} + +class Ajax { + static send (xhr, body, text = true) { + return new Promise((resolve, reject) => { + xhr.addEventListener('load', () => { + // if (xhr.status.toString().match(/^[45]/)) { + // reject(xhr.status) + // } else { + resolve(text ? xhr.responseText : xhr.response) + // } + }) + xhr.addEventListener('error', () => reject(xhr.status)) + xhr.send(body) + }) + } + static getBlob (url) { + const xhr = new XMLHttpRequest() + xhr.responseType = 'blob' + xhr.open('GET', url) + return this.send(xhr, undefined, false) + } + static getBlobWithCredentials (url) { + const xhr = new XMLHttpRequest() + xhr.responseType = 'blob' + xhr.open('GET', url) + xhr.withCredentials = true + return this.send(xhr, undefined, false) + } + static async getJson (url) { + return JSON.parse(await this.getText(url)) + } + static async getJsonWithCredentials (url) { + return JSON.parse(await this.getTextWithCredentials(url)) + } + static getText (url) { + const xhr = new XMLHttpRequest() + xhr.open('GET', url) + return this.send(xhr) + } + static getTextWithCredentials (url) { + const xhr = new XMLHttpRequest() + xhr.open('GET', url) + xhr.withCredentials = true + return this.send(xhr) + } + static postText (url, body) { + const xhr = new XMLHttpRequest() + xhr.open('POST', url) + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') + return this.send(xhr, body) + } + static postTextWithCredentials (url, body) { + const xhr = new XMLHttpRequest() + xhr.open('POST', url) + xhr.withCredentials = true + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') + return this.send(xhr, body) + } + static postJson (url, json) { + const xhr = new XMLHttpRequest() + xhr.open('POST', url) + xhr.setRequestHeader('Content-Type', 'application/json') + return this.send(xhr, JSON.stringify(json), false) + } + static postJsonWithCredentials (url, json) { + const xhr = new XMLHttpRequest() + xhr.open('POST', url) + xhr.withCredentials = true + xhr.setRequestHeader('Content-Type', 'application/json') + return this.send(xhr, JSON.stringify(json), false) + } + static getHandlers (name) { + name = name.toLowerCase() + let handlers = Ajax[name] + if (handlers === undefined) { + handlers = Ajax[name] = [] + } + return handlers + } + static addEventListener (type, handler) { + const handlers = Ajax.getHandlers(type) + handlers.push(handler) + } + static removeEventListener (type, handler) { + const handlers = Ajax.getHandlers(type) + handlers.splice(handlers.indexOf(handler), 1) + } + static monkey (details) { + return new Promise((resolve, reject) => { + const fullDetails = { + ...details, + onload: r => resolve(r.response), + onerror: r => reject(r), + } + if (!('method' in fullDetails)) { + fullDetails.method = 'GET' + } + GM.xmlHttpRequest(fullDetails) + }) + } + static async getPages({api, getList, getTotal}) { + let page = 1 + let total = Infinity + const result = [] + while (result.length < total) { + const json = await api(page) + if (json.code !== 0) { + console.warn(`api failed in Ajax.getPages. message = ${json.message}, page = ${page}, total = ${total}, api = `, api) + } + const list = getList(json) + result.push(...list) + if (total === Infinity) { + total = getTotal(json) + } + } + return result + } +} +// https://github.com/the1812/Bilibili-Evolved/issues/84 +let ajaxHooked = false +function setupAjaxHook () { + if (ajaxHooked) { + return + } + ajaxHooked = true + const original = { + open: XMLHttpRequest.prototype.open, + send: XMLHttpRequest.prototype.send + } + const fireHandlers = (name, thisArg, ...args) => Ajax.getHandlers(name).forEach(it => it.call(thisArg, ...args)) + const hook = (name, thisArgs, ...args) => { + fireHandlers('before' + name, thisArgs, ...args) + const returnValue = original[name].call(thisArgs, ...args) + fireHandlers('after' + name, thisArgs, ...args) + return returnValue + } + const hookOnEvent = (name, thisArg) => { + if (thisArg[name]) { + const originalHandler = thisArg[name] + thisArg[name] = (...args) => { + fireHandlers('before' + name, thisArg, ...args) + originalHandler.apply(thisArg, args) + fireHandlers('after' + name, thisArg, ...args) + } + } else { + thisArg[name] = (...args) => { + fireHandlers('before' + name, thisArg, ...args) + fireHandlers('after' + name, thisArg, ...args) + } + } + } + XMLHttpRequest.prototype.open = function (...args) { return hook('open', this, ...args) } + XMLHttpRequest.prototype.send = function (...args) { + hookOnEvent('onreadystatechange', this) + hookOnEvent('onload', this) + return hook('send', this, ...args) + } +} + +async function loadResources () { + Resource.root = 'https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/' + switch (await GM.getValue('updateCdn')) { + case 'jsDelivr': + default: + Resource.cdnRoot = 'https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@master/' + break + case 'GitHub': + Resource.cdnRoot = Resource.root + break + } + Resource.all = {} + Resource.displayNames = {} + Resource.reloadables = [] + for (const [key, data] of Object.entries(Resource.manifest)) { + const resource = new Resource(data.path, { styles: data.styles, alwaysPreview: data.alwaysPreview }) + resource.key = key + resource.dropdown = data.dropdown + if (data.reloadable) { + Resource.reloadables.push(key) + } + if (data.displayNames) { + resource.displayName = data.displayNames[key] + Object.assign(Resource.displayNames, data.displayNames) + } + if (data.style) { + const styleKey = key + 'Style' + const style = Resource.all[styleKey] = new Resource(data.path.replace('.js', '.css'), { alwaysPreview: data.alwaysPreview }) + style.key = styleKey + switch (data.style) { + case 'instant': + { + resource.styles.push(styleKey) + break + } + case true: + { + resource.dependencies.push(style) + break + } + case 'important': + { + resource.styles.push({ + key: styleKey, + important: true + }) + break + } + default: + { + if (typeof data.style === 'object') { + resource.styles.push(Object.assign({ key: styleKey }, data.style)) + } + break + } + } + } + if (data.html === true) { + const htmlKey = key + 'Html' + const html = Resource.all[htmlKey] = new Resource(data.path.replace('.js', '.html'), { alwaysPreview: data.alwaysPreview }) + html.key = htmlKey + resource.dependencies.push(html) + } + Resource.all[key] = resource + } + for (const [key, data] of Object.entries(Resource.manifest)) { + if (data.dependencies) { + Resource.all[key].dependencies.push(...data.dependencies.map(name => Resource.all[name])) + } + } +} + +// Placeholder class for Toast +class Toast { + show () { } + dismiss () { } + static show () { } + static info () { } + static success () { } + static error () { } +} + +class DoubleClickEvent { + constructor (handler, singleClickHandler = null) { + this.handler = handler + this.singleClickHandler = singleClickHandler + this.elements = [] + this.clickedOnce = false + this.doubleClickHandler = e => { + if (!this.clickedOnce) { + this.clickedOnce = true + setTimeout(() => { + if (this.clickedOnce) { + this.clickedOnce = false + this.singleClickHandler && this.singleClickHandler(e) + } + }, 200) + } else { + this.clickedOnce = false + this.handler && this.handler(e) + } + } + } + bind (element) { + if (this.elements.indexOf(element) === -1) { + this.elements.push(element) + element.addEventListener('click', this.doubleClickHandler) + } + } + unbind (element) { + const index = this.elements.indexOf(element) + if (index === -1) { + return + } + this.elements.splice(index, 1) + element.removeEventListener('click', this.doubleClickHandler) + } +} + +let cidHooked = false +const videoChangeCallbacks = [] +class Observer { + constructor (elements, callback) { + this.elements = elements || [] + this.callback = callback + this.observer = null + this.options = undefined + } + start () { + this.elements.forEach(element => { + this.observer = new MutationObserver(this.callback) + this.observer.observe(element, this.options) + }) + return this + } + add (element) { + this.elements.push(element) + this.observer.observe(element, this.options) + return this + } + stop () { + this.observer && this.observer.disconnect() + return this + } + // 向后兼容的接口, 实际并没有什么遍历 + forEach (callback) { + callback(this) + } + static observe (selector, callback, options) { + callback([]) + let elements = selector + if (typeof selector === 'string') { + elements = [...document.querySelectorAll(selector)] + } else if (!Array.isArray(selector)) { + elements = [selector] + } + const observer = new Observer(elements, callback) + observer.options = options + return observer.start() + } + static childList (selector, callback) { + return Observer.observe(selector, callback, { + childList: true, + subtree: false, + attributes: false + }) + } + static childListSubtree (selector, callback) { + return Observer.observe(selector, callback, { + childList: true, + subtree: true, + attributes: false + }) + } + static attributes (selector, callback) { + return Observer.observe(selector, callback, { + childList: false, + subtree: false, + attributes: true + }) + } + static attributesSubtree (selector, callback) { + return Observer.observe(selector, callback, { + childList: false, + subtree: true, + attributes: true + }) + } + static all (selector, callback) { + return Observer.observe(selector, callback, { + childList: true, + subtree: true, + attributes: true + }) + } + static async videoChange (callback) { + const cid = await SpinQuery.select(() => unsafeWindow.cid) + if (cid === null) { + return + } + if (!cidHooked) { + let hookedCid = cid + Object.defineProperty(unsafeWindow, 'cid', { + get () { + return hookedCid + }, + set (newId) { + hookedCid = newId + if (!Array.isArray(newId)) { + videoChangeCallbacks.forEach(it => it()) + } + } + }) + cidHooked = true + } + // callback(); + const videoContainer = await SpinQuery.select('#bofqi video') + if (videoContainer) { + Observer.childList(videoContainer, callback) + } else { + callback() + } + videoChangeCallbacks.push(callback) + } +} + +class SpinQuery { + constructor (query, condition, action, failed) { + this.maxRetry = 15 + this.retry = 0 + this.queryInterval = 1000 + this.query = query + this.condition = condition + this.action = action + this.failed = failed + } + start () { + this.tryQuery(this.query, this.condition, this.action, this.failed) + } + tryQuery (query, condition, action, failed) { + if (this.retry < this.maxRetry) { + const result = query() + if (condition(result)) { + action(result) + } else { + if (document.hasFocus()) { + this.retry++ + } + setTimeout(() => this.tryQuery(query, condition, action, failed), this.queryInterval) + } + } else { + typeof failed === 'function' && failed() + } + } + static condition (query, condition, action, failed) { + if (action !== undefined) { + new SpinQuery(query, condition, action, failed).start() + } else { + return new Promise((resolve) => { + new SpinQuery(query, condition, it => resolve(it), () => resolve(null)).start() + }) + } + } + static select (query, action, failed) { + if (typeof query === 'string') { + const selector = query + query = () => document.querySelector(selector) + } + return SpinQuery.condition(query, it => it !== null && it !== undefined, action, failed) + } + static any (query, action, failed) { + if (typeof query === 'string') { + const selector = query + query = () => $(selector) + } + return SpinQuery.condition(query, it => it.length > 0, action, failed) + } + static count (query, count, action, failed) { + if (typeof query === 'string') { + const selector = query + query = () => document.querySelectorAll(selector) + } + return SpinQuery.condition(query, it => it.length === count, action, failed) + } + static unsafeJquery (action, failed) { + return SpinQuery.condition(() => unsafeWindow.$, jquery => jquery !== undefined, action, failed) + } +} + +class ColorProcessor { + constructor (hex) { + this.hex = hex + } + get rgb () { + return this.hexToRgb(this.hex) + } + get rgba () { + return this.hexToRgba(this.hex) + } + getHexRegex (alpha, shorthand) { + const repeat = shorthand ? '' : '{2}' + const part = `([a-f\\d]${repeat})` + const count = alpha ? 4 : 3 + const pattern = `#?${part.repeat(count)}` + return new RegExp(pattern, 'ig') + } + hexToRgbOrRgba (hex, alpha) { + const isShortHand = hex.length < 6 + if (isShortHand) { + const shorthandRegex = this.getHexRegex(alpha, true) + hex = hex.replace(shorthandRegex, function (...args) { + let result = '' + let i = 1 + while (args[i]) { + result += args[i].repeat(2) + i++ + } + return result + }) + } + + const regex = this.getHexRegex(alpha, false) + const regexResult = regex.exec(hex) + if (regexResult) { + const color = { + r: parseInt(regexResult[1], 16), + g: parseInt(regexResult[2], 16), + b: parseInt(regexResult[3], 16) + } + if (regexResult[4]) { + color.a = parseInt(regexResult[4], 16) / 255 + } + return color + } else if (alpha) { + const rgb = this.hexToRgbOrRgba(hex, false) + if (rgb) { + rgb.a = 1 + return rgb + } + } + return null + } + hexToRgb (hex) { + return this.hexToRgbOrRgba(hex, false) + } + hexToRgba (hex) { + return this.hexToRgbOrRgba(hex, true) + } + rgbToString (color) { + if (color.a) { + return `rgba(${color.r},${color.g},${color.b},${color.a})` + } + return `rgb(${color.r},${color.g},${color.b})` + } + rgbToHsb (rgb) { + const { r, g, b } = rgb + const max = Math.max(r, g, b) + const min = Math.min(r, g, b) + const delta = max - min + const s = Math.round((max === 0 ? 0 : delta / max) * 100) + const v = Math.round(max / 255 * 100) + + let h + if (delta === 0) { + h = 0 + } else if (r === max) { + h = (g - b) / delta % 6 + } else if (g === max) { + h = (b - r) / delta + 2 + } else if (b === max) { + h = (r - g) / delta + 4 + } + h = Math.round(h * 60) + if (h < 0) { + h += 360 + } + + return { h: h, s: s, b: v } + } + get hsb () { + return this.rgbToHsb(this.rgb) + } + get grey () { + const color = this.rgb + return 1 - (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) / 255 + } + get foreground () { + const color = this.rgb + const mode = settings.foregroundColorMode + if (mode === '自动' || mode === undefined) { + if (color && this.grey < 0.35) { + return '#000' + } + return '#fff' + } else if (mode === '黑色') { + return '#000' + } else if (mode === '白色') { + return '#fff' + } + } + makeImageFilter (originalRgb) { + const { h, s } = this.rgbToHsb(originalRgb) + const targetColor = this.hsb + + const hue = targetColor.h - h + const saturate = ((targetColor.s - s) / 100 + 1) * 100 + // const brightness = ((targetColor.b - b) / 100 + 1) * 100; + const filter = `hue-rotate(${hue}deg) saturate(${saturate}%)` + return filter + } + get blueImageFilter () { + const blueColor = { + r: 0, + g: 160, + b: 213 + } + return this.makeImageFilter(blueColor) + } + get pinkImageFilter () { + const pinkColor = { + r: 251, + g: 113, + b: 152 + } + return this.makeImageFilter(pinkColor) + } + get brightness () { + return `${this.foreground === '#000' ? '100' : '0'}%` + } + get filterInvert () { + return this.foreground === '#000' ? 'invert(0)' : 'invert(1)' + } +} + const offlineData = {}; offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/about.min.css"] = `.bilibili-evolved-about{height:100%;width:450px;background:#fff;color:#000;position:fixed;top:0;left:0;z-index:100000;transform:translateX(-101%);transition:.3s cubic-bezier(0,.86,.58,1);display:flex;flex-direction:column;box-shadow:4px 0 16px 0 #0000;user-select:none}.gui-settings-dock-right .bilibili-evolved-about{right:0;left:unset;transform:translateX(101%)}body.dark .bilibili-evolved-about{background:#222;color:#eee}.bilibili-evolved-about.opened,.gui-settings-dock-right .bilibili-evolved-about.opened{transform:translateX(0);box-shadow:4px 0 16px 0 #0005}.about-header{padding:32px;display:flex;align-items:center;justify-content:flex-start}.about-header i{margin-right:8px;display:flex}.about-title{font-size:16pt}.about-content{padding:16px 36px 0;margin-bottom:36px;display:flex;flex-direction:column;overflow:auto}.about-content .name{font-size:24pt;display:none;align-items:center}.about-content .name svg{width:100%}body.dark .about-content .name.dark,body:not(.dark) .about-content .name.light{display:flex}.about-content .version{font-size:10pt;font-weight:700;opacity:.6;margin-top:6px;margin-bottom:6px;align-self:center}.about-content .love{font-size:10pt;margin-bottom:24px;align-self:center}.about-content .love a{color:inherit!important}.about-content section{font-size:10pt;margin-top:16px}.about-content section .title{display:flex;justify-content:center;text-transform:uppercase;font-weight:700;font-size:13pt;letter-spacing:3px;margin:8px 0 16px}.about-content section .supporter,.about-content section a{color:var(--theme-color)!important;margin-right:8px;display:inline-flex}.about-content section .supporter{user-select:none}.about-content section .supporter:not(:last-child)::after,.about-content section a:not(:last-child)::after{content:","}@keyframes spinner{to{transform:translate(-50%,-50%) rotate(360deg)}}.about-content section.participants .fetching{margin-right:8px;position:relative;display:inline-flex}.about-content section.participants .fetching::before{content:"Loading..."}`; offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/about.min.html"] = `
关于

v{{version}} · {{clientType}}

Made with ❤  Buy me a coffee ☕

Authors{{author.name}}
Contributors{{contributor.name}}
View Supporters
Community Power{{participant.name}}
Websites{{website.name}}
Components{{component.name}}
`; @@ -1272,7 +1273,7 @@ offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/m offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/custom-control-background.min.js"] = (()=>{return(t,o)=>{addSettingsListener("customControlBackgroundOpacity",t=>{document.documentElement.style.setProperty("--custom-control-background-opacity",t)},true);const n=()=>{o.applyStyle("customControlBackgroundStyle");if(!t.touchVideoPlayer){o.applyImportantStyleFromText(`\n\n`)}};n();return{reload:n,unload:()=>{o.removeStyle("customControlBackgroundStyle");const t=document.getElementById("control-background-non-touch");t&&t.remove()}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/custom-navbar.min.css"] = `@font-face{font-family:custom-navbar-font;src:url(//s1.hdslb.com/bfs/seed/jinkela/header/asserts/iconfont.ttf) format("truetype")}@font-face{font-family:custom-navbar-font-extended;src:url(//s1.hdslb.com/bfs/static/jinkela/video/asserts/iconfont.4bab144.ttf) format("truetype")}@font-face{font-family:custom-navbar-font-new-home;src:url(//s1.hdslb.com/bfs/seed/jinkela/header-v2/asserts/iconfont.ttf) format("truetype")}.custom-navbar-iconfont,.custom-navbar-iconfont-extended,.custom-navbar-iconfont-new-home{color:inherit;font-family:custom-navbar-font!important;font-size:24px;font-style:normal}.custom-navbar-iconfont-extended{font-family:custom-navbar-font-extended!important}.custom-navbar-iconfont-new-home{font-family:custom-navbar-font-new-home!important}.custom-navbar-icon-logo::before{content:""}.custom-navbar-icon-lv0::before{content:"";color:#9a9a9a}.custom-navbar-icon-lv1::before{content:"";color:#646464}.custom-navbar.dark .custom-navbar-icon-lv0::before{color:#777}.custom-navbar.dark .custom-navbar-icon-lv1::before{color:#ddd}.custom-navbar-icon-lv2::before{content:"";color:#1bc861}.custom-navbar-icon-lv3::before{content:"";color:#22baea}.custom-navbar-icon-lv4::before{content:"";color:#eaa722}.custom-navbar-icon-lv5::before{content:"";color:#ff7631}.custom-navbar-icon-lv6::before{content:"";color:#ff3131}.custom-navbar-icon-profile::before{content:""}.custom-navbar-icon-posts::before{content:""}.custom-navbar-icon-wallet::before{content:""}.custom-navbar-icon-live-center::before{content:""}.custom-navbar-icon-order-center::before{content:""}.custom-navbar-icon-logout::before{content:""}.custom-navbar-icon-ok::before{content:""}.custom-navbar-icon-cancel::before{content:""}.custom-navbar-icon-bind-phone::before{content:""}.custom-navbar-icon-bind-email::before{content:""}.custom-navbar-icon-coin::before{content:""}.custom-navbar-icon-b-coin::before{content:""}.custom-navbar-icon-activity::before{content:""}.custom-navbar-icon-message::before{content:""}.custom-navbar-icon-favorite::before{content:""}.custom-navbar-icon-history::before{content:""}.custom-navbar-icon-vip::before{content:""}.custom-navbar-icon-course::before{content:""}[class^=custom-navbar-icon-lv]::before{font-size:24px}html{--navbar-height:50px;--navbar-foreground:#555;--navbar-background:white;--navbar-bounds-padding:0 5%;--navbar-blur-opacity:0.7;--navbar-icon-size:24px}body.custom-navbar-loading::after{content:"";height:var(--navbar-height);width:100%;position:absolute;top:0;left:0;background-color:#fff;z-index:10001}body.dark.custom-navbar-loading::after{background-color:#333}.bili-banner .taper-line,.bili-header-m .head-banner .head-content .head-logo,.bili-header-m>#banner_link .search,.i_menu_login,.international-header .b-logo,.international-header .mini-header,.z-top-container>.header .search,body.no-banner #banner_link,body.no-banner .z-top-container.has-banner>.header,li.nav-item[report-id=playpage_dynamic] .i-frame,li.nav-item[report-id=playpage_dynamic] iframe{display:none!important}.van-popover{z-index:10002!important}:not(.international-home)>.international-header{min-height:var(--navbar-height)!important}.bili-header-m .head-banner{margin-top:calc(-1 * var(--navbar-height))!important}.bili-header-m>.nav-menu,.z_top{visibility:hidden!important;height:var(--navbar-height)!important}.link-top-container#tab-container{top:var(--navbar-height)!important}.custom-navbar,.custom-navbar *,.custom-navbar-settings,.custom-navbar-settings *{transition:.2s ease-out;-webkit-tap-highlight-color:transparent;outline:0!important;margin-inline-start:0;margin-inline-end:0;padding-inline-start:0;padding-inline-end:0}.custom-navbar{position:absolute;top:0;left:0;height:var(--navbar-height);width:100%;background-color:var(--navbar-background);color:var(--navbar-foreground);z-index:10001;display:flex;justify-content:center}.custom-navbar:not(.fill) .custom-navbar-iconfont{color:var(--theme-color)}.custom-navbar path{fill:var(--navbar-foreground)}.custom-navbar svg.stroke,.custom-navbar svg.stroke path{fill:transparent;stroke:var(--navbar-foreground)}.custom-navbar.fill:not(.transparent) path{fill:var(--foreground-color-d)}.custom-navbar.fill:not(.transparent) path svg.stroke,.custom-navbar.fill:not(.transparent) path svg.stroke path{fill:transparent;stroke:var(--navbar-foreground-d)}.custom-navbar.shadow:not(.transparent){box-shadow:#0002 0 1px 10px 1px}.custom-navbar.dark.shadow:not(.transparent){box-shadow:#0004 0 2px 10px 1px}.custom-navbar.dark:not(.fill):not(.transparent){--navbar-background:#222;--navbar-foreground:#eee}.custom-navbar.transparent{--navbar-background:transparent;--navbar-foreground:#eee}.custom-navbar.transparent::before{content:"";position:absolute;top:0;left:0;width:100%;height:calc(2 * var(--navbar-height));background-image:linear-gradient(to bottom,#000a 0,#0004 65%,transparent 100%)}.custom-navbar .popup{color:#000;background:#fff;transition:.2s ease-out .2s}.custom-navbar.dark .popup{color:#eee;background:#222}.custom-navbar.dark .popup iframe{box-shadow:rgba(0,0,0,.2) 0 4px 8px 0}.custom-navbar.fill:not(.transparent){--navbar-background:var(--theme-color);--navbar-foreground:var(--foreground-color-d);height:var(--navbar-height);width:100%}.custom-navbar.fill.shadow:not(.transparent){box-shadow:var(--theme-color-30) 0 2px 10px 1px}.custom-navbar>ul{display:flex;align-items:center;justify-content:space-between;margin:var(--navbar-bounds-padding);height:100%;flex-grow:1}.custom-navbar ul{list-style:none;color:inherit}.custom-navbar li{color:inherit;list-style:none}.custom-navbar>ul>li{position:relative;height:100%;display:flex;align-items:center;color:inherit}.custom-navbar li .active-bar{position:absolute;left:0;bottom:0;background-color:var(--theme-color);width:100%;height:3px;border-radius:1.5px;display:none}.custom-navbar.fill li .active-bar,.custom-navbar.transparent li .active-bar{background-color:rgba(0,0,0,.3)}.custom-navbar li.active .active-bar{display:flex}.custom-navbar>ul>li.view-border::before{content:"";width:94%;height:94%;border:2px dashed var(--navbar-foreground);position:absolute;top:3%;left:3%;box-sizing:border-box}.custom-navbar>ul>li:not(.disabled){cursor:pointer}.custom-navbar>ul>li.disabled a{cursor:default}.custom-navbar>ul>li:not(.disabled):hover{background:rgba(0,0,0,.1)}.custom-navbar .main-content{font-size:10pt;height:100%;display:flex;align-items:center;padding:0 10px;color:var(--navbar-foreground);user-select:none}.custom-navbar .active .main-content{font-weight:700;font-size:11pt}.custom-navbar .main-content:hover{color:var(--navbar-foreground)!important}.custom-navbar .popup{position:absolute;top:100%;left:50%;padding:8px;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;pointer-events:none;opacity:0;transform:translateY(-6px) translateX(-50%);cursor:default}.custom-navbar .popup.no-padding{padding:0}.custom-navbar .popup.transparent{background-color:transparent!important;box-shadow:none}.custom-navbar li.left-side .popup{left:0;transform:translateY(-6px) translateX(10%)}.custom-navbar li.right-side .popup{left:100%;transform:translateY(-6px) translateX(-90%)}.custom-navbar.dark .popup{box-shadow:rgba(0,0,0,.3) 0 4px 8px 0}.custom-navbar a,.custom-navbar a:hover{color:inherit!important;text-decoration:none}.custom-navbar form{height:100%;display:flex;align-items:center;position:relative;--submit-button-size:30px;opacity:.4;margin:0}.custom-navbar.fill:not(.transparent) form{opacity:.8}.custom-navbar form:focus-within,.custom-navbar form:hover,.custom-navbar.fill form:focus-within,.custom-navbar.fill form:hover{opacity:1}.custom-navbar form input{border:none;height:60%;background:0 0;border-bottom:1.5px solid!important;color:var(--navbar-foreground);box-sizing:border-box;width:250px;padding-right:var(--submit-button-size);padding-left:4px}.custom-navbar form input:focus{border-bottom-color:var(--navbar-foreground)!important;outline:0!important}.custom-navbar form button[type=submit]{background:0 0;border:none;padding:4px;cursor:pointer;height:var(--submit-button-size);width:var(--submit-button-size);position:absolute;right:0;top:50%;transform:translateY(-50%)}.custom-navbar form input[type=text]::placeholder{color:var(--navbar-foreground)!important;opacity:.9}.custom-navbar .user-face-container{position:relative;height:calc(var(--navbar-height) - 16px);width:calc(var(--navbar-height) - 16px)}.custom-navbar .user-face,.custom-navbar .user-pendant{position:absolute;width:100%;height:100%}.custom-navbar .user-face{background-color:transparent;background-size:contain;border-radius:50%}.custom-navbar .user-pendant{background-color:transparent;background-size:cover;width:170%;height:170%;top:-12px;left:-12px;opacity:0;pointer-events:none}.custom-navbar .user-info-panel{width:240px;font-size:12px}.custom-navbar .user-info-panel .circle{position:relative;width:var(--navbar-icon-size);height:var(--navbar-icon-size);opacity:.7}.custom-navbar .user-info-panel .circle .mdi{position:absolute;top:0;left:0}.custom-navbar .user-info-panel .mdi-circle~.mdi{filter:invert(1);font-size:calc(var(--navbar-icon-size) - 10px);line-height:calc(var(--navbar-icon-size) - 10px);transform:translate(5px,5px)}.custom-navbar .user-info-panel i{font-size:var(--navbar-icon-size);font-style:normal;line-height:var(--navbar-icon-size)}.custom-navbar .user-info-panel .logged-in{display:flex;flex-direction:column;align-items:center;justify-content:space-between}.custom-navbar .user-info-panel .items,.custom-navbar .user-info-panel .row{align-self:stretch;display:flex;justify-content:space-between;align-items:center}.custom-navbar .user-info-panel .row{margin:0 10px;width:auto!important}.custom-navbar .user-info-panel .row::after{content:none!important}.custom-navbar .user-info-panel .row.level-info{margin-bottom:-5px}.custom-navbar .user-info-panel .privileges{justify-content:center}.custom-navbar .user-info-panel .privileges>*{font-size:11px;background-color:#8882;padding:2px 4px;margin:0 2px;border-radius:4px;line-height:normal;cursor:pointer}.custom-navbar .user-info-panel .privileges>.received{cursor:default;opacity:.5}.custom-navbar .user-info-panel .privileges>:not(.received):hover{background-color:#8884}.custom-navbar .user-info-panel .operation{height:36px;display:flex;align-items:center;justify-content:center;position:relative;align-self:stretch}.custom-navbar .user-info-panel .operation:hover{background-color:rgba(0,0,0,.1)}.custom-navbar .user-info-panel .operation .icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);background:0 0}.custom-navbar .user-info-panel .item>i{opacity:.7;font-size:14pt}.custom-navbar .user-info-panel .item{display:flex;flex-direction:column;justify-content:space-around;align-items:center;height:48px;flex:1}.custom-navbar .user-info-panel .item span{font-size:14px;font-weight:700;opacity:.7}.custom-navbar .user-info-panel .item>i:nth-child(2){font-size:18px;line-height:18px}.custom-navbar .user-info-panel .name,.custom-navbar .user-info-panel .welcome{font-size:16px;font-weight:700;margin:46px 0 16px;text-align:center;color:inherit}.custom-navbar .user-info-panel .name{margin:62px 0 0}.custom-navbar .user-info-panel .type{font-size:11px;opacity:.5;margin:6px 0}.custom-navbar .user-info-panel .separator{height:1px;align-self:stretch;margin:5px 10px;background:rgba(0,0,0,.1)}.custom-navbar .user-info-panel .logout{margin-top:5px}.custom-navbar .user-info-panel .logout:hover{color:inherit!important}.custom-navbar .user-info-panel .level-progress-thumb{width:100%;height:100%;background:var(--theme-color);transform-origin:left}.custom-navbar .user-info-panel .level-progress-label{font-size:11px}.custom-navbar .user-info-panel .stats{display:flex;align-items:center;align-self:stretch;margin:0 10px;line-height:normal}.custom-navbar .user-info-panel .stats-item{padding:6px 0;flex:1;display:flex;flex-direction:column;align-items:center;transition:none}.custom-navbar .user-info-panel .stats-item:hover{color:var(--theme-color)!important}.custom-navbar .user-info-panel .stats-item .stats-number{font-weight:700;margin-bottom:4px;font-size:14px;transition:none}.custom-navbar.dark .user-info-panel .separator{background:rgba(255,255,255,.1)}.custom-navbar .grey-button,.custom-navbar .theme-button{align-self:stretch;height:36px;display:flex;align-items:center;justify-content:center}.custom-navbar .grey-button{background:#ededed;color:inherit!important}.custom-navbar .grey-button:hover{background:#ddd}.custom-navbar.dark .grey-button{background:#383838}.custom-navbar.dark .grey-button:hover{background:#333}.custom-navbar .theme-button{background:var(--theme-color);color:var(--foreground-color)!important}.custom-navbar .theme-button:hover{background:var(--theme-color-90);color:var(--foreground-color)!important}.custom-navbar li:hover .user-face,.custom-navbar li:hover .user-pendant{transform:scale(2) translateY(10px);z-index:100;opacity:1}.custom-navbar .video-list{width:280px;font-size:12px}.custom-navbar .video-list li:not(.history-item):not(.more):not(.loading)::after,.custom-navbar .video-list li:not(.history-item):not(.more):not(.loading)::before{content:"";transition:.3s cubic-bezier(.22,.61,.36,1) .1s;width:calc(100% - 16px);height:2px;border-radius:1px;background:linear-gradient(to right,var(--theme-color),var(--theme-color-50));opacity:1;position:absolute;bottom:0;left:8px;pointer-events:none}.custom-navbar .video-list li:not(.history-item):not(.more):not(.loading)::after{width:0;background:linear-gradient(to right,var(--theme-color),var(--theme-color-50))}.custom-navbar .video-list li:not(.history-item):not(.more):not(.loading):hover::after{width:calc(100% - 16px)}.custom-navbar.dark .video-list li:not(.history-item):not(.more):not(.loading)::after{background:linear-gradient(to right,var(--theme-color-60),var(--theme-color))}.custom-navbar .video-list li:not(.history-item):not(.more):not(.loading)::before{background:#8882}.custom-navbar .video-list li{position:relative}.custom-navbar .video-list li:not(.more) a{padding:12px 16px;margin:0;box-sizing:border-box;transition:.2s ease-out .1s;display:block;width:100%;height:100%;line-height:1.5}.custom-navbar.compact .video-list li:not(.more) a{padding:6px 8px}.custom-navbar .video-list li:not(.loading):hover .title{color:var(--theme-color)}.custom-navbar .video-list li.more a{width:100%;padding:8px 0;display:flex;justify-content:center;font-weight:700}.custom-navbar.compact .video-list li.more a{padding:6px 0}.custom-navbar .video-list li.more:hover{border-color:var(--theme-color);color:var(--theme-color)!important}.custom-navbar .video-list .loading{display:flex;justify-content:center;padding:8px;cursor:default}.custom-navbar .video-list.loaded .loading:not(.empty){display:none}.custom-navbar .video-list.history .history-item{border:none!important}.custom-navbar.compact .video-list li:not(.more) a,.custom-navbar.compact .video-list.history .history-item .title{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.custom-navbar .video-list li:not(.history-item):not(.more):hover a{color:var(--theme-color)!important}.custom-navbar .video-list.history li:not(.more) a{justify-content:space-between;position:relative;display:flex;padding:13px 16px!important}.custom-navbar.compact .video-list.history li:not(.more) a{padding:7px 8px!important}.custom-navbar .video-list.history a .description{opacity:.6;margin-left:4px;white-space:nowrap}.custom-navbar .video-list.history a .progress.foreground{height:2px;border-radius:1px;background:linear-gradient(to right,var(--theme-color),var(--theme-color-50));width:0;transition:.3s cubic-bezier(.22,.61,.36,1) .1s}.custom-navbar .video-list.history a:hover .progress.foreground{width:var(--progress)}.custom-navbar.dark .video-list.history a .progress.foreground{background:linear-gradient(to right,var(--theme-color-60),var(--theme-color))}.custom-navbar .video-list.history a .progress.background{position:absolute;bottom:0;left:8px;height:2px;width:calc(100% - 16px);transform-origin:left;border-radius:1px;background:#8882}.custom-navbar .notify-count{position:absolute;left:50%;top:0;background-color:var(--theme-color);padding:0 8px;display:flex;justify-content:center;font-size:11px;transform:translateX(-50%);opacity:0;line-height:14px;white-space:nowrap;color:var(--foreground-color);border-radius:0 0 8px 8px}.custom-navbar .notify-count:not(:empty):not(.hidden){opacity:1}.custom-navbar .notify-count.dot{color:transparent;border-radius:50%;width:8px;height:8px;padding:0;top:2px}.custom-navbar.fill .notify-count{background-color:rgba(0,0,0,.3)}.custom-navbar .blur-layer-container{overflow:hidden;display:none;width:100%;height:100%;position:absolute;top:0;left:0}.custom-navbar.blur:not(.transparent) .blur-layer-container{display:flex}.custom-navbar .blur-layer{width:100%;height:100%;background-position:center 0;background-repeat:no-repeat;filter:blur(36px);opacity:var(--navbar-blur-opacity)}.custom-navbar .blur-layer.left-pad{position:absolute;left:0;top:0;transform:translateX(-100%) scaleX(-1);width:100%;height:100%}.custom-navbar .blur-layer.right-pad{position:absolute;left:0;top:0;transform:translateX(100%) scaleX(-1);width:100%;height:100%}.custom-navbar.dark .blur-layer{filter:blur(54px)}.custom-navbar ol{color:#000}.custom-navbar.dark ol{color:#eee}.custom-navbar em.suggest-highlight{color:var(--theme-color);font-style:normal}.custom-navbar .copy-tip{position:absolute;top:calc(100% + 4px);left:50%;pointer-events:none;opacity:0;transform:translateX(-50%) translateY(-8px);border-radius:4px;background-color:#000a;color:#fff;padding:6px 8px}.custom-navbar .copy-tip.show{transform:translateX(-50%) translateY(0);opacity:1}.custom-navbar .search-list-item{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;cursor:pointer;display:flex;align-items:center}.custom-navbar .search-list-item-text{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;flex:1;padding:6px 0 6px 6px}.custom-navbar .search-list-item .delete-history{opacity:.5;padding:6px 6px 6px 0;line-height:1}.custom-navbar .search-list-item .delete-history:hover{opacity:1}.custom-navbar .search-list-item:focus-within,.custom-navbar .search-list-item:hover{background-color:#8883}.custom-navbar .search-list-item.clear-history{text-align:center;font-weight:700;background-color:#8881;margin-top:8px;display:flex;align-items:center;justify-content:center;padding:6px}.custom-navbar .search-list-item.clear-history .mdi{line-height:1;margin-right:6px}.custom-navbar .search-list-item.clear-history:focus-within,.custom-navbar .search-list-item.clear-history:hover{color:var(--theme-color);background-color:#8883}.custom-navbar .search-list{width:250px}.custom-navbar .activity-popup{width:380px;font-size:9pt}.custom-navbar .activity-tabs{display:flex;padding:12px 12px 16px 18px;justify-content:space-between;align-items:center}.custom-navbar .activity-tabs .view-all,.custom-navbar .subscriptions-tabs .view-all{background-color:#8882;padding:4px 6px 4px 10px;height:28px;box-sizing:border-box;border-radius:14px;display:flex;align-items:center}.custom-navbar .activity-tabs .view-all i{font-size:14pt;margin-left:4px}.custom-navbar .subscriptions-tabs .view-all i{font-size:12pt;margin-left:4px}.custom-navbar .activity-tabs .view-all:hover,.custom-navbar .subscriptions-tabs .view-all:hover{background-color:#8884}.custom-navbar .activity-tab{position:relative;cursor:pointer}.custom-navbar .activity-tab.selected{opacity:1;transform:scale(1.2)}.custom-navbar .activity-tab .tab-name{line-height:normal;opacity:.5}.custom-navbar .activity-tab.selected .tab-name{opacity:1;font-weight:700}.custom-navbar .activity-tab[data-count]::before{content:attr(data-count);position:absolute;top:0;left:50%;transform:translateX(-50%) translateY(-100%);font-size:10px;font-weight:400;line-height:1;background-color:#8884;padding:2px 4px;border-radius:10px;white-space:nowrap}.custom-navbar .activity-tab::after,.custom-navbar .subscriptions .tab::after{content:"";width:calc(80%);height:2px;border-radius:1px;position:absolute;background-color:var(--theme-color);left:10%;bottom:-4px;transform:scaleX(0);transition:.2s ease-out}.custom-navbar .activity-tab.selected::after,.custom-navbar .subscriptions .tab.selected::after{transform:scaleX(1)}.custom-navbar .activity-popup-content{overflow:auto;overscroll-behavior:contain;height:500px;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:space-between;scrollbar-width:none!important}.custom-navbar .activity-popup-content::-webkit-scrollbar,.custom-navbar .subscriptions .content::-webkit-scrollbar{width:0!important}.custom-navbar .activity-popup-content .view-more{display:flex;align-items:center;flex-shrink:0;position:-webkit-sticky;position:sticky;bottom:0;left:0;justify-content:center;padding:6px 12px;background-color:#fffe;transform:translateY(-6px);box-shadow:rgba(0,0,0,.12) 0 4px 8px 0;cursor:pointer;height:28px;border-radius:14px;box-sizing:border-box;z-index:2}.custom-navbar .activity-popup-content .view-more:hover{background-color:#fff}.custom-navbar.dark .activity-popup-content .view-more:hover{background-color:#333}.custom-navbar .activity-popup-content .view-more .mdi{line-height:1;margin-left:8px;font-size:12pt}.custom-navbar .activity-popup-content .loading,.custom-navbar .bangumi-subscriptions .empty,.custom-navbar .bangumi-subscriptions .loading{height:100%;align-self:center;display:flex;align-items:center;justify-content:center}.custom-navbar .activity-popup-content .loading .mdi,.custom-navbar .bangumi-subscriptions .loading .mdi{line-height:1;margin-right:6px}.custom-navbar .video-activity{padding:0 12px;display:flex;justify-content:space-between;align-self:stretch}.custom-navbar .video-activity.center{height:100%;flex-direction:column;justify-content:center;align-items:center}.custom-navbar .video-activity-card{--card-width:172px;width:var(--card-width);display:flex;flex-direction:column;box-shadow:rgba(0,0,0,.12) 0 4px 8px 0;margin-bottom:12px;break-inside:avoid;flex-shrink:0}.custom-navbar.dark .activity-popup-content .view-more,.custom-navbar.dark .column-card,.custom-navbar.dark .video-activity-card{box-shadow:rgba(0,0,0,.3) 0 4px 8px 0;background-color:#2d2d2d}.custom-navbar .video-activity-card .cover{width:var(--card-width);background-color:#8884;height:calc(var(--card-width)/ 16 * 10);object-fit:cover;display:block;min-height:100px}.custom-navbar .video-activity-card .title{font-size:10pt;font-weight:700;margin:8px 8px 2px;color:inherit;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.5;max-height:3em;word-break:break-all}.custom-navbar .video-activity-card .title:hover,.custom-navbar .video-activity-card .up:hover .name{color:var(--theme-color)}.custom-navbar .video-activity-card .up{display:flex;justify-content:space-between;align-items:center;margin:6px 8px;border-radius:13px;padding:2px}.custom-navbar .video-activity-card .up:hover{background-color:#8882}.custom-navbar .video-activity-card .up .face{width:24px;border-radius:50%;background-color:#8884}.custom-navbar .video-activity-card .up .name{padding:0 8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.custom-navbar .video-activity-card .cover-container{position:relative}.custom-navbar .video-activity-card .time,.custom-navbar .video-activity-card .watchlater{position:absolute;bottom:4px;display:flex;align-items:center;background-color:#000a;color:#fff;padding:0 8px;height:20px;border-radius:10px;box-sizing:border-box;opacity:0}.custom-navbar .video-activity-card:hover .time,.custom-navbar .video-activity-card:hover .watchlater{opacity:1}.custom-navbar .video-activity-card .time{left:4px}.custom-navbar .video-activity-card .watchlater{padding:0 8px 0 3px;right:4px;font-size:11px}.custom-navbar .video-activity-card .watchlater .mdi{line-height:1;margin-right:4px;font-size:16px}.custom-navbar .bangumi-activity{display:flex;flex-direction:column;padding-top:4px;width:100%}.custom-navbar .bangumi-activity.center{height:100%;justify-content:center;align-items:center}.custom-navbar .bangumi-card{--cover-width:100px;margin:0 12px 12px;box-shadow:rgba(0,0,0,.12) 0 2px 8px 0;display:grid;grid-template-areas:"cover epTitle" "cover title";grid-template-columns:var(--cover-width) 1fr;grid-template-rows:6fr 5fr;position:relative;flex-shrink:0}.custom-navbar.dark .bangumi-card,.custom-navbar.dark .live-card{box-shadow:rgba(0,0,0,.3) 0 2px 8px 0;background-color:#2d2d2d}.custom-navbar .bangumi-card .up{grid-area:title;display:flex;align-items:center;padding:0 12px;align-self:start;overflow:hidden}.custom-navbar .bangumi-card .up .cover{height:18px;border-radius:50%}.custom-navbar .bangumi-card .up .title{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0 6px;line-height:normal}.custom-navbar .bangumi-card .ep-title{grid-area:epTitle;font-size:11pt;font-weight:700;padding:0 12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;align-self:center;color:inherit;line-height:normal}.custom-navbar .bangumi-card:hover .ep-title{color:var(--theme-color)}.custom-navbar .bangumi-card .ep-cover{width:var(--cover-width);min-height:62.5px;background-color:#8884;grid-area:cover}.custom-navbar .column-activity{display:flex;flex-direction:column;align-items:stretch;padding:0 12px}.custom-navbar .column-activity.center{height:100%;align-items:center;justify-content:center}.custom-navbar .column-card{display:flex;flex-direction:column;margin-bottom:12px;box-shadow:rgba(0,0,0,.12) 0 4px 8px 0;position:relative;flex-shrink:0}.custom-navbar .column-card .up{position:absolute;left:8px;bottom:6px;padding:2px;display:flex;align-items:center;background-color:#000a;border-radius:14px;height:28px;box-sizing:border-box}.custom-navbar .column-card .face{border-radius:50%;height:24px}.custom-navbar .column-card .up .name{margin:0 6px;color:#fff}.custom-navbar .column-card .title{padding:10px 10px 0;font-size:11pt;font-weight:700;color:inherit;line-height:normal}.custom-navbar .column-card:hover .title{color:var(--theme-color)}.custom-navbar .column-card .description{margin:8px 10px;max-height:3em;overflow:hidden;text-overflow:ellipsis;word-break:break-all;line-height:1.5;-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box}.custom-navbar .column-card .covers{position:relative;display:flex}.custom-navbar .column-card .cover{width:0;flex-grow:1;object-fit:cover}.custom-navbar .live-activity{display:flex;flex-direction:column;align-items:stretch;width:100%;padding-top:4px}.custom-navbar .live-activity.center{height:100%;align-items:center;justify-content:center}.custom-navbar .live-card{margin:0 12px 12px;box-shadow:rgba(0,0,0,.12) 0 2px 8px 0;display:grid;grid-template-areas:"face title" "face name";grid-template-columns:48px 1fr;grid-template-rows:6fr 5fr;height:52px;border-radius:26px;box-sizing:border-box;padding:2px;width:auto;flex-shrink:0}.custom-navbar .live-card .face{grid-area:face;border-radius:50%;height:48px}.custom-navbar .live-card .live-title{grid-area:title;font-size:11pt;font-weight:700;align-self:center;padding:0 12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:inherit;line-height:normal}.custom-navbar .live-card:hover .live-title{color:var(--theme-color)}.custom-navbar .live-card .name{grid-area:name;align-self:start;padding:0 12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:normal}.custom-navbar .activity-content-enter-active,.custom-navbar .activity-content-leave-active,.custom-navbar .subscriptions-content-enter-active,.custom-navbar .subscriptions-content-leave-active{transition:.2s ease-out}.custom-navbar .activity-content-enter,.custom-navbar .activity-content-leave-to,.custom-navbar .subscriptions-content-enter,.custom-navbar .subscriptions-content-leave-to{opacity:0;transform:translateY(12px)}.custom-navbar .bangumi-card.new::before,.custom-navbar .column-card.new::before,.custom-navbar .video-activity-card.new .cover-container::before{content:"NEW";position:absolute;top:4px;left:4px;background-color:var(--theme-color);color:var(--foreground-color);padding:0 6px;height:18px;border-radius:9px;font-weight:700;font-size:11px;line-height:18px;z-index:1}.custom-navbar .column-card.new::before{left:unset;right:8px;top:8px;height:20px;border-radius:10px;line-height:20px;font-size:12px;padding:0 8px}.custom-navbar .subscriptions{width:380px;font-size:9pt}.custom-navbar .subscriptions .tab-placeholder{flex-grow:1}.custom-navbar .subscriptions .tab{opacity:.5;margin-right:24px;position:relative;line-height:1.4;cursor:pointer}.custom-navbar .subscriptions .tab.selected{opacity:1;font-weight:700;transform:scale(1.2)}.custom-navbar .subscriptions .content{padding:8px 12px;height:500px;overflow:auto;overscroll-behavior:contain;scrollbar-width:none!important}.custom-navbar .subscriptions-tabs{margin:12px 12px 8px 18px;display:flex;align-items:center}.custom-navbar .bangumi-subscriptions{display:flex;flex-direction:column}.custom-navbar .bangumi-subscriptions.center{height:100%}.custom-navbar .bangumi-subscriptions-card{position:relative;display:flex;margin-bottom:12px;flex-shrink:0}body.dark .custom-navbar .bangumi-subscriptions-card{background-color:#2d2d2d}.custom-navbar .bangumi-subscriptions-card .cover{height:64px;width:64px}.custom-navbar .bangumi-subscriptions-card .card-info{flex-grow:1;display:flex;flex-direction:column;align-items:flex-start;padding:0 12px;max-width:calc(100% - 24px - 64px);box-sizing:content-box}.custom-navbar .bangumi-subscriptions-card .info{padding:2px;background-color:#8882;font-size:12pt;border-radius:14px;line-height:1}.custom-navbar .bangumi-subscriptions-card .info:hover{background-color:#8884}.custom-navbar .bangumi-subscriptions-card .progress-row{flex-grow:1;display:flex;justify-content:space-between;align-self:stretch;align-items:center}.custom-navbar .bangumi-subscriptions-card .status{padding:0 4px;background-color:#8882;border-radius:4px;opacity:.75}.custom-navbar .bangumi-subscriptions-card .status.status-2{background-color:var(--theme-color-10);opacity:1}.custom-navbar .bangumi-subscriptions-card .progress{white-space:nowrap;width:0;flex-grow:1;margin:0 8px;overflow:hidden;text-overflow:ellipsis}.custom-navbar .bangumi-subscriptions-card .title{font-size:11pt;font-weight:700;padding-top:8px;color:inherit;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:100%;margin:0}.custom-navbar .bangumi-subscriptions-card:hover .title{color:var(--theme-color)}.round-corner .custom-navbar .popup,.round-corner .custom-navbar .popup iframe{border-radius:var(--large-corner-radius)}.round-corner #custom-navbar-home-popup .category-item,.round-corner #custom-navbar-home-popup .category-item .popup{border-radius:var(--corner-radius)}.round-corner .custom-navbar .video-list li.more,.round-corner .user-info-panel .login,.round-corner .user-info-panel .logout{border-radius:0 0 var(--corner-radius) var(--corner-radius)}.round-corner .custom-navbar-settings{border-radius:var(--large-corner-radius)}.round-corner .custom-navbar .search-list-item{border-radius:var(--corner-radius)}.round-corner .custom-navbar .bangumi-subscriptions-card{border-radius:var(--large-corner-radius);box-shadow:rgba(0,0,0,.12) 0 2px 8px 0}.round-corner .custom-navbar .bangumi-subscriptions-card .cover{border-radius:var(--large-corner-radius) 0 0 var(--large-corner-radius)}.round-corner .custom-navbar .column-card .cover:first-child{border-top-left-radius:var(--large-corner-radius)}.round-corner .custom-navbar .column-card .cover:nth-last-child(2){border-top-right-radius:var(--large-corner-radius)}.round-corner .custom-navbar .bangumi-card,.round-corner .custom-navbar .column-card,.round-corner .custom-navbar .video-activity-card{border-radius:var(--large-corner-radius)}.round-corner .custom-navbar .video-activity-card .cover{border-radius:var(--large-corner-radius) var(--large-corner-radius) 0 0}.round-corner .custom-navbar .bangumi-activity .ep-cover{border-radius:var(--large-corner-radius) 0 0 var(--large-corner-radius)}.custom-navbar-settings{display:flex;flex-direction:column;pointer-events:none;opacity:0;width:370px;position:fixed;top:50%;left:50%;transform:translate(-50%,-46%) scale(.95);z-index:10001;background:var(--navbar-background);padding-top:16px;box-shadow:#0002 0 1px 10px 1px;font-size:16px;line-height:1.5}.custom-navbar-settings.dark{--navbar-background:#222;--navbar-foreground:#eee;box-shadow:#0004 0 2px 10px 1px}.custom-navbar-settings h1{color:var(--navbar-foreground);font-size:16pt;font-weight:700}.custom-navbar-settings.show{pointer-events:initial;transform:translate(-50%,-46%) scale(1);opacity:1}.custom-navbar-settings .header,.custom-navbar-settings .orders{display:flex;justify-content:space-between;align-items:center}.custom-navbar-settings .header{padding:0 24px;font-size:9pt}.custom-navbar-settings .header .header-blank,.custom-navbar-settings .orders{flex-grow:1}.custom-navbar-settings .order-list{padding:0 24px;max-height:60vh;overflow:auto;overscroll-behavior:contain;list-style:none;width:100%;margin:16px 0}.custom-navbar-settings button{border:none;background-color:transparent;color:var(--navbar-foreground);padding:8px;cursor:pointer;font-size:14pt}.custom-navbar-settings button:hover{color:var(--theme-color)}.custom-navbar-settings .order-list li .mdi-menu{padding:8px}.custom-navbar-settings .order-list i{font-size:14pt}.custom-navbar-settings .order-list i.mdi-menu{cursor:move}.custom-navbar-settings .order-list li{color:var(--navbar-foreground);font-size:12pt;display:flex!important;justify-content:space-between;align-items:center;user-select:none;transition:opacity .2s ease-out}.custom-navbar-settings .order-list li.hidden{opacity:.5}.custom-navbar-settings .paddings{display:flex;align-items:center;justify-content:space-between;padding:16px 32px;color:var(--navbar-foreground)}.custom-navbar-settings .paddings span{min-width:40px}.custom-navbar-settings .paddings input{flex-grow:1;margin-right:16px;-webkit-appearance:none;background:0 0;width:100%}.custom-navbar-settings .paddings input::-webkit-slider-thumb{-webkit-appearance:none;height:18px;width:18px;background:var(--theme-color);border-radius:50%;box-shadow:0 2px 8px 0 var(--theme-color-50);cursor:pointer;border:none;transform:translateY(-7px)}.custom-navbar-settings .paddings input::-moz-range-thumb{-webkit-appearance:none;height:18px;width:18px;background:var(--theme-color);border-radius:50%;box-shadow:0 2px 8px 0 var(--theme-color-50);cursor:pointer;border:none}.custom-navbar-settings .paddings input::-webkit-slider-runnable-track{width:100%;background:#8884;height:4px}.custom-navbar-settings .paddings input::-moz-range-track{width:100%;background:#8884;height:4px}#custom-navbar-home-popup{max-height:80vh;display:flex;flex-direction:column;flex-wrap:wrap;width:350px}#custom-navbar-home-popup .category-item{font-size:12pt;padding:8px 16px;cursor:pointer;position:relative}#custom-navbar-home-popup .category-item.loading{font-size:10pt;cursor:initial;display:flex;align-items:center;justify-content:center}#custom-navbar-home-popup .category-item:not(.loading):hover{background-color:#0001}#custom-navbar-home-popup .category-item a{display:flex;justify-content:space-between;align-items:center}#custom-navbar-home-popup .category-item svg{width:25px;height:25px;fill:currentColor;margin-right:10px}#custom-navbar-home-popup .category-item div{flex:1 0 auto}#custom-navbar-home-popup .category-item.main{min-width:150px}#custom-navbar-home-popup .category-item .popup{z-index:10002;width:max-content;transform:scaleX(0);transform-origin:left;padding:8px;left:100%;top:0;transition-delay:.3s;pointer-events:initial}#custom-navbar-home-popup .category-item span{opacity:.5}@media screen and (min-height:1000px){#custom-navbar-home-popup{flex-wrap:nowrap;width:250px}}.custom-navbar .popup .watchlater-list{min-height:200px;max-height:600px;width:380px;font-size:12px;display:flex;flex-flow:column nowrap;justify-content:space-between}.custom-navbar .popup .watchlater-list .empty-tip,.custom-navbar .popup .watchlater-list .loading-tip{opacity:0;pointer-events:none;position:absolute;top:50%;left:50%;transform:translateX(-50%) translateY(-50%);display:flex;align-items:center}.custom-navbar .popup .watchlater-list .empty-tip .mdi,.custom-navbar .popup .watchlater-list .loading-tip .mdi{margin-right:6px}.custom-navbar .popup .watchlater-list .empty-tip,.custom-navbar .popup .watchlater-list.loading .loading-tip{opacity:1}.custom-navbar .popup .watchlater-list.loading>:not(.loading-tip){opacity:0}.custom-navbar .popup .watchlater-list .mdi{line-height:1;font-size:18px}.custom-navbar .popup .watchlater-list .round-button{box-sizing:border-box;height:28px;border-radius:14px;display:flex;align-items:center;background-color:#8882;justify-content:center;cursor:pointer;width:28px}.custom-navbar .popup .watchlater-list .round-button:hover{background-color:#8884}.custom-navbar .popup .watchlater-list .floating{box-sizing:border-box;height:20px;border-radius:10px;display:flex;align-items:center;background-color:#000C;color:#fff;justify-content:center;cursor:pointer}.custom-navbar .popup .watchlater-list .header{display:flex;align-items:center;justify-content:space-between;margin:16px 12px}.custom-navbar .popup .watchlater-list .header .search{position:relative;flex-grow:1;margin-right:16px}.custom-navbar .popup .watchlater-list .header .search input{width:100%;padding:4px;border:none;outline:0!important;color:inherit;background-color:transparent;border-radius:4px}.custom-navbar .popup .watchlater-list .header .search input::-webkit-input-placeholder{color:inherit!important;opacity:.3}.custom-navbar .popup .watchlater-list .header .search::after{content:"";position:absolute;top:calc(100%);left:0;width:100%;height:2px;border-radius:2px;transition:.24s ease-out;background-color:#8882}.custom-navbar .popup .watchlater-list .header .search.not-empty::after,.custom-navbar .popup .watchlater-list .header .search:focus-within::after{background-color:var(--theme-color)}.custom-navbar .popup .watchlater-list .header .operations{display:flex;align-items:center}.custom-navbar .popup .watchlater-list .header .operations .round-button:not(:last-child){margin-right:4px}.custom-navbar .popup .watchlater-list .header .more-info{display:flex;align-items:center;box-sizing:border-box;height:28px;border-radius:14px;padding:4px 6px 4px 10px;background-color:#8882}.custom-navbar .popup .watchlater-list .header .more-info:hover{background-color:#8884}.custom-navbar .popup .watchlater-list .header .more-info .mdi{margin-left:8px}.custom-navbar .popup .watchlater-list .cards{flex:1;overflow:auto;overscroll-behavior:contain;scroll-behavior:smooth;position:relative;scrollbar-width:none!important;padding:0 12px 12px}.custom-navbar .popup .watchlater-list .cards::-webkit-scrollbar{height:0!important;width:0!important}.custom-navbar .popup .watchlater-list .cards-enter,.custom-navbar .popup .watchlater-list .cards-leave-to{opacity:0;transform:translateY(-16px) scale(.9)}.custom-navbar .popup .watchlater-list .cards-leave-active{transition:.24s cubic-bezier(.22,.61,.36,1);position:absolute}.custom-navbar .popup .watchlater-list .cards .watchlater-card{cursor:pointer;flex-shrink:0;border-radius:8px;box-shadow:0 4px 8px 0 #0001;color:#000;background-color:#fff;display:grid;grid-template:"cover title" 2fr "cover info" 1fr/130px 1fr;height:85px}body.dark .custom-navbar .popup .watchlater-list .cards .watchlater-card{background-color:#282828;color:#eee}.custom-navbar .popup .watchlater-list .cards .watchlater-card:not(:last-child){margin-bottom:12px}.custom-navbar .popup .watchlater-list .cards .watchlater-card:hover .cover{transform:scale(1.05)}.custom-navbar .popup .watchlater-list .cards .watchlater-card .cover-container{grid-area:cover;overflow:hidden;border-radius:8px 0 0 8px;position:relative}.custom-navbar .popup .watchlater-list .cards .watchlater-card .cover-container .remove{top:6px;left:6px;width:20px}.custom-navbar .popup .watchlater-list .cards .watchlater-card .cover-container .remove .mdi{font-size:16px}.custom-navbar .popup .watchlater-list .cards .watchlater-card .cover-container .duration{left:6px;bottom:6px;padding:0 6px}.custom-navbar .popup .watchlater-list .cards .watchlater-card .cover-container .viewed{white-space:nowrap;right:6px;top:6px;padding:0 6px}.custom-navbar .popup .watchlater-list .cards .watchlater-card .cover-container .floating{position:absolute;opacity:0;font-size:11px}.custom-navbar .popup .watchlater-list .cards .watchlater-card .cover-container .cover{object-fit:cover}.custom-navbar .popup .watchlater-list .cards .watchlater-card:hover .floating{opacity:1}.custom-navbar .popup .watchlater-list .cards .watchlater-card .title{grid-area:title;font-size:13px;font-weight:700;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;max-height:3em;word-break:break-all;line-height:1.5;overflow:hidden;margin-top:8px;padding:0 10px}.custom-navbar .popup .watchlater-list .cards .watchlater-card .title:hover{color:var(--theme-color)!important}.custom-navbar .popup .watchlater-list .cards .watchlater-card .up{flex:0 1 auto;padding:2px 10px 2px 2px;margin:0 8px 6px;justify-self:start;align-self:center;max-width:calc(100% - 16px);display:flex;align-items:center;background-color:#8882;box-sizing:border-box;height:24px;border-radius:12px}.custom-navbar .popup .watchlater-list .cards .watchlater-card .up:hover{background-color:#8884}.custom-navbar .popup .watchlater-list .cards .watchlater-card .up .face{border-radius:50%;margin-right:6px;height:20px;width:20px}.custom-navbar .popup .watchlater-list .cards .watchlater-card .up .name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:11px}.custom-navbar .popup .watchlater-list .cards .watchlater-card .up:hover .name{color:var(--theme-color)}.custom-navbar .popup .watchlater-list .undo{position:absolute;bottom:16px;left:50%;opacity:0;transform:translateX(-50%) translateY(8px)}.custom-navbar .popup .watchlater-list .undo.show{opacity:1;transform:translateX(-50%) translateY(0)}.custom-navbar .favorites-list{width:380px;height:600px;font-size:12px;display:flex;align-items:stretch;flex-direction:column;justify-content:center}.custom-navbar .favorites-list .dropdown-menu{max-height:500px;overflow:auto}.custom-navbar .favorites-list .empty-tip,.custom-navbar .favorites-list .loading-tip{display:flex;justify-content:center;width:100%}.custom-navbar .favorites-list>.loading-tip{display:none}.custom-navbar .favorites-list .mdi{line-height:1;font-size:18px}.custom-navbar .favorites-list.loading>.loading-tip{display:flex}.custom-navbar .favorites-list.loading>:not(.loading-tip){display:none}.custom-navbar .favorites-list .content{display:flex;align-items:stretch;flex-direction:column;scrollbar-width:none!important;justify-content:space-between;flex-grow:1;overflow:auto}.custom-navbar .favorites-list .content::-webkit-scrollbar{height:0!important;width:0!important}.custom-navbar .favorites-list .content .floating{box-sizing:border-box;height:20px;border-radius:10px;display:flex;align-items:center;background-color:#000c;color:#fff;justify-content:center;cursor:pointer}.custom-navbar .favorites-list .content .header{display:flex;align-items:center;justify-content:space-between;margin:16px 12px}.custom-navbar .favorites-list .content .header .search{position:relative;flex-grow:1;margin-right:16px}.custom-navbar .favorites-list .content .header .search input{width:100%;padding:4px;border:none;outline:0!important;color:inherit;background-color:transparent;border-radius:4px}.custom-navbar .favorites-list .content .header .search input::-webkit-input-placeholder{color:inherit!important;opacity:.3}.custom-navbar .favorites-list .content .header .search::after{content:"";position:absolute;top:calc(100%);left:0;width:100%;height:2px;border-radius:2px;transition:.24s ease-out;background-color:#8882}.custom-navbar .favorites-list .content .header .search.not-empty::after,.custom-navbar .favorites-list .content .header .search:focus-within::after{background-color:var(--theme-color)}.custom-navbar .favorites-list .content .header .list-select{flex-shrink:0;height:26px}.custom-navbar .favorites-list .content .header .more-info{display:flex;align-items:center;box-sizing:border-box;height:26px;border-radius:13px;flex-shrink:0;padding:4px;background-color:#8882}.custom-navbar .favorites-list .content .header .more-info:hover{background-color:#8884}.custom-navbar .favorites-list .content .header .play-all-container{flex-shrink:0;padding:0 6px;display:flex;align-items:center;justify-content:flex-start}.custom-navbar .favorites-list .content .header .play-all-container .play-all{display:flex;align-items:center;box-sizing:border-box;height:26px;border-radius:13px;padding:4px;background-color:#8882}.custom-navbar .favorites-list .content .header .play-all-container .play-all:hover{background-color:#8884}.custom-navbar .favorites-list .content .cards{flex:1;overflow:auto;overscroll-behavior:contain;scroll-behavior:smooth;position:relative;scrollbar-width:none!important;padding:0 12px 12px}.custom-navbar .favorites-list .content .cards::-webkit-scrollbar{height:0!important;width:0!important}.custom-navbar .favorites-list .content .cards-enter,.custom-navbar .favorites-list .content .cards-leave-to{opacity:0;transform:translateY(-16px) scale(.9)}.custom-navbar .favorites-list .content .cards-leave-active{transition:.24s cubic-bezier(.22,.61,.36,1);position:absolute}.custom-navbar .favorites-list .content .cards .favorite-card{cursor:pointer;flex-shrink:0;border-radius:8px;box-shadow:0 4px 8px 0 #0001;color:#000;background-color:#fff;display:grid;grid-template:"cover title" 2fr "cover info" 1fr/130px 1fr;height:85px}body.dark .custom-navbar .favorites-list .content .cards .favorite-card{background-color:#282828;color:#eee}.custom-navbar .favorites-list .content .cards .favorite-card:not(:last-child){margin-bottom:12px}.custom-navbar .favorites-list .content .cards .favorite-card:hover .cover{transform:scale(1.05)}.custom-navbar .favorites-list .content .cards .favorite-card .cover-container{grid-area:cover;overflow:hidden;border-radius:8px 0 0 8px;position:relative}.custom-navbar .favorites-list .content .cards .favorite-card .cover-container .favorite-time{top:6px;left:6px;padding:0 6px}.custom-navbar .favorites-list .content .cards .favorite-card .cover-container .duration{left:6px;bottom:6px;padding:0 6px}.custom-navbar .favorites-list .content .cards .favorite-card .cover-container .floating{position:absolute;opacity:0;font-size:11px}.custom-navbar .favorites-list .content .cards .favorite-card .cover-container .cover{object-fit:cover}.custom-navbar .favorites-list .content .cards .favorite-card:hover .floating{opacity:1}.custom-navbar .favorites-list .content .cards .favorite-card .title{grid-area:title;font-size:13px;font-weight:700;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;max-height:3em;word-break:break-all;line-height:1.5;overflow:hidden;margin-top:8px;padding:0 10px}.custom-navbar .favorites-list .content .cards .favorite-card .title:hover{color:var(--theme-color)!important}.custom-navbar .favorites-list .content .cards .favorite-card .up{flex:0 1 auto;padding:2px 10px 2px 2px;margin:0 8px 6px;justify-self:start;align-self:center;max-width:calc(100% - 16px);display:flex;align-items:center;box-sizing:border-box;height:24px;border-radius:12px;background-color:#8882}.custom-navbar .favorites-list .content .cards .favorite-card .up:hover{background-color:#8884}.custom-navbar .favorites-list .content .cards .favorite-card .up .face{border-radius:50%;margin-right:6px;height:20px;width:20px;object-fit:cover}body.dark .custom-navbar .favorites-list .content .cards .favorite-card .up .face.placeholder{filter:invert(.9)}.custom-navbar .favorites-list .content .cards .favorite-card .up .name{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:11px}.custom-navbar .favorites-list .content .cards .favorite-card .up:hover .name{color:var(--theme-color)}.custom-navbar .history-list{width:350px;height:600px;font-size:12px;display:flex;align-items:stretch;flex-direction:column;justify-content:center}.custom-navbar .history-list .loading-tip{display:flex;justify-content:center;width:100%}.custom-navbar .history-list>.loading-tip{display:none}.custom-navbar .history-list .mdi{line-height:1;font-size:18px}.custom-navbar .history-list.loading>.loading-tip{display:flex}.custom-navbar .history-list.loading>:not(.loading-tip){display:none}.custom-navbar .history-list .content{display:flex;align-items:stretch;flex-direction:column;scrollbar-width:none!important;justify-content:space-between;flex-grow:1;overflow:auto}.custom-navbar .history-list .content::-webkit-scrollbar{height:0!important;width:0!important}.custom-navbar .history-list .content .header{display:flex;align-items:center;justify-content:space-between;margin:16px 12px}.custom-navbar .history-list .content .header .search{position:relative;flex-grow:1;margin-right:16px}.custom-navbar .history-list .content .header .search input{width:100%;padding:4px;border:none;outline:0!important;color:inherit;background-color:transparent;border-radius:4px}.custom-navbar .history-list .content .header .search input::-webkit-input-placeholder{color:inherit!important;opacity:.3}.custom-navbar .history-list .content .header .search::after{content:"";position:absolute;top:calc(100%);left:0;width:100%;height:2px;border-radius:2px;transition:.24s ease-out;background-color:#8882}.custom-navbar .history-list .content .header .search.not-empty::after,.custom-navbar .history-list .content .header .search:focus-within::after{background-color:var(--theme-color)}.custom-navbar .history-list .content .header .tabs{flex:0;margin:0 16px 0 0;padding:0 6px;display:flex;align-items:center;justify-content:flex-start}.custom-navbar .history-list .content .header .tabs .tab{cursor:pointer;position:relative;white-space:nowrap}.custom-navbar .history-list .content .header .tabs .tab:not(:last-child){margin-right:24px}.custom-navbar .history-list .content .header .tabs .tab::after{content:"";width:calc(80%);height:2px;border-radius:1px;position:absolute;background-color:var(--theme-color);left:10%;bottom:-4px;transform:scaleX(0);transition:.2s ease-out}.custom-navbar .history-list .content .header .tabs .tab.active::after{transform:scaleX(1)}.custom-navbar .history-list .content .header .tabs .tab .tab-name{opacity:.5;line-height:normal}.custom-navbar .history-list .content .header .tabs .tab.active{transform:scale(1.2)}.custom-navbar .history-list .content .header .tabs .tab.active .tab-name{font-weight:700;opacity:1}.custom-navbar .history-list .content .header .more-info{display:flex;align-items:center;box-sizing:border-box;height:26px;border-radius:13px;flex-shrink:0;padding:4px;background-color:#8882;border:none;cursor:pointer;color:inherit;font-size:inherit}.custom-navbar .history-list .content .header .more-info:disabled{opacity:.3;cursor:not-allowed}.custom-navbar .history-list .content .header .more-info:hover:not(:disabled){background-color:#8884}.custom-navbar .history-list .content .history-content{flex:1;overflow:auto;overscroll-behavior:contain;scroll-behavior:smooth;position:relative;scrollbar-width:none!important;padding:0 12px 12px}.custom-navbar .history-list .content .history-content-enter,.custom-navbar .history-list .content .history-content-leave-to{opacity:0;transform:translateY(-16px) scale(.9)}.custom-navbar .history-list .content .history-content-leave-active{transition:.24s cubic-bezier(.22,.61,.36,1);position:absolute}.custom-navbar .history-list .content .history-content::-webkit-scrollbar{height:0!important;width:0!important}.custom-navbar .history-list .content .history-content .empty-tip{text-align:center}.custom-navbar .history-list .content .history-content .time-group{padding-bottom:16px}.custom-navbar .history-list .content .history-content .time-group-enter,.custom-navbar .history-list .content .history-content .time-group-leave-to{opacity:0;transform:translateY(-16px) scale(.9)}.custom-navbar .history-list .content .history-content .time-group-leave-active{transition:.24s cubic-bezier(.22,.61,.36,1);position:absolute}.custom-navbar .history-list .content .history-content .time-group-name{padding-bottom:4px;margin-bottom:4px}.custom-navbar .history-list .content .history-content .time-group-items .floating{box-sizing:border-box;height:20px;border-radius:10px;display:flex;align-items:center;background-color:#000c;color:#fff;justify-content:center;position:absolute;opacity:0;font-size:11px}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item{display:grid;grid-template:"cover title title" 3fr "cover up time" 2fr/80px 1fr auto;border-radius:4px 8px 8px 4px;color:#000;background-color:#fff;box-shadow:0 4px 8px 0 #0001}body.dark .custom-navbar .history-list .content .history-content .time-group-items .time-group-item{background-color:#282828;color:#eee}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item:not(:last-child){margin-bottom:8px}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item:hover .cover{transform:scale(1.05)}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item:hover .floating{opacity:1}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .cover-container{grid-area:cover;position:relative;height:55px;overflow:hidden;border-radius:4px 0 0 4px}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .cover-container .cover{object-fit:cover;width:80px;height:55px}body.dark .custom-navbar .history-list .content .history-content .time-group-items .time-group-item .cover-container .cover.placeholder{filter:invert(.9)}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .cover-container .duration{left:2px;bottom:2px;padding:0 6px}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .cover-container .progress-number{left:2px;top:2px;padding:0 6px}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .cover-container .progress{position:absolute;bottom:0;left:0;height:2px;border-radius:1px;background-color:var(--theme-color)}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .title{grid-area:title;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;align-self:center;padding-left:8px;padding-right:6px;font-size:13px}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .title:hover{color:var(--theme-color)!important}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .time,.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .up{font-size:11px;opacity:.75;align-self:start}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .up{grid-area:up;display:flex;align-items:center;padding-left:8px}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .up:hover{opacity:1}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .up .be-icon{margin-right:4px;font-size:14px}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .up-name{white-space:nowrap;max-width:160px;overflow:hidden;text-overflow:ellipsis}.custom-navbar .history-list .content .history-content .time-group-items .time-group-item .time{font-size:11px;grid-area:time;padding-right:6px}.custom-navbar>ul>li:not(.disabled) .popup-container{position:absolute;top:100%;left:50%}#custom-navbar-home-popup .category-item:hover .popup,#custom-navbar-search:focus-within~.search-list:not(.empty),.custom-navbar .search-list:not(.empty):focus-within,.custom-navbar>ul>li:not(.disabled):hover .popup-container>.popup{transform:translateY(0) translateX(-50%);pointer-events:initial;opacity:1}.custom-navbar>ul>li:not(.disabled).right-side:hover .popup-container>.popup{transform:translateY(0) translateX(-90%);left:100%}.custom-navbar>ul>li:not(.disabled).left-side:hover .popup-container>.popup{transform:translateY(0) translateX(10%);left:0}#custom-navbar-home-popup .category-item:hover .popup{transform:scaleX(1)}.custom-navbar.compact #custom-navbar-home-popup .category-item{padding:6px}.custom-navbar.compact #custom-navbar-home-popup .category-item.main{min-width:110px}#custom-navbar-home-popup .category-item .popup a,#message-list a,#upload-actions a{position:relative;padding:8px;display:flex;justify-content:start;border-bottom:2px solid transparent;font-size:11pt;line-height:16pt}#custom-navbar-home-popup .category-item .popup a::before,#message-list a::before,#upload-actions a::before{content:"";position:absolute;top:calc(100% - 4px);left:8px;width:calc(100% - 16px);height:2px;border-radius:2px;background-color:var(--theme-color);transition:.16s ease-out .1s;transform:scaleX(0)}.custom-navbar.compact #custom-navbar-home-popup .category-item .popup a{padding:6px}#custom-navbar-home-popup .category-item .popup a:hover::before,#message-list a:hover::before,#upload-actions a:hover::before{transform:scaleX(1)}.im-list-box{border-radius:0!important}#upload-button{padding-left:4px;font-size:12pt;font-weight:700}#message-list,#upload-actions{width:max-content}#message-list a[data-count]::after{content:attr(data-count);position:absolute;left:100%;top:50%;transform:translateY(-50%);background-color:var(--theme-color);color:var(--foreground-color);padding:0 6px;display:flex;justify-content:center;font-size:9pt;border-radius:6px;white-space:nowrap}@media screen and (max-width:1300px){.custom-navbar form input{width:200px}}`; offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/custom-navbar.min.html"] = `

顶栏布局

边缘间距: 设定两侧边缘处的间距, 单位为百分比, 100%为整个顶栏的宽度. 允许设置的范围为 0% ~ 40%
{{boundsPadding}}%
顺序与显示: 在左侧的条状图标上拖动可以改变它们的顺序, 或者按住名字一会再拖动也可以调顺序. 点击右侧的眼睛图标可以显示/隐藏它们.
`; -offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/custom-navbar.min.js"] = (()=>{return(t,i)=>{const e=["//www.bilibili.com","//t.bilibili.com","//search.bilibili.com","//space.bilibili.com","//account.bilibili.com","//pay.bilibili.com","//member.bilibili.com","//big.bilibili.com","//message.bilibili.com","//app.bilibili.com","//passport.bilibili.com","//game.bilibili.com","//live.bilibili.com/blackboard/"];const a=["//t.bilibili.com/vote/h5/index/#/result","//t.bilibili.com/lottery/h5/index/#/result","//member.bilibili.com/video/upload","//space.bilibili.com/ajax/","//www.bilibili.com/h5/comment/","//www.bilibili.com/blackboard/","//member.bilibili.com/v2"];const s=()=>{document.documentElement.style.setProperty("--navbar-bounds-padding",`0 ${t.customNavbarBoundsPadding}%`);document.documentElement.style.setProperty("--navbar-blur-opacity",(t.customNavbarBlurOpacity||.7).toString());addSettingsListener("customNavbarBlurOpacity",t=>{document.documentElement.style.setProperty("--navbar-blur-opacity",t)})};const n=(t,i,e)=>{e.classList.toggle(t,i)};const o=t=>{dq(".custom-navbar").classList.toggle("dark",t);dq(".custom-navbar-settings").classList.toggle("dark",t)};const c=()=>{try{JSON.parse(document.body.innerText);return true}catch(t){return false}};return(()=>{const r=document.URL.replace(location.search,"");const l=r==="https://www.bilibili.com/"||r==="https://www.bilibili.com/index.html";if(isIframe()||t.bilibiliSimpleNewHomeCompatible&&l||c()){i.removeStyle("customNavbarStyle");return}s();const m=!(!e.some(t=>document.URL.includes(t))||a.some(t=>document.URL.includes(t)))||document.URL.includes("//www.bilibili.com/blackboard/bnj2020.html")||document.URL.includes("//www.bilibili.com/blackboard/help.html");if(m){document.body.classList.add("custom-navbar-loading");(async()=>{const e=await i.importAsync("customNavbarHtml");document.body.insertAdjacentHTML("beforeend",e);addSettingsListener("useDarkStyle",o,true);const a=()=>dq(".custom-navbar");["Fill","Shadow","Compact","Blur"].forEach(t=>{const i="customNavbar"+t;addSettingsListener(i,i=>n(t.toLowerCase(),i,a()),true)});SpinQuery.condition(()=>dq("#banner_link,.international-header .bili-banner"),t=>t===null?false:Boolean(t.style.backgroundImage),i=>{Observer.attributes(i,()=>{const e=dqa(".custom-navbar .blur-layer");e.forEach(t=>{t.style.backgroundImage=i.style.backgroundImage;t.setAttribute("data-image",i.style.backgroundImage)});addSettingsListener("customNavbarTransparent",i=>{if(!t.hideBanner){a().classList.toggle("transparent",i)}},true);addSettingsListener("hideBanner",i=>{if(t.customNavbarTransparent){a().classList.toggle("transparent",!i)}})})});const{Blank:s}=await i.importAsync("custom-navbar-blank");const{Logo:c}=await i.importAsync("custom-navbar-logo");const{Category:r}=await i.importAsync("custom-navbar-category");const{SimpleLink:l}=await i.importAsync("custom-navbar-simple-link");const{UserInfo:m}=await i.importAsync("custom-navbar-user-info");const{SearchBox:b}=await i.importAsync("custom-navbar-search-box");const{Iframe:u}=await i.importAsync("custom-navbar-iframe");const d=[new s(1),new c,new r,new l("排行","https://www.bilibili.com/ranking","ranking"),new l("相簿","https://h.bilibili.com","drawing"),new l("音频","https://www.bilibili.com/audio/home/","music"),new u("游戏中心","https://game.bilibili.com/",{src:`https://www.bilibili.com/page-proxy/game-nav.html`,width:`680px`,height:`260px`,lazy:true,iframeName:"games"}),new u("直播","https://live.bilibili.com",{src:`https://live.bilibili.com/blackboard/dropdown-menu.html`,width:`528px`,height:`266px`,lazy:true,iframeName:"lives"}),new l("会员购","https://show.bilibili.com","shop"),new l("漫画","https://manga.bilibili.com","manga"),new s(2),new b,new m];if(getUID()){const{WatchlaterList:t}=await i.importAsync("custom-navbar-watchlater-list");const{Messages:e}=await i.importAsync("custom-navbar-messages");const{Activities:a}=await i.importAsync("custom-navbar-activities");const{Subscriptions:s}=await i.importAsync("custom-navbar-subscriptions");const{FavoritesList:n}=await i.importAsync("custom-navbar-favorites-list");const{HistoryList:o}=await i.importAsync("custom-navbar-history-list");d.push(new e,new s,new a,new t,new n,new o)}const{Upload:p}=await i.importAsync("custom-navbar-upload");const{DarkMode:w}=await i.importAsync("custom-navbar-dark-mode");d.push(new p,new s(3),new w);new Vue({el:".custom-navbar",data:{components:d},methods:{async requestPopup(t){if(!t.requestedPopup&&!t.disabled){this.$set(t,`requestedPopup`,true);if(t.initialPopup){t.initialPopup()}}if(t.onPopup){t.onPopup()}}},mounted(){document.body.classList.remove("custom-navbar-loading");const t=[...d].sort(ascendingSort(t=>t.order));const i=()=>{const i=()=>{let i=0;let e=true;let a=t.length-1;let s=true;while(i\n\n顶栏布局\n`,condition:()=>m,success:async()=>{const{initSettingsPanel:t}=await i.importAsync("custom-navbar-settings");await t()}},unload:()=>{const t=dqa(".custom-navbar,.custom-navbar-settings");t.forEach(t=>t.style.display="none");i.removeStyle("customNavbarStyle")},reload:()=>{const t=dqa(".custom-navbar,.custom-navbar-settings");t.forEach(t=>t.style.display="flex");i.applyImportantStyle("customNavbarStyle")}}})()}})(); +offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/custom-navbar.min.js"] = (()=>{return(t,i)=>{const e=["//www.bilibili.com","//t.bilibili.com","//search.bilibili.com","//space.bilibili.com","//account.bilibili.com","//pay.bilibili.com","//member.bilibili.com","//big.bilibili.com","//message.bilibili.com","//app.bilibili.com","//passport.bilibili.com","//game.bilibili.com","//live.bilibili.com/blackboard/"];const a=["//t.bilibili.com/vote/h5/index/#/result","//t.bilibili.com/lottery/h5/index/#/result","//member.bilibili.com/video/upload","//space.bilibili.com/ajax/","//www.bilibili.com/h5/comment/","//www.bilibili.com/blackboard/","//member.bilibili.com/v2"];const s=()=>{document.documentElement.style.setProperty("--navbar-bounds-padding",`0 ${t.customNavbarBoundsPadding}%`);document.documentElement.style.setProperty("--navbar-blur-opacity",(t.customNavbarBlurOpacity||.7).toString());addSettingsListener("customNavbarBlurOpacity",t=>{document.documentElement.style.setProperty("--navbar-blur-opacity",t)})};const n=(t,i,e)=>{e.classList.toggle(t,i)};const o=t=>{dq(".custom-navbar").classList.toggle("dark",t);dq(".custom-navbar-settings").classList.toggle("dark",t)};return(()=>{const c=document.URL.replace(location.search,"");const r=c==="https://www.bilibili.com/"||c==="https://www.bilibili.com/index.html";if(isIframe()||t.bilibiliSimpleNewHomeCompatible&&r||document.contentType!=="text/html"){i.removeStyle("customNavbarStyle");return}s();const l=!(!e.some(t=>document.URL.includes(t))||a.some(t=>document.URL.includes(t)))||document.URL.includes("//www.bilibili.com/blackboard/bnj2020.html")||document.URL.includes("//www.bilibili.com/blackboard/help.html");if(l){document.body.classList.add("custom-navbar-loading");(async()=>{const e=await i.importAsync((()=>"customNavbarHtml")());document.body.insertAdjacentHTML("beforeend",e);addSettingsListener("useDarkStyle",o,true);const a=()=>dq(".custom-navbar");["Fill","Shadow","Compact","Blur"].forEach(t=>{const i="customNavbar"+t;addSettingsListener(i,i=>n(t.toLowerCase(),i,a()),true)});SpinQuery.condition(()=>dq("#banner_link,.international-header .bili-banner"),t=>t===null?false:Boolean(t.style.backgroundImage),i=>{Observer.attributes(i,()=>{const e=dqa(".custom-navbar .blur-layer");e.forEach(t=>{t.style.backgroundImage=i.style.backgroundImage;t.setAttribute("data-image",i.style.backgroundImage)});addSettingsListener("customNavbarTransparent",i=>{if(!t.hideBanner){a().classList.toggle("transparent",i)}},true);addSettingsListener("hideBanner",i=>{if(t.customNavbarTransparent){a().classList.toggle("transparent",!i)}})})});const{Blank:s}=await i.importAsync("custom-navbar-blank");const{Logo:c}=await i.importAsync("custom-navbar-logo");const{Category:r}=await i.importAsync("custom-navbar-category");const{SimpleLink:l}=await i.importAsync("custom-navbar-simple-link");const{UserInfo:m}=await i.importAsync("custom-navbar-user-info");const{SearchBox:b}=await i.importAsync("custom-navbar-search-box");const{Iframe:u}=await i.importAsync("custom-navbar-iframe");const d=[new s(1),new c,new r,new l("排行","https://www.bilibili.com/ranking","ranking"),new l("相簿","https://h.bilibili.com","drawing"),new l("音频","https://www.bilibili.com/audio/home/","music"),new u("游戏中心","https://game.bilibili.com/",{src:`https://www.bilibili.com/page-proxy/game-nav.html`,width:`680px`,height:`260px`,lazy:true,iframeName:"games"}),new u("直播","https://live.bilibili.com",{src:`https://live.bilibili.com/blackboard/dropdown-menu.html`,width:`528px`,height:`266px`,lazy:true,iframeName:"lives"}),new l("会员购","https://show.bilibili.com","shop"),new l("漫画","https://manga.bilibili.com","manga"),new s(2),new b,new m];if(getUID()){const{WatchlaterList:t}=await i.importAsync("custom-navbar-watchlater-list");const{Messages:e}=await i.importAsync("custom-navbar-messages");const{Activities:a}=await i.importAsync("custom-navbar-activities");const{Subscriptions:s}=await i.importAsync("custom-navbar-subscriptions");const{FavoritesList:n}=await i.importAsync("custom-navbar-favorites-list");const{HistoryList:o}=await i.importAsync("custom-navbar-history-list");d.push(new e,new s,new a,new t,new n,new o)}const{Upload:p}=await i.importAsync("custom-navbar-upload");const{DarkMode:w}=await i.importAsync("custom-navbar-dark-mode");d.push(new p,new s(3),new w);new Vue({el:".custom-navbar",data:{components:d},methods:{async requestPopup(t){if(!t.requestedPopup&&!t.disabled){this.$set(t,`requestedPopup`,true);if(t.initialPopup){t.initialPopup()}}if(t.onPopup){t.onPopup()}}},mounted(){document.body.classList.remove("custom-navbar-loading");const t=[...d].sort(ascendingSort(t=>t.order));const i=()=>{const i=()=>{let i=0;let e=true;let a=t.length-1;let s=true;while(i\n\n顶栏布局\n`,condition:()=>l,success:async()=>{const{initSettingsPanel:t}=await i.importAsync("custom-navbar-settings");await t()}},unload:()=>{const t=dqa(".custom-navbar,.custom-navbar-settings");t.forEach(t=>t.style.display="none");i.removeStyle("customNavbarStyle")},reload:()=>{const t=dqa(".custom-navbar,.custom-navbar-settings");t.forEach(t=>t.style.display="flex");i.applyImportantStyle("customNavbarStyle")}}})()}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/custom-navbar-activities.min.js"] = (()=>{return(t,i)=>{const{NavbarComponent:a}=i.import("custom-navbar-component");let e=async()=>{};let n=async()=>{};let c;const s=({dataObject:t,apiUrl:a,name:n,handleJson:c,template:s})=>{return{template:s,components:{"dpi-img":()=>i.importAsync("dpi-img.vue")},methods:{handleJson:c,async fetchData(t=false){try{const i=await Ajax.getJsonWithCredentials(a);if(i.code!==0){throw new Error(i.message)}await this.handleJson(i)}catch(i){if(t===true){return}logError(`加载${n}动态失败, error = ${i}`)}finally{this.loading=false}}},data(){return Object.assign({loading:true},t)},mounted(){this.fetchData();e=(async()=>await this.fetchData(true))},destroyed(){e=(async()=>{})}}};class r extends a{constructor(){super();this.boundingWidth=380;this.noPadding=true;this.href=t.oldTweets?"https://www.bilibili.com/account/dynamic":"https://t.bilibili.com/";this.html="动态";this.popupHtml=`\n
\n\n
\n\n\n\n \x3c!-- 查看更多 --\x3e\n
\n
\n`;this.active=document.URL.replace(/\?.*$/,"")===this.href;this.initialPopup=(()=>{this.init()});this.onPopup=(()=>{this.setNotifyCount(0)});this.getNotifyCount();setInterval(async()=>{await this.getNotifyCount();await n();await e()},r.updateInterval)}static get updateInterval(){return 5*60*1e3}static getLatestID(){return document.cookie.replace(new RegExp(`(?:(?:^|.*;\\s*)bp_t_offset_${getUID()}\\s*\\=\\s*([^;]*).*$)|^.*$`),"$1")}static setLatestID(t){if(t===null||t===undefined){return}const i=r.getLatestID();if(r.compareID(t,i)<0){return}document.cookie=`bp_t_offset_${getUID()}=${t};path=/;domain=.bilibili.com;max-age=${60*60*24*30}`}static compareID(t,i){if(t===i){return 0}if(t.length>i.length){return 1}if(i.length>t.length){return-1}return t>i===true?1:-1}static isNewID(t){return r.compareID(t,c)>0}static updateLatestID(t){const[i]=[...t.map(t=>t.id)].sort(r.compareID).reverse();r.setLatestID(i)}async getNotifyCount(){const t=`https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_num?rsp_type=1&uid=${getUID()}&update_num_dy_id=${r.getLatestID()}&type_list=8,64,512`;const i=await Ajax.getJsonWithCredentials(t);if(i.code!==0){return}this.setNotifyCount(i.data.update_num)}async init(){Vue.component("activity-loading",{template:`\n
\n加载中...\n
`,props:["loading"]});Vue.component("activity-empty",{template:`\n
空空如也哦 = ̄ω ̄=
`});new Vue({el:await SpinQuery.select(".activity-popup"),data:{tabs:[{name:"视频",component:"video-activity",moreUrl:"https://t.bilibili.com/?tab=8",get notifyApi(){return`https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_num?rsp_type=1&uid=${getUID()}&update_num_dy_id=${r.getLatestID()}&type_list=8`},notifyCount:null},{name:"番剧",component:"bangumi-activity",moreUrl:"https://t.bilibili.com/?tab=512",get notifyApi(){return`https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_num?rsp_type=1&uid=${getUID()}&update_num_dy_id=${r.getLatestID()}&type_list=512`},notifyCount:null},{name:"专栏",component:"column-activity",moreUrl:"https://t.bilibili.com/?tab=64",get notifyApi(){return`https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_num?rsp_type=1&uid=${getUID()}&update_num_dy_id=${r.getLatestID()}&type_list=64`},notifyCount:null},{name:"直播",component:"live-activity",moreUrl:"https://link.bilibili.com/p/center/index#/user-center/follow/1",notifyCount:null}],selectedTab:"视频"},components:{"activity-tabs":{props:["items","tab"],template:`\n\n`,methods:{changeTab(t){if(this.tab===t.name){window.open(t.moreUrl,"_blank")}this.$emit("update:tab",t.name)}}},"video-activity":Object.assign(s({dataObject:{leftCards:[],rightCards:[]},apiUrl:`https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new?uid=${getUID()}&type_list=8`,name:"视频",template:`\n
\n\n\n
\n\n
\n
\n\n
\n
\n`,handleJson:async function(t){const i=_.uniqBy(_.get(t,"data.cards",[]).map(t=>{const i=JSON.parse(t.card);return{coverUrl:i.pic,title:i.title,timeNumber:i.duration,time:formatDuration(i.duration),description:i.desc,aid:i.aid,videoUrl:`https://www.bilibili.com/av${i.aid}`,faceUrl:t.desc.user_profile.info.face,upName:t.desc.user_profile.info.uname,upUrl:`https://space.bilibili.com/${t.desc.user_profile.info.uid}`,id:t.desc.dynamic_id_str,watchlater:true,get new(){return r.isNewID(this.id)}}}),t=>t.aid);this.leftCards=i.filter((t,i)=>i%2===0);this.rightCards=i.filter((t,i)=>i%2===1);if(this.leftCards.length!==this.rightCards.length){this.leftCards.pop()}r.updateLatestID(i)}}),{components:{"video-card":{props:["card","watchlaterInit"],store:store,data(){return{}},computed:{...Vuex.mapState(["watchlaterList"]),watchlater(){if(this.watchlaterInit!==null){return this.watchlaterList.includes(this.card.aid)}else{return null}}},components:{"dpi-img":()=>i.importAsync("dpi-img.vue")},methods:{...Vuex.mapActions(["toggleWatchlater"])},async mounted(){},template:`\n\n
\n\n
{{card.time}}
\n
{{watchlater ? '已添加' : '稍后再看'}}
\n
\n

{{card.title}}

\n
\n\n{{card.upName}}\n\n\n`}}}),"bangumi-activity":s({dataObject:{cards:[]},apiUrl:`https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new?uid=${getUID()}&type_list=512`,name:"番剧",template:`\n\n`,handleJson:async function(t){this.cards=_.get(t,"data.cards",[]).map(t=>{const i=JSON.parse(t.card);return{title:i.apiSeasonInfo.title,coverUrl:i.apiSeasonInfo.cover,epCoverUrl:i.cover,epTitle:i.new_desc,url:i.url,id:t.desc.dynamic_id_str,get new(){return r.isNewID(this.id)}}});r.updateLatestID(this.cards)}}),"column-activity":s({dataObject:{cards:[]},apiUrl:`https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/dynamic_new?uid=${getUID()}&type_list=64`,name:"专栏",template:`\n
\n\n\n\n\n

{{card.title}}

\n
{{card.description}}
\n\n
\n`,handleJson:async function(t){this.cards=_.get(t,"data.cards",[]).map(t=>{const i=JSON.parse(t.card);return{covers:i.image_urls,originalCovers:i.origin_image_urls,upName:i.author.name,faceUrl:i.author.face,upUrl:`https://space.bilibili.com/${i.author.mid}`,title:i.title,description:i.summary,url:`https://www.bilibili.com/read/cv${i.id}`,id:t.desc.dynamic_id_str,get new(){return r.isNewID(this.id)}}});r.updateLatestID(this.cards)}}),"live-activity":s({dataObject:{cards:[]},apiUrl:`https://api.live.bilibili.com/relation/v1/feed/feed_list?page=1&pagesize=24`,name:"直播",template:`\n\n`,handleJson:async function(t){this.cards=_.get(t,"data.list",[]).map(t=>{return{faceUrl:t.face,title:t.title,name:t.uname,id:t.roomid,url:t.link}})}})},computed:{content(){return this.tabs.find(t=>t.name===this.selectedTab).component},viewMoreUrl(){return this.tabs.find(t=>t.name===this.selectedTab).moreUrl}},mounted(){n=(async()=>{for(const t of this.tabs){if(t.notifyApi){const i=await Ajax.getJsonWithCredentials(t.notifyApi);if(i.code!==0||!i.data.update_num||this.selectedTab===t.name){continue}t.notifyCount=i.data.update_num}}});n()},destroyed(){n=(async()=>{})},watch:{selectedTab(t){this.tabs.find(i=>i.name===t).notifyCount=null}}})}get name(){return"activities"}}c=r.getLatestID();return{export:{Activities:r}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/custom-navbar-blank.min.js"] = (()=>{return(t,e)=>{const{NavbarComponent:n}=e.import("custom-navbar-component");class r extends n{constructor(t){super();this.number=t;this.flex="1 0 auto";this.disabled=true}get name(){return"blank"+this.number}}return{export:{Blank:r}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/custom-navbar-category.min.js"] = (()=>{return(i,t)=>{const{NavbarComponent:l}=t.import("custom-navbar-component");class o extends l{constructor(){super();this.boundingWidth=366;this.href=`https://www.bilibili.com`;this.html=`主站`;this.popupHtml=`\n\n`;const i=async()=>{const i=await Ajax.getJson("https://api.bilibili.com/x/web-interface/online");if(parseInt(i.code)!==0){throw new Error(`[自定义顶栏] 分区投稿信息获取失败: ${i.message}`)}const t=i.data.region_count;await SpinQuery.select("#custom-navbar-home-popup");return{"动画":{icon:"douga",count:t[1],link:`https://www.bilibili.com/v/douga/`,subRegions:{"MAD·AMV":`https://www.bilibili.com/v/douga/mad/`,"MMD·3D":`https://www.bilibili.com/v/douga/mmd/`,"短片·手书·配音":`https://www.bilibili.com/v/douga/voice/`,"综合":`https://www.bilibili.com/v/douga/other/`}},"番剧":{icon:"anime",count:t[13],link:`https://www.bilibili.com/anime/`,subRegions:{"连载动画":`https://www.bilibili.com/v/anime/serial/`,"完结动画":`https://www.bilibili.com/v/anime/finish/`,"资讯":`https://www.bilibili.com/v/anime/information/`,"官方延伸":`https://www.bilibili.com/v/anime/offical/`,"新番时间表":`https://www.bilibili.com/anime/timeline/`,"番剧索引":`https://www.bilibili.com/anime/index/`}},"国创":{icon:"guochuang",count:t[167],link:`https://www.bilibili.com/guochuang/`,subRegions:{"国产动画":`https://www.bilibili.com/v/guochuang/chinese/`,"国产原创相关":`https://www.bilibili.com/v/guochuang/original/`,"布袋戏":`https://www.bilibili.com/v/guochuang/puppetry/`,"动态漫·广播剧":`https://www.bilibili.com/v/guochuang/motioncomic/`,"资讯":`https://www.bilibili.com/v/guochuang/information/`,"新番时间表":`https://www.bilibili.com/guochuang/timeline/`,"国产动画索引":`https://www.bilibili.com/guochuang/index/`}},"音乐":{icon:"music",count:t[3],link:`https://www.bilibili.com/v/music/`,subRegions:{"原创音乐":"https://www.bilibili.com/v/music/original/","翻唱":"https://www.bilibili.com/v/music/cover/","VOCALOID·UTAU":"https://www.bilibili.com/v/music/vocaloid/","电音":"https://www.bilibili.com/v/music/electronic/","演奏":"https://www.bilibili.com/v/music/perform/",MV:"https://www.bilibili.com/v/music/mv/","音乐现场":"https://www.bilibili.com/v/music/live/","音乐综合":"https://www.bilibili.com/v/music/other/","音频":"https://www.bilibili.com/audio/home?musicType=music"}},"舞蹈":{icon:"dance",count:t[129],link:`https://www.bilibili.com/v/dance/`,subRegions:{"宅舞":"https://www.bilibili.com/v/dance/otaku/","街舞":"https://www.bilibili.com/v/dance/hiphop/","明星舞蹈":"https://www.bilibili.com/v/dance/star/","中国舞":"https://www.bilibili.com/v/dance/china/","舞蹈综合":"https://www.bilibili.com/v/dance/three_d/","舞蹈教程":"https://www.bilibili.com/v/dance/demo/"}},"游戏":{icon:"game",count:t[4],link:`https://www.bilibili.com/v/game/`,subRegions:{"单机游戏":"https://www.bilibili.com/v/game/stand_alone/","电子竞技":"https://www.bilibili.com/v/game/esports/","手机游戏":"https://www.bilibili.com/v/game/mobile/","网络游戏":"https://www.bilibili.com/v/game/online/","桌游棋牌":"https://www.bilibili.com/v/game/board/",GMV:"https://www.bilibili.com/v/game/gmv/","音游":"https://www.bilibili.com/v/game/music/",Mugen:"https://www.bilibili.com/v/game/mugen/","游戏赛事":"https://www.bilibili.com/v/game/match/"}},"科技":{icon:"technology",count:t[36],link:`https://www.bilibili.com/v/technology/`,subRegions:{"科学科普":"https://www.bilibili.com/v/technology/science/","社科人文":"https://www.bilibili.com/v/technology/fun/","野生技术协会":"https://www.bilibili.com/v/technology/wild/","演讲·公开课":"https://www.bilibili.com/v/technology/speech_course/","星海":"https://www.bilibili.com/v/technology/military/","机械":"https://www.bilibili.com/v/technology/mechanical/","汽车":"https://www.bilibili.com/v/technology/automobile/"}},"数码":{icon:"digital",count:t[188],link:`https://www.bilibili.com/v/digital/`,subRegions:{"手机平板":"https://www.bilibili.com/v/digital/mobile/","电脑装机":"https://www.bilibili.com/v/digital/pc/","摄影摄像":"https://www.bilibili.com/v/digital/photography/","影音智能":"https://www.bilibili.com/v/digital/intelligence_av/"}},"生活":{icon:"life",count:t[160],link:`https://www.bilibili.com/v/life/`,subRegions:{"搞笑":"https://www.bilibili.com/v/life/funny/","日常":"https://www.bilibili.com/v/life/daily/","美食圈":"https://www.bilibili.com/v/life/food/","动物圈":"https://www.bilibili.com/v/life/animal/","手工":"https://www.bilibili.com/v/life/handmake/","绘画":"https://www.bilibili.com/v/life/painting/","运动":"https://www.bilibili.com/v/life/sports/","其他":"https://www.bilibili.com/v/life/other/"}},"鬼畜":{icon:"kichiku",count:t[119],link:`https://www.bilibili.com/v/kichiku/`,subRegions:{"鬼畜调教":"https://www.bilibili.com/v/kichiku/guide/","音MAD":"https://www.bilibili.com/v/kichiku/mad/","人力VOCALOID":"https://www.bilibili.com/v/kichiku/manual_vocaloid/","教程演示":"https://www.bilibili.com/v/kichiku/course/"}},"时尚":{icon:"fashion",count:t[155],link:`https://www.bilibili.com/v/fashion/`,subRegions:{"美妆":"https://www.bilibili.com/v/fashion/makeup/","服饰":"https://www.bilibili.com/v/fashion/clothing/","健身":"https://www.bilibili.com/v/fashion/aerobics/","T台":"https://www.bilibili.com/v/fashion/catwalk/","风尚标":"https://www.bilibili.com/v/fashion/trends/"}},"资讯":{icon:"information",count:t[202],link:`https://www.bilibili.com/v/information/`,subRegions:{"热点":"https://www.bilibili.com/v/information/hotspot/","环球":"https://www.bilibili.com/v/information/global/","社会":"https://www.bilibili.com/v/information/social/","综合":"https://www.bilibili.com/v/information/multiple/"}},"娱乐":{icon:"ent",count:t[5],link:`https://www.bilibili.com/v/ent/`,subRegions:{"综艺":"https://www.bilibili.com/v/ent/variety/","明星":"https://www.bilibili.com/v/ent/star/","Korea相关":"https://www.bilibili.com/v/ent/korea/"}},"影视":{icon:"cinephile",count:t[181],link:`https://www.bilibili.com/v/cinephile/`,subRegions:{"影视杂谈":"https://www.bilibili.com/v/cinephile/cinecism/","影视剪辑":"https://www.bilibili.com/v/cinephile/montage/","短片":"https://www.bilibili.com/v/cinephile/shortfilm/","预告·资讯":"https://www.bilibili.com/v/cinephile/trailer_info/","特摄":"https://www.bilibili.com/v/cinephile/tokusatsu/"}},"放映厅":{icon:"cinema",count:t[177]+t[23]+t[11],link:`https://www.bilibili.com/cinema/`,subRegions:{"纪录片":"https://www.bilibili.com/documentary/","电影":"https://www.bilibili.com/movie/","电视剧":"https://www.bilibili.com/tv/"}},"专栏":{icon:"read",count:``,link:`https://www.bilibili.com/read/home`},"直播":{icon:"zhibo",count:``,link:`https://live.bilibili.com`,subRegions:{"全部直播":"https://live.bilibili.com/all?visit_id=5icxsa0kmts0","游戏直播":"https://live.bilibili.com/p/eden/area-tags?parentAreaId=2&areaId=0&visit_id=5icxsa0kmts0#/2/0","手游直播":"https://live.bilibili.com/p/eden/area-tags?parentAreaId=3&areaId=0&visit_id=5icxsa0kmts0#/3/0","娱乐直播":"https://live.bilibili.com/p/eden/area-tags?parentAreaId=1&areaId=0&visit_id=5icxsa0kmts0#/1/0","电台直播":"https://live.bilibili.com/p/eden/area-tags?parentAreaId=5&areaId=0&visit_id=5icxsa0kmts0#/5/0","绘画直播":"https://live.bilibili.com/p/eden/area-tags?parentAreaId=4&areaId=0&visit_id=5icxsa0kmts0#/4/0"}},"小黑屋":{icon:"blackroom",count:``,link:`https://www.bilibili.com/blackroom/`},"专题":{icon:"topic",count:``,link:`https://www.bilibili.com/blackboard/topic_list.html`},"活动":{icon:"activit",count:``,link:`https://www.bilibili.com/blackboard/x/act_list`}}};this.initialPopup=(async()=>{new Vue({el:await SpinQuery.select("#custom-navbar-home-popup"),data:{info:[],loading:true},async mounted(){try{this.info=Object.entries(await i())}finally{this.loading=false}}})})}get name(){return"category"}}return{export:{Category:o}}}})(); @@ -1471,7 +1472,7 @@ offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/m offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/trending-videos.min.js"] = (()=>{return(t,e)=>{const i=async(t,e)=>{const i=await Ajax.getJsonWithCredentials(`https://api.bilibili.com/x/web-interface/ranking/index?day=${t}`);if(i.code!==0){throw new Error(i.message)}return i.data.map(e=>({id:e.aid+"-"+t,aid:parseInt(e.aid),title:e.title,upID:e.mid,upName:e.author,coverUrl:e.pic.replace("http://","https://"),description:e.description,durationText:e.duration,playCount:formatCount(e.play),coins:formatCount(e.coins),favorites:formatCount(e.favorites),watchlater:true}))};return{export:{getTrendingVideos:i}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/trending-videos.vue.min.js"] = (()=>{return(a,t)=>{const i=`
热门
{{tab.name}}
`;t.applyStyleFromText(`.simple-home .trendings{display:flex;flex-direction:column}.simple-home .trendings .header{padding:0 8px}.simple-home .trendings .contents{--card-width:200px;--card-height:250px;--card-count:3;margin-top:16px;display:flex;overflow:auto;height:calc(var(--card-height) + 16px);width:calc((var(--card-width) + 16px) * var(--card-count));scrollbar-width:none!important}@media screen and (max-width:1300px) and (min-width:900px){.simple-home .trendings .contents{--card-count:2}}@media screen and (max-width:1100px) and (min-width:900px){.simple-home .trendings .contents{--card-count:4}}@media screen and (min-width:1550px){.simple-home .trendings .contents{--card-count:4}}.simple-home .trendings .contents::-webkit-scrollbar{width:0!important;height:0!important}.simple-home .trendings .contents .card-wrapper{padding:0 8px;scroll-snap-align:start;flex-shrink:0}`,"trending-videos-style");const n=[{name:"今日",day:1,url:"https://www.bilibili.com/ranking/all/0/0/1"},{name:"三日",day:3,url:"https://www.bilibili.com/ranking"},{name:"一周",day:7,url:"https://www.bilibili.com/ranking/all/0/0/7"}];return{export:Object.assign({template:i},{components:{VideoCard:()=>t.importAsync("video-card.vue")},data(){return{tabs:n,currentTab:n[0],trendingCards:[]}},watch:{currentTab(a){this.updateTrendingTab(a)}},methods:{async updateTrendingTab(a){const{getTrendingVideos:i}=await t.importAsync("trending-videos");this.trendingCards=await i(a.day)},changeTab(a){if(this.currentTab===a){open(a.url,"_blank")}else{this.currentTab=a}}},mounted(){this.updateTrendingTab(this.currentTab)}})}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/tweets.min.css"] = `.nav-search-submit{display:block!important;color:var(--foreground-color-d)!important;transform:translateX(-125px);-webkit-tap-highlight-color:transparent}.nav-search-submit:hover{color:var(--foreground-color)!important}#nav_searchform{transition:.3s ease-out;box-shadow:none;width:0!important;padding:0!important}.preserve-rank>a{opacity:0!important;pointer-events:none}.showSearch .preserve-rank>a{opacity:.382!important;pointer-events:initial}.showSearch #nav_searchform{box-shadow:0 2px 10px 1px #0002;width:250px!important}.showSearch .nav-search-submit,.showSearch .nav-search-submit:hover{color:#888!important;transform:none}@media only screen and (max-width:1291px){.showSearch #nav_searchform{width:140px!important}}`; -offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/url-params-clean.min.js"] = (()=>{return(t,e)=>{const r=["spm_id_from","from_source","from_spmid","from","seid","share_source","share_medium","share_plat","share_tag","bbid","ts","timestamp","unique_k","rt","tdsourcetag","accept_quality","broadcast_type","current_qn","current_quality","playurl_h264","playurl_h265","quality_description","network","network_status","platform_network_status"];const s=[/game\.bilibili\.com\/fgo/];const o=t=>{return t};const a=()=>{const t=location.search.substring(1).split("&");const e=t.filter(t=>{if(r.some(e=>t.startsWith(`${e}=`))){return false}return true});const s=e.join("&");const a=o(document.URL.replace(location.search,""));const n=s?"?"+s:"";const c=a+n;if(c!==document.URL){console.log("[URL params clean]",document.URL,c);history.replaceState({},document.title,c)}};let n=false;try{JSON.parse(document.body.innerText);n=true}catch(t){n=false}fullyLoaded(()=>{if(!n){a();Observer.videoChange(()=>a())}})}})(); +offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/url-params-clean.min.js"] = (()=>{return(t,e)=>{const r=["spm_id_from","from_source","from_spmid","from","seid","share_source","share_medium","share_plat","share_tag","bbid","ts","timestamp","unique_k","rt","tdsourcetag","accept_quality","broadcast_type","current_qn","current_quality","playurl_h264","playurl_h265","quality_description","network","network_status","platform_network_status"];const o=[/game\.bilibili\.com\/fgo/];const s=t=>{return t};const n=()=>{const t=location.search.substring(1).split("&");const e=t.filter(t=>{if(r.some(e=>t.startsWith(`${e}=`))){return false}return true});const o=e.join("&");const n=s(document.URL.replace(location.search,""));const a=o?"?"+o:"";const c=n+a;if(c!==document.URL){console.log("[URL params clean]",document.URL,c);history.replaceState({},document.title,c)}};fullyLoaded(()=>{if(document.contentType==="text/html"){n();Observer.videoChange(()=>n())}})}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/v-checkbox.vue.min.js"] = (()=>{return(e,c)=>{const i=`
{{title}}
`;c.applyStyleFromText(`.v-checkbox{font-size:10pt;cursor:pointer;display:flex;align-items:center}.v-checkbox .mdi{font-size:15pt;line-height:1}.v-checkbox .content{flex-grow:1;text-align:left;padding:0 8px}.v-checkbox .mdi-checkbox-marked-circle{color:var(--theme-color);position:absolute;top:0;left:0;transform:scale(0);transition-timing-function:cubic-bezier(.6,-.28,.74,.05)}.v-checkbox .mdi-checkbox-blank-circle-outline{color:#8884;position:relative}.v-checkbox.checked .mdi-checkbox-blank-circle-outline{color:var(--theme-color)}.v-checkbox.checked .mdi-checkbox-marked-circle{transform:scale(1);transition-timing-function:cubic-bezier(.18,.89,.32,1.28)}`,"v-checkbox-style");return{export:Object.assign({template:i},{props:["checked","title"],methods:{toggleCheck(){this.$emit("update:checked",!this.checked)}}})}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/v-dropdown.vue.min.js"] = (()=>{return(o,r)=>{const e=`
{{ value }}
`;r.applyStyleFromText(`.v-dropdown{--background-color:#eee;position:relative;background-color:var(--background-color);cursor:pointer;display:flex;align-items:center;justify-content:space-between;min-width:100px;border-radius:var(--corner-radius);line-height:normal}body.dark .v-dropdown{--background-color:#333}.v-dropdown.round{border-radius:14px;padding:0 4px}.v-dropdown .dropdown-menu{transform-origin:top;transform:translateY(-4px) translateX(-50%);pointer-events:none;opacity:0;position:absolute;top:calc(100% + 2px);left:50%;background-color:var(--background-color);z-index:1;transition:.2s ease-out;box-shadow:rgba(0,0,0,.2) 0 4px 8px 0;border-radius:var(--corner-radius)}.v-dropdown .dropdown-menu.opened{transform:translateY(0) translateX(-50%);pointer-events:initial;opacity:1}.v-dropdown .dropdown-menu li{padding:4px 16px;box-sizing:content-box;white-space:nowrap;min-width:64px;text-align:center;cursor:pointer;color:inherit;background-color:transparent;border-radius:var(--corner-radius)}.v-dropdown .dropdown-menu li:hover{background-color:rgba(0,0,0,.08)}body.dark .v-dropdown .dropdown-menu li:hover{background-color:rgba(0,0,0,.16)}.v-dropdown .mdi-chevron-down{font-size:16pt;line-height:1;transform:rotate(0)}.v-dropdown .dropdown-menu.opened~.mdi-chevron-down{transform:rotate(180deg)}.v-dropdown .selected{user-select:none;padding:4px 8px}`,"v-dropdown-style");return{export:Object.assign({template:e},{props:["items","value","round"],data(){return{dropdownOpen:false}},methods:{toggleDropdown(){this.dropdownOpen=!this.dropdownOpen;if(this.dropdownOpen){document.addEventListener("click",o=>{const r=o.target;if(r===this.$el||this.$el.contains(r)){return}this.dropdownOpen=false},{once:true,capture:true})}},select(o){if(o!==this.value){this.$emit("update:value",o);this.$emit("change",o)}}}})}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/video-card.vue.min.js"] = (()=>{return(e,i)=>{const t=`
{{durationText}}
{{watchlater ? '已添加' : '稍后再看'}}

{{title}}

{{description}}

{{upName}}
{{playCount}}
`;i.applyStyleFromText(`.video-card{display:grid;grid-template-columns:200px 1fr;grid-template-rows:1fr 1fr 1fr;grid-template-areas:"cover title" "cover description" "cover up";height:var(--card-height);width:var(--card-width);color:#000;background-color:#fff;border-radius:16px;box-shadow:0 4px 8px 0 #0001;margin-right:var(--card-margin);margin-bottom:var(--card-margin);position:relative}body.dark .video-card,body.dark .video-card:hover{background-color:#282828;color:#eee}.video-card:hover{color:#000}.video-card.vertical{grid-template-columns:auto auto;grid-template-rows:2fr 1fr 1fr;grid-template-areas:"cover cover" "title title" "up up"}.video-card.vertical .description,.video-card.vertical .topics{display:none}.video-card.vertical .cover-container{border-radius:16px 16px 0 0}.video-card.vertical .title{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;max-height:3em;word-break:break-all;white-space:normal;line-height:1.5;font-size:11pt}.video-card.vertical .up{align-self:start;white-space:nowrap}.video-card.vertical .up .name{text-overflow:ellipsis;overflow:hidden}.video-card.vertical .up:not(.no-face){margin-left:8px;max-width:calc(var(--card-width) - 16px)}.video-card.vertical .up.no-face{margin-top:8px;max-width:calc(var(--card-width) - 24px)}.video-card.vertical .stats{align-self:end;justify-self:start;margin-bottom:8px;margin-right:0}.video-card>*{justify-self:self-start;align-self:center}.video-card:hover .cover{transform:scale(1.05);transition:.1s cubic-bezier(.39,.58,.57,1)}.video-card:hover .duration,.video-card:hover .watchlater{opacity:1}.video-card .duration,.video-card .watchlater{opacity:0}.video-card .cover-container{grid-area:cover;border-radius:16px 0 0 16px;position:relative;width:100%;height:100%;overflow:hidden}.video-card .cover-container .cover{object-fit:cover;width:100%;height:100%}.video-card .cover-container>:not(.cover){position:absolute}.video-card .cover-container .duration,.video-card .cover-container .watchlater{bottom:6px;padding:4px 8px;background-color:#000a;color:#fff;border-radius:14px;height:24px;box-sizing:border-box}.video-card .cover-container .duration .mdi,.video-card .cover-container .watchlater .mdi{font-size:12pt;line-height:1;margin-right:4px}.video-card .cover-container .duration{left:6px}.video-card .cover-container .watchlater{right:6px;display:flex;align-items:center;padding-left:4px}.video-card .title{grid-area:title;font-size:12pt;font-weight:700;color:inherit;padding:0 12px;white-space:nowrap;overflow:hidden;justify-self:stretch;text-overflow:ellipsis}.video-card .topics{grid-area:description;display:flex;align-items:center;margin-left:12px}.video-card .topics .topic{color:inherit;padding:4px 8px;background-color:#8882;margin-right:8px;border-radius:14px;white-space:nowrap;max-width:120px;overflow:hidden;text-overflow:ellipsis}.video-card .topics .topic:hover{background-color:#8884;color:var(--theme-color)}.video-card .description{grid-area:description;color:inherit;overflow:hidden;align-self:stretch;justify-self:stretch;margin:0 12px;line-height:1.5;height:3em;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;scrollbar-width:none!important}.video-card .description::-webkit-scrollbar{width:0!important}.video-card .description.single-line{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.video-card .stats,.video-card .up{grid-area:up}.video-card .up{margin-left:12px;display:flex;align-items:center;padding:2px;background-color:#8882;border-radius:14px;color:inherit}.video-card .up.no-face{background-color:transparent;padding:0}.video-card .up.no-face .be-icon{font-size:14pt;opacity:.75}.video-card .up .face{border-radius:50%;width:24px;height:24px}.video-card .up .name{margin:0 8px}.video-card .up:not(.no-face):hover{background-color:#8884}.video-card .up:hover .be-icon,.video-card .up:hover .name{color:var(--theme-color)}.video-card .stats{justify-self:self-end;margin-right:12px;display:flex;align-items:center;opacity:.5}.video-card .stats .be-icon{font-size:12pt;margin:0 4px 0 12px}.video-card .stats .be-icon.be-iconfont-favorites-outline{font-size:14pt}.video-card .stats .be-icon.be-iconfont-coin-outline{font-size:11pt}`,"video-card-style");return{export:Object.assign({template:t},{props:["data","orientation"],store:store,components:{"dpi-img":()=>i.importAsync("dpi-img.vue"),Icon:()=>i.importAsync("icon.vue")},data(){return{upFaceUrl:"",danmakuCount:"",like:"",coins:"",favorites:"",dynamic:"",topics:[],upID:0,epID:0,..._.omit(this.data,"watchlater"),watchlaterInit:this.data.watchlater}},computed:{vertical(){return this.orientation==="vertical"},...Vuex.mapState(["watchlaterList"]),watchlater(){if(getUID()&&this.watchlaterInit!==null){return this.watchlaterList.includes(this.aid)}else{return null}}},methods:{...Vuex.mapActions(["toggleWatchlater"])}})}}})(); @@ -1485,1998 +1486,1998 @@ offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/m offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/watchlater.min.js"] = (()=>{return(e,t)=>{const i=e=>{const t=e.match(/(av[\d]+)\/p([\d]+)/i)||e.match(/(BV[\w]+)\/p([\d]+)/i);if(t){return`https://www.bilibili.com/video/${t[1]}/?p=${t[2]}`}else{return"javascript:;"}};const r=e=>{const t=e.map(e=>{const t=e.getAttribute("href");if(!t){return"javascript:;"}if(t.match(/.*watchlater.*|javascript:;/g)){return i(t)}if(t.match(/video\/av|video\/BV/i)){return t}return t});e.forEach((e,i)=>{e.setAttribute("href",t[i]);e.setAttribute("target","_blank")})};const a=(...e)=>{for(const t of e){SpinQuery.select(()=>document.querySelectorAll(t),e=>r([...e]))}};SpinQuery.select(".watch-later-list").then(()=>{Observer.childListSubtree("#viewlater-app",()=>{SpinQuery.condition(()=>document.URL.match(/(av[\d]+)\/p([\d]+)/i)||document.URL.match(/(BV[\w]+)\/p([\d]+)/i),e=>e!==null&&document.URL.indexOf("watchlater")!==-1,()=>{const e=i(document.URL);if(e!==null){window.location.assign(e)}});SpinQuery.select("#viewlater-app .s-btn[href='#/']",e=>e.remove());a(".av-pic",".av-about>a")})});SpinQuery.select("li.nav-item[report-id*=watchlater]").then(()=>{Observer.childListSubtree("li.nav-item[report-id*=watchlater]",()=>{a(".av-item>a",".av-about>a","div.watch-later-m>ul>div>li>a");SpinQuery.select(".read-more.mr",e=>e.remove());SpinQuery.select(".read-more-grp>.read-more",e=>{e.style.width="auto";e.style.float="none"})})});SpinQuery.select(".van-popper-favorite").then(async e=>{if(!e){return}const t=Observer.childListSubtree(e,()=>{const i=e.querySelector(".play-all");if(i){const e="//www.bilibili.com/watchlater/#/list";Observer.attributes(i,()=>{if(i.firstElementChild===null||i.lastChild===null){return}if(i.getAttribute("href")==="//www.bilibili.com/watchlater/"){i.setAttribute("href",e);i.firstElementChild.classList.remove("bili-icon_dingdao_bofang");i.firstElementChild.classList.add("bili-icon_xinxi_yuedushu");i.lastChild.nodeValue="查看全部"}else if(i.getAttribute("href")!==e){i.firstElementChild.classList.add("bili-icon_dingdao_bofang");i.firstElementChild.classList.remove("bili-icon_xinxi_yuedushu");i.lastChild.nodeValue="播放全部"}});t.forEach(e=>e.stop())}})})}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/watchlater-api.min.js"] = (()=>{return(t,i)=>{const e=async(t,i)=>{const e=i?"https://api.bilibili.com/x/v2/history/toview/add":"https://api.bilibili.com/x/v2/history/toview/del";const a=getCsrf();const s=await Ajax.postTextWithCredentials(e,`aid=${t}&csrf=${a}`);const r=JSON.parse(s);if(r.code!==0){throw new Error(`稍后再看操作失败: ${r.message}`)}};async function a(t=false){const i=`https://api.bilibili.com/x/v2/history/toview/web`;const e=await Ajax.getJsonWithCredentials(i);if(e.code!==0){throw new Error(`获取稍后再看列表失败: ${e.message}`)}if(!e.data.list){return[]}if(t){return e.data.list}return e.data.list.map(t=>t.aid)}return{export:{toggleWatchlater:e,getWatchlaterList:a}}}})(); offlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/min/watchlater-expire-warnings.min.js"] = (()=>{return(e,n)=>{(async()=>{if(!["//www.bilibili.com/watchlater/#/list"].some(e=>document.URL.includes(e))){return}const{getWatchlaterList:t}=await n.importAsync("watchlater-api");const i=await SpinQuery.select(".watch-later-list .list-box");if(i===null){return}n.applyStyleFromText(`\n .expire-warning {\n padding: 3px 25px;\n color: #F78C6C;\n display: inline-flex;\n align-items: center;\n }\n .expire-warning .mdi {\n line-height: 1;\n margin-right: 8px;\n font-size: 16px;\n }\n`,"watchlater-expire-warning-style");const r=e.watchlaterExpireWarningDays;const a=24*3600*1e3;const l=e=>{return(e-Number(new Date))/a};Observer.childListSubtree(i,async()=>{const e=[...i.querySelectorAll(".av-item .state")];const n=await t(true);e.forEach((e,t)=>{const i=n[t].add_at*1e3+60*a;const c=l(i);console.log(n[t].aid,c);if(c还剩${n}天过期`)}}else{e.querySelectorAll(".expire-warning").forEach(e=>e.remove())}})})})()}})(); - -class ResourceType { - constructor (name, preprocessor) { - this.name = name - this.preprocessor = preprocessor || (text => text) - } - static fromUrl (url) { - if (url.indexOf('.css') !== -1) { - return this.style - } else if (url.indexOf('.html') !== -1 || url.indexOf('.htm') !== -1) { - return this.html - } else if (url.indexOf('.js') !== -1) { - return this.script - } else if (url.indexOf('.txt') !== -1) { - return this.text - } else { - return this.unknown - } - } - static get style () { - return new ResourceType('style') - } - static get html () { - return new ResourceType('html') - } - static get script () { - return new ResourceType('script') - } - static get text () { - return new ResourceType('text') - } - static get unknown () { - return new ResourceType('unknown') - } -} - -class Resource { - get downloaded () { - return this.text !== null - } - constructor (url, { styles = [], alwaysPreview = false } = {}) { - this.relativePath = 'min/' + url - this.rawUrl = Resource.root + 'min/' + url - this.dependencies = [] - this.styles = styles - this.text = null - this.key = null - this.alwaysPreview = alwaysPreview - this.type = ResourceType.fromUrl(url) - this.displayName = '' - } - get url () { - if (typeof offlineData === 'undefined' && this.alwaysPreview) { - return this.rawUrl.replace('/master/', '/preview/') - } - return this.rawUrl - } - flatMapPolyfill () { - if (Array.prototype.flatMap === undefined) { - const flatMap = function (mapFunc) { - return this - .map(mapFunc) - .reduce((acc, it) => acc.concat(it), []) - } - return flatMap - } else { - return Array.prototype.flatMap - } - } - loadCache () { - const key = this.key - if (!settings.cache || !settings.cache[key]) { - return null - } else { - return settings.cache[key] - } - } - async download () { - const key = this.key - return new Promise((resolve, reject) => { - if (this.downloaded) { - resolve(this.text) - } else { - const flattenStyles = this.flatMapPolyfill() - .bind(this.styles)(it => typeof it === 'object' ? it.key : it) - Promise.all(this.dependencies - .concat(flattenStyles.map(it => Resource.all[it])) - .map(r => r.download()) - ) - .then(() => { - this.text=this.type.preprocessor(offlineData[this.url]);resolve(this.text); - }) - } - }) - } - getStyle (id) { - const style = this.text - if (style === null) { - console.error(`Attempt to get style which is not downloaded. key = ${this.key}`) - } - const styleElement = document.createElement('style') - styleElement.id = id - styleElement.innerText = style - return styleElement - } - getPriorStyle () { - if (this.priority !== undefined) { - let insertPosition = this.priority - 1 - let formerStyle = $(`style[priority='${insertPosition}']`) - while (insertPosition >= 0 && formerStyle.length === 0) { - formerStyle = $(`style[priority='${insertPosition}']`) - insertPosition-- - } - if (insertPosition < 0) { - return null - } else { - return formerStyle - } - } else { - return null - } - } - applyStyle (id, important) { - if (!document.querySelector(`#${id}`)) { - const style = this.getStyle(id) - if (important) { - document.body.insertAdjacentElement('beforeend', style) - } else { - document.head.insertAdjacentElement('afterbegin', style) - } - } - } -} - -Resource.manifest = { - style: { - path: 'style.min.css' - }, - oldStyle: { - path: 'old.min.css' - }, - scrollbarStyle: { - path: 'scrollbar.min.css' - }, - darkStyle: { - path: 'dark.min.css', - alwaysPreview: true - }, - darkStyleImportant: { - path: 'dark-important.min.css', - alwaysPreview: true - }, - darkStyleNavBar: { - path: 'dark-navbar.min.css', - alwaysPreview: true - }, - touchPlayerStyle: { - path: 'touch-player.min.css' - }, - navbarOverrideStyle: { - path: 'override-navbar.min.css' - }, - noBannerStyle: { - path: 'no-banner.min.css' - }, - imageViewerStyle: { - path: 'image-viewer.min.css' - }, - imageViewerHtml: { - path: 'image-viewer.min.html' - }, - iconsStyle: { - path: 'icons.min.css' - }, - settingsSideBar: { - path: 'settings-side-bar.min.js' - }, - textValidate: { - path: 'text-validate.min.js' - }, - themeColors: { - path: 'theme-colors.min.js' - }, - settingsTooltipStyle: { - path: 'settings-tooltip.min.css' - }, - settingsTooltipJapanese: { - path: 'settings-tooltip.ja-JP.min.js' - }, - settingsTooltipChinese: { - path: 'settings-tooltip.zh-CN.min.js' - }, - settingsTooltipEnglish: { - path: 'settings-tooltip.en-US.min.js' - }, - settingsTooltip: { - path: 'settings-tooltip.loader.min.js', - dependencies: [ - 'settingsTooltipStyle' - ] - }, - settingsSearch: { - path: 'settings-search.min.js' - }, - guiSettings: { - path: 'gui-settings.min.js', - html: true, - style: 'instant', - dependencies: [ - 'textValidate', - 'settingsSideBar', - 'themeColors', - 'settingsTooltip', - 'settingsSearch', - ], - styles: [ - { - key: 'iconsStyle', - important: true, - }, - ], - displayNames: { - guiSettings: '设置', - blurSettingsPanel: '模糊设置面板背景', - clearCache: '清除缓存', - settingsTooltip: '设置项帮助', - settingsSearch: '搜索设置', - sideBarOffset: '侧栏垂直偏移量', - ajaxHook: '启用 Ajax Hook API', - scriptLoadingMode: '加载模式', - guiSettingsDockSide: '设置面板停靠位置', - foregroundColorMode: '文本颜色', - updateCdn: '更新源', - autoHideSideBar: '自动隐藏侧栏', - elegantScrollbar: '使用细滚动条', - }, - dropdown: [ - { - key: 'guiSettingsDockSide', - items: ['左侧', '右侧'] - }, - { - key: 'foregroundColorMode', - items: ['自动', '黑色', '白色'], - }, - { - key: 'scriptLoadingMode', - items: ['同时', '延后', '同时(自动)', '延后(自动)'] - }, - { - key: 'updateCdn', - items: ['jsDelivr', 'GitHub'], - } - ], - }, - useDarkStyle: { - path: 'dark-styles.min.js', - reloadable: true, - alwaysPreview: true, - styles: [ - 'darkStyle', - { - key: 'darkStyleNavBar', - important: true, - condition () { - return !settings.useNewStyle && ($('#banner_link').length === 0 || - $('#banner_link').length > 0 && - settings.overrideNavBar && - !settings.showBanner) - } - }, - { - key: 'darkStyleImportant', - important: true, - condition: () => true - } - ], - displayNames: { - useDarkStyle: '夜间模式', - useDarkStyleAsUserStyle: 'UserStyle 模式', - } - }, - tweetsStyle: { - path: 'tweets.min.css' - }, - hideBanner: { - path: 'hide-banner.min.js', - reloadable: true, - style: 'instant', - displayNames: { - hideBanner: '隐藏顶部横幅' - } - }, - touchNavBar: { - path: 'touch-navbar.min.js', - displayNames: { - touchNavBar: '顶栏触摸优化' - } - }, - touchVideoPlayer: { - path: 'touch-player.min.js', - styles: [ - 'touchPlayerStyle' - ], - displayNames: { - touchVideoPlayer: '播放器触摸支持', - touchVideoPlayerAnimation: '启用实验性动画效果', - touchVideoPlayerDoubleTapControl: '启用双击控制' - } - }, - expandDanmakuList: { - path: 'expand-danmaku.min.js', - displayNames: { - expandDanmakuList: '自动展开弹幕列表' - } - }, - removeAds: { - path: 'remove-promotions.min.js', - style: 'instant', - displayNames: { - removeAds: '删除广告', - showBlockedAdsTip: '显示占位文本', - removeGameMatchModule: '删除电竞赛事', - preserveEventBanner: '保留活动横幅', - } - }, - watchLaterRedirect: { - path: 'watchlater.min.js', - displayNames: { - watchLaterRedirect: '稍后再看重定向' - } - }, - hideTopSearch: { - path: 'hide-top-search.min.js', - displayNames: { - hideTopSearch: '隐藏搜索推荐' - } - }, - harunaScale: { - path: 'haruna-scale.min.js', - reloadable: true, - displayNames: { - harunaScale: '缩放直播看板娘' - } - }, - removeLiveWatermark: { - path: 'remove-watermark.min.js', - reloadable: true, - displayNames: { - removeLiveWatermark: '删除直播水印' - } - }, - fullTweetsTitle: { - path: 'full-tweets-title.min.js', - reloadable: true, - style: 'instant', - displayNames: { - fullTweetsTitle: '展开动态标题' - } - }, - fullPageTitle: { - path: 'full-page-title.min.js', - style: 'instant', - reloadable: true, - displayNames: { - fullPageTitle: '展开选集列表' - } - }, - viewCover: { - path: 'view-cover.min.js', - dependencies: [ - 'imageViewerHtml', - 'videoInfo', - 'title' - ], - styles: [ - 'imageViewerStyle' - ], - displayNames: { - viewCover: '查看封面' - } - }, - notifyNewVersion: { - path: 'notify-new-version.min.js', - displayNames: { - notifyNewVersion: '检查更新' - } - }, - toast: { - path: 'toast.min.js', - style: 'instant', - displayNames: { - toast: '显示消息', - toastInternalError: '显示内部错误消息' - } - }, - removeVideoTopMask: { - path: 'remove-top-mask.min.js', - reloadable: true, - displayNames: { - removeVideoTopMask: '删除视频标题层' - } - }, - blurVideoControl: { - path: 'blur-video-control.min.js', - reloadable: true, - style: 'instant', - displayNames: { - blurVideoControl: '模糊视频控制栏背景' - } - }, - darkSchedule: { - path: 'dark-schedule.min.js', - displayNames: { - darkSchedule: '夜间模式计划时段', - darkScheduleStart: '起始时间', - darkScheduleEnd: '结束时间' - } - }, - clearCache: { - path: 'clear-cache.min.js', - displayNames: { - useCache: '启用缓存' - } - }, - videoDownloadPackage: { - path: 'download-video-package.min.js', - }, - downloadVideo: { - path: 'download-video.min.js', - html: true, - style: 'instant', - dependencies: ['title', 'videoInfo', 'videoDownloadPackage'], - displayNames: { - 'downloadVideo': '下载视频', - 'videoDownloadPackage': '下载视频打包器', - 'batchDownload': '批量下载', - 'aria2Rpc': 'aria2 RPC', - } - }, - downloadDanmaku: { - path: 'download-danmaku.min.js', - dependencies: [ - 'title', - 'videoInfo', - 'danmakuConverter' - ], - displayNames: { - 'downloadDanmaku': '下载弹幕' - } - }, - danmakuConverter: { - path: 'danmaku-converter.min.js' - }, - videoInfo: { - path: 'video-info.min.js' - }, - videoStory: { - path: 'video-story.min.js' - }, - about: { - path: 'about.min.js', - alwaysPreview: true, - html: true, - style: 'important', - displayNames: { - 'about': '关于' - } - }, - customControlBackground: { - path: 'custom-control-background.min.js', - reloadable: true, - style: { - key: 'customControlBackgroundStyle', - condition: () => settings.customControlBackgroundOpacity > 0 - }, - displayNames: { - customControlBackground: '控制栏着色', - customControlBackgroundOpacity: '不透明度' - } - }, - useDefaultPlayerMode: { - path: 'default-player-mode.min.js', - displayNames: { - useDefaultPlayerMode: '使用默认播放器模式', - defaultPlayerMode: '默认播放器模式', - autoLightOff: '播放时自动关灯', - applyPlayerModeOnPlay: '播放时应用模式' - }, - dropdown: { - key: 'defaultPlayerMode', - items: ['常规', '宽屏', '网页全屏', '全屏'] - } - }, - useDefaultVideoQuality: { - path: 'default-video-quality.min.js', - displayNames: { - useDefaultVideoQuality: '使用默认视频画质', - defaultVideoQuality: '画质设定' - }, - dropdown: { - key: 'defaultVideoQuality', - items: ['4K', '1080P60', '1080P+', '1080P', '720P60', '720P', '480P', '360P', '自动'] - } - }, - comboLike: { - path: 'combo-like.min.js', - displayNames: { - comboLike: '素质三连触摸支持' - } - }, - autoContinue: { - path: 'auto-continue.min.js', - displayNames: { - autoContinue: '自动从历史记录点播放', - allowJumpContinue: '允许跨集跳转' - } - }, - expandDescription: { - path: 'expand-description.min.js', - style: 'instant', - displayNames: { - expandDescription: '自动展开视频简介' - } - }, - defaultDanmakuSettingsStyle: { - path: 'default-danmaku-settings.min.css' - }, - useDefaultDanmakuSettings: { - path: 'default-danmaku-settings.min.js', - styles: [ - { - key: 'defaultDanmakuSettingsStyle', - condition: () => settings.rememberDanmakuSettings - } - ], - displayNames: { - useDefaultDanmakuSettings: '使用默认弹幕设置', - enableDanmaku: '开启弹幕', - rememberDanmakuSettings: '记住弹幕设置' - } - }, - skipChargeList: { - path: 'skip-charge-list.min.js', - style: 'instant', - displayNames: { - skipChargeList: '跳过充电鸣谢' - } - }, - playerLayout: { - path: 'default-player-layout.min.js', - displayNames: { - playerLayout: '指定播放器布局', - useDefaultPlayerLayout: '指定播放器布局', - defaultPlayerLayout: '视频区布局', - defaultBangumiLayout: '番剧区布局' - }, - dropdown: [ - { - key: 'defaultPlayerLayout', - items: ['旧版', '新版'] - }, - { - key: 'defaultBangumiLayout', - items: ['旧版', '新版'] - } - ] - }, - compactLayout: { - path: 'compact-layout.min.js', - reloadable: true, - style: true, - displayNames: { - compactLayout: '首页使用紧凑布局' - } - }, - medalHelper: { - path: 'medal-helper.min.js', - html: true, - style: 'instant', - displayNames: { - medalHelper: '直播勋章快速更换', - autoMatchMedal: '自动选择当前直播间勋章', - } - }, - showDeadVideoTitle: { - path: 'show-dead-video-title.min.js', - displayNames: { - showDeadVideoTitle: '显示失效视频信息', - useBiliplusRedirect: '失效视频重定向', - deadVideoTitleProvider: '信息来源', - }, - // dropdown: { - // key: 'deadVideoTitleProvider', - // items: ['稍后再看'], - // }, - }, - autoPlay: { - path: 'auto-play.min.js', - displayNames: { - autoPlay: '自动播放视频' - } - }, - useCommentStyle: { - path: 'comment.min.js', - reloadable: true, - style: 'important', - displayNames: { - useCommentStyle: '简化评论区' - } - }, - title: { - path: 'title.min.js', - displayNames: { - filenameFormat: '文件命名格式', - batchFilenameFormat: '批量命名格式', - } - }, - imageResolution: { - path: 'image-resolution.min.js', - displayNames: { - imageResolution: '高分辨率图片' - } - }, - biliplusRedirect: { - path: 'biliplus-redirect.min.js', - displayNames: { - biliplusRedirect: 'BiliPlus跳转支持' - } - }, - framePlayback: { - path: 'frame-playback.min.js', - reloadable: true, - style: 'instant', - html: true, - displayNames: { - framePlayback: '启用逐帧调整' - } - }, - downloadAudio: { - path: 'download-audio.min.js', - displayNames: { - downloadAudio: '下载音频' - } - }, - i18n: { - path: 'i18n.min.js', - alwaysPreview: true, - style: 'important', - displayNames: { - i18n: '界面翻译', - i18nLanguage: '语言', - }, - dropdown: { - key: 'i18nLanguage', - // items: Object.keys(languageCodeMap), - items: [`日本語`, `English`] - } - }, - i18nEnglish: { - path: 'i18n.en-US.min.js', - alwaysPreview: true - }, - i18nJapanese: { - path: 'i18n.ja-JP.min.js', - alwaysPreview: true - }, - i18nTraditionalChinese: { - path: 'i18n.zh-TW.min.js', - alwaysPreview: true - }, - i18nGerman: { - path: 'i18n.de-DE.min.js', - alwaysPreview: true - }, - playerFocus: { - path: 'player-focus.min.js', - displayNames: { - playerFocus: '自动定位到播放器', - playerFocusOffset: '定位偏移量' - } - }, - simplifyLiveroom: { - path: 'simplify-liveroom.min.js', - style: 'important', - displayNames: { - simplifyLiveroom: '简化直播间' - } - }, - oldTweets: { - path: 'old-tweets.min.js', - displayNames: { - oldTweets: '旧版动态跳转支持' - } - }, - customNavbarComponent: { - path: 'custom-navbar-component.min.js', - }, - customNavbar: { - path: 'custom-navbar.min.js', - reloadable: true, - style: 'instant', - html: true, - dependencies: ['customNavbarComponent'], - displayNames: { - customNavbar: '使用自定义顶栏', - customNavbarComponent: '顶栏组件', - customNavbarSeasonLogo: '使用季节Logo', - customNavbarFill: '主题色填充', - customNavbarTransparent: '透明填充', - customNavbarShadow: '投影', - customNavbarCompact: '紧凑布局', - customNavbarBlur: '背景模糊', - customNavbarBlurOpacity: '模糊层不透明度', - allNavbarFill: '填充其他顶栏' - } - }, - favoritesRedirect: { - path: 'favorites-redirect.min.js', - displayNames: { - favoritesRedirect: '收藏夹视频重定向' - } - }, - outerWatchlater: { - path: 'outer-watchlater.min.js', - reloadable: true, - style: true, - displayNames: { - outerWatchlater: '外置稍后再看' - } - }, - playerShadow: { - path: 'player-shadow.min.js', - reloadable: true, - displayNames: { - playerShadow: '播放器投影' - } - }, - narrowDanmaku: { - path: 'narrow-danmaku.min.js', - reloadable: true, - displayNames: { - narrowDanmaku: '强制保留弹幕栏' - } - }, - hideOldEntry: { - path: 'hide-old-entry.min.js', - reloadable: true, - displayNames: { - hideOldEntry: '隐藏返回旧版' - } - }, - videoScreenshot: { - path: 'screenshot.min.js', - reloadable: true, - style: true, - displayNames: { - videoScreenshot: '启用视频截图' - }, - dependencies: [ - 'title' - ] - }, - hideBangumiReviews: { - path: 'hide-bangumi-reviews.min.js', - reloadable: true, - displayNames: { - hideBangumiReviews: '隐藏番剧点评' - } - }, - noLiveAutoplay: { - path: 'no-live-autoplay.min.js', - displayNames: { - noLiveAutoplay: '禁止直播首页自动播放', - hideHomeLive: '隐藏首页推荐直播', - } - }, - noMiniVideoAutoplay: { - path: 'no-mini-video-autoplay.min.js', - displayNames: { - noMiniVideoAutoplay: '禁止小视频自动播放', - } - }, - hideCategory: { - path: 'hide-category.min.js', - reloadable: true, - style: 'instant', - displayNames: { - hideCategory: '隐藏分区栏', - }, - }, - foldComment: { - path: 'fold-comment.min.js', - style: true, - displayNames: { - foldComment: '快速收起动态评论区', - }, - }, - useDefaultVideoSpeed: { - path: 'default-video-speed.min.js', - displayNames: { - useDefaultVideoSpeed: '使用默认播放速度', - defaultVideoSpeed: '默认播放速度', - }, - dropdown: { - key: 'defaultVideoSpeed', - items: ['0.5', '0.75', '1.0', '1.25', '1.5', '2.0'], - } - }, - seedsToCoins: { - path: 'seeds-to-coins.min.js', - displayNames: { - seedsToCoins: '瓜子换硬币', - autoSeedsToCoins: '自动运行', - }, - }, - magicGrid: { - path: 'magic-grid.min.js', - displayNames: { - magicGrid: 'Magic Grid', - }, - }, - autoDraw: { - path: 'auto-draw.min.js', - displayNames: { - autoDraw: '直播间自动领奖', - }, - }, - keymap: { - path: 'keymap.min.js', - reloadable: true, - displayNames: { - keymap: '快捷键扩展', - }, - }, - doubleClickFullscreen: { - path: 'double-click-fullscreen.min.js', - displayNames: { - doubleClickFullscreen: '双击全屏', - }, - }, - simplifyHome: { - path: 'simplify-home.min.js', - style: 'instant', - displayNames: { - simplifyHome: '简化首页', - simplifyHomeStyle: '首页风格', - }, - dropdown: { - key: 'simplifyHomeStyle', - items: ['清爽', '极简'], - }, - }, - fullActivityContent: { - path: 'full-activity-content.min.js', - reloadable: true, - displayNames: { - fullActivityContent: '展开动态内容', - }, - }, - activityImageSaver: { - path: 'activity-image-saver.min.js', - displayNames: { - activityImageSaver: '解除动态存图限制', - }, - }, - selectableColumnText: { - path: 'selectable-column-text.min.js', - reloadable: true, - displayNames: { - selectableColumnText: '专栏文字选择', - }, - }, - watchlaterExpireWarnings: { - path: 'watchlater-expire-warnings.min.js', - displayNames: { - watchlaterExpireWarnings: '稍后再看期限提醒', - }, - }, - superchatTranslate: { - path: 'superchat-translate.min.js', - style: true, - displayNames: { - superchatTranslate: '醒目留言翻译', - }, - }, - miniPlayerTouchMove: { - path: 'mini-player-touch-move.min.js', - style: true, - reloadable: true, - displayNames: { - miniPlayerTouchMove: '迷你播放器触摸拖动', - }, - }, - feedsFilter: { - path: 'feeds-filter.min.js', - reloadable: true, - displayNames: { - feedsFilter: '动态过滤器', - }, - }, - hideBangumiSponsors: { - path: 'hide-bangumi-sponsors.min.js', - reloadable: true, - displayNames: { - hideBangumiSponsors: '隐藏番剧承包', - }, - }, - hideRecommendLive: { - path: 'hide-recommend-live.min.js', - reloadable: true, - displayNames: { - hideRecommendLive: '隐藏推荐直播', - }, - }, - hideRelatedVideos: { - path: 'hide-related-videos.min.js', - reloadable: true, - displayNames: { - hideRelatedVideos: '隐藏视频推荐', - }, - }, - urlParamsClean: { - path: 'url-params-clean.min.js', - displayNames: { - urlParamsClean: '网址参数清理', - }, - }, - collapseLiveSideBar: { - path: 'collapse-live-side-bar.min.js', - style: 'instant', - reloadable: true, - displayNames: { - collapseLiveSideBar: '收起直播间侧栏', - }, - }, - downloadSubtitle: { - path: 'download-subtitle.min.js', - displayNames: { - downloadSubtitle: '下载字幕', - }, - }, - feedsTranslate: { - path: 'feeds-translate.min.js', - style: true, - displayNames: { - feedsTranslate: '动态翻译', - feedsTranslateProvider: '翻译器', - }, - dropdown: { - key: 'feedsTranslateProvider', - items: ['Bing', 'Google', 'GoogleCN'], - }, - }, - recordLiveDanmaku: { - path: 'record-live-danmaku.min.js', - displayNames: { - recordLiveDanmaku: '直播弹幕记录器', - }, - }, - useDefaultLiveQuality: { - path: 'default-live-quality.min.js', - displayNames: { - useDefaultLiveQuality: '使用默认直播画质', - defaultLiveQuality: '默认直播画质', - }, - dropdown: { - key: 'defaultLiveQuality', - items: ['原画', '蓝光', '超清', '高清', '流畅'], - }, - }, - downloadLiveRecords: { - path: 'download-live-records.min.js', - displayNames: { - downloadLiveRecords: '下载直播录像', - }, - }, - bvidConvert: { - path: 'bvid-convert.min.js', - style: true, - displayNames: { - bvidConvert: 'BV号转换', - preferAvUrl: '网址AV号转换', - }, - }, - fixedSidebars: { - path: 'fixed-sidebars.min.js', - reloadable: true, - displayNames: { - fixedSidebars: '强制固定顶栏与侧栏', - }, - }, - livePip: { - path: 'live-pip.min.js', - displayNames: { - livePip: '直播画中画', - }, - }, - extendFeedsLive: { - path: 'extend-feeds-live.min.js', - style: true, - displayNames: { - extendFeedsLive: '直播信息扩充', - }, - }, - playerOnTop: { - path: 'player-on-top.min.js', - reloadable: true, - displayNames: { - playerOnTop: '播放器置顶', - }, - }, - darkColorScheme: { - path: 'dark-color-scheme.min.js', - displayNames: { - darkColorScheme: '夜间模式跟随系统', - }, - }, - restoreFloors: { - path: 'restore-floors.min.js', - displayNames: { - restoreFloors: '评论楼层显示', - }, - }, - quickFavorite: { - path: 'quick-favorite.min.js', - style: true, - reloadable: true, - displayNames: { - quickFavorite: '启用快速收藏', - }, - }, -} -const resourceManifest = Resource.manifest - -class StyleManager { - constructor (resources) { - this.resources = resources - } - getDefaultStyleId (key) { - return key.replace(/([a-z][A-Z])/g, - g => `${g[0]}-${g[1].toLowerCase()}`) - } - applyStyle (key, id) { - if (id === undefined) { - id = this.getDefaultStyleId(key) - } - Resource.all[key].applyStyle(id, false) - } - removeStyle (key) { - const style = document.querySelector(`#${this.getDefaultStyleId(key)}`) - style && style.remove() - } - applyImportantStyle (key, id) { - if (id === undefined) { - id = this.getDefaultStyleId(key) - } - Resource.all[key].applyStyle(id, true) - } - applyStyleFromText (text, id) { - if (!id) { - document.head.insertAdjacentHTML('afterbegin', text) - } else { - const style = document.createElement('style') - style.id = id - style.innerHTML = text - document.head.insertAdjacentElement('afterbegin', style) - } - } - applyImportantStyleFromText (text, id) { - if (!id) { - document.body.insertAdjacentHTML('beforeend', text) - } else { - const style = document.createElement('style') - style.id = id - style.innerHTML = text - document.body.insertAdjacentElement('beforeend', style) - } - } - getStyle (key, id) { - return Resource.all[key].getStyle(id) - } - fetchStyleByKey (key) { - if (settings[key] !== true) { - return - } - const resource = Resource.all[key] - if (!resource || !resource.styles) { - return - } - if (key === 'useDarkStyle' && settings.useDarkStyleAsUserStyle) { - return - } - resource.styles - .filter(it => it.condition !== undefined ? it.condition() : true) - .forEach(it => { - const important = typeof it === 'object' ? it.important : false - const styleKey = typeof it === 'object' ? it.key : it - Resource.all[styleKey].download().then(() => { - if (important) { - contentLoaded(() => this.applyImportantStyle(styleKey)) - } else { - this.applyStyle(styleKey) - } - }) - }) - } - prefetchStyles () { - for (const key in Resource.all) { - if (typeof offlineData !== 'undefined' || settings.useCache && settings.cache[key]) { - this.fetchStyleByKey(key) - } - } - for (const style of settings.customStyles.filter(it => it.mode === 'instant' && it.enabled)) { - this.applyStyleFromText(style.style, this.getDefaultStyleId(style.name)) - } - } - applyCustomStyles() { - for (const style of settings.customStyles.filter(it => it.mode !== 'instant' && it.enabled)) { - this[style.mode === 'important' ? 'applyImportantStyleFromText' : 'applyStyleFromText'](style.style, this.getDefaultStyleId(style.name)) - } - } -} - -class ResourceManager { - constructor () { - this.data = Resource.all - this.skippedImport = [] - this.attributes = {} - this.styleManager = new StyleManager(this) - const styleMethods = Object.getOwnPropertyNames(StyleManager.prototype).filter(it => it !== 'constructor') - for (const key of styleMethods) { - this[key] = function (...params) { - this.styleManager[key](...params) - } - } - this.setupColors() - } - setupColors () { - this.color = new ColorProcessor(settings.customStyleColor) - settings.foreground = this.color.foreground - settings.blueImageFilter = this.color.blueImageFilter - settings.pinkImageFilter = this.color.pinkImageFilter - settings.brightness = this.color.brightness - settings.filterInvert = this.color.filterInvert - - const hexToRgba = input => this.color.rgbToString(this.color.hexToRgba(input)) - let styles = [] - styles.push('--theme-color:' + settings.customStyleColor) - for (let opacity = 10; opacity <= 90; opacity += 10) { - const color = this.color.hexToRgba(settings.customStyleColor) - color.a = opacity / 100 - styles.push(`--theme-color-${opacity}:` + this.color.rgbToString(color)) - } - styles.push('--foreground-color:' + settings.foreground) - styles.push('--foreground-color-b:' + hexToRgba(settings.foreground + 'b')) - styles.push('--foreground-color-d:' + hexToRgba(settings.foreground + 'd')) - styles.push('--blue-image-filter:' + settings.blueImageFilter) - styles.push('--pink-image-filter:' + settings.pinkImageFilter) - styles.push('--brightness:' + settings.brightness) - styles.push('--invert-filter:' + settings.filterInvert) - styles.push('--blur-background-opacity:' + settings.blurBackgroundOpacity) - // styles.push("--custom-control-background-opacity:" + settings.customControlBackgroundOpacity); - this.applyStyleFromText(`html{${styles.join(';')}}`, 'bilibili-evolved-variables') - } - resolveComponentName (componentName) { - const filename = '/' + componentName.substring(componentName.lastIndexOf('/') + 1) + '.min.js' - for (const [name, value] of Object.entries(Resource.all)) { - if (value.url.endsWith(filename)) { - return name - } - } - if (componentName.endsWith('Html') || componentName.endsWith('Style')) { - return componentName - } - return filename.replace('/', '') - } - resolveComponent (componentName) { - const name = this.resolveComponentName(componentName) - let resource = Resource.all[name] - if (!resource) { - resource = new Resource(name) - let key = name.substring(0, name.indexOf('.')).replace(/-\w/g, t => t.substr(1).toUpperCase()) - if (name.includes('.vue.')) { - key += 'Component' - } - resource.key = key - if (resource.text === undefined) { - resource.text = null - } - Resource.all[key] = resource - } - return resource - } - importAsync (componentName) { - return new Promise(resolve => { - const resource = this.resolveComponent(componentName) - if (!resource) { - resolve(unsafeWindow.bilibiliEvolved) - } - if (!Object.keys(this.attributes).includes(resource.key)) { - if (resource.type.name === 'html' || resource.type.name === 'style') { - resource.download().then(() => resolve(this.import(componentName))) - } else { - this.fetchByKey(resource.key).then(() => resolve(this.import(componentName))) - } - } else { - resolve(this.import(componentName)) - } - }) - } - import (componentName) { - const resource = this.resolveComponent(componentName) - if (!resource) { - return unsafeWindow.bilibiliEvolved - } - if (resource.type.name === 'html' || resource.type.name === 'style') { - if (!resource.downloaded) { - console.error(`Import failed: component "${componentName}" is not loaded.`) - return null - } - return resource.text - } else { - const attribute = this.attributes[this.resolveComponentName(componentName)] - if (attribute === undefined) { - console.error(`Import failed: component "${componentName}" is not loaded.`) - return null - } - return attribute.export - } - } - async fetchByKey (key) { - const resource = Resource.all[key] - if (!resource) { - return null - } - const text = await resource.download().catch(reason => { - console.error(`Download error, XHR status: ${reason}`) - let toastMessage = `无法下载组件${Resource.all[key].displayName}` - if (settings.toastInternalError) { - toastMessage += '\n' + reason - } - Toast.error(toastMessage, '错误') - }) - // await Promise.all(resource.dependencies - // .filter(it => it.type.name === 'style') - // .map(it => this.styleManager.fetchStyleByKey(it.key))) - await Promise.all(resource.dependencies - .filter(it => it.type.name === 'script') - .map(it => this.fetchByKey(it.key))) - this.applyComponent(key, text) - } - async fetch () { - const isCacheValid = this.validateCache() - // let loadingToast = null - if (settings.toast === true) { - await this.fetchByKey('toast') - unsafeWindow.bilibiliEvolved.Toast = Toast = this.attributes.toast.export.Toast || this.attributes.toast.export - // if (!isCacheValid && settings.useCache) { - // loadingToast = Toast.info(/* html */`
正在初始化脚本`, '初始化') - // } - } - const promises = [] - for (const key in settings) { - if (settings[key] === true && key !== 'toast') { - await this.styleManager.fetchStyleByKey(key) - const promise = this.fetchByKey(key) - if (promise) { - promises.push(promise) - } - } - } - await Promise.all(promises) - // if (loadingToast) { - // loadingToast.dismiss() - // } - this.applyReloadables() // reloadables run sync - this.styleManager.applyCustomStyles() - // await this.applyDropdownOptions(); - // this.applyWidgets() // No need to wait the widgets - if (!isOffline() && settings.scriptDownloadMode === 'bundle') { - console.log('scheduled bundle update') - const checkUpdates = () => { - console.log('downloading bundle') - this.checkUpdates(!isCacheValid) - } - if ('requestIdleCallback' in unsafeWindow && GM.info.scriptHandler !== 'Violentmonkey') { - unsafeWindow.requestIdleCallback(checkUpdates) - } else { - fullyLoaded(checkUpdates) - } - } - } - applyReloadables () { - const checkAttribute = (key, attributes) => { - if (attributes.reload && attributes.unload) { - addSettingsListener(key, newValue => { - if (newValue === true) { - attributes.reload() - } else { - attributes.unload() - } - }) - } - } - for (const key of Resource.reloadables) { - const attributes = this.attributes[key] - if (attributes === undefined) { - const fetchListener = async newValue => { - if (newValue === true) { - const isDownloading = - typeof offlineData === 'undefined' && - (settings.useCache ? settings.cache[key] === undefined : true) - try { - if (isDownloading) { - const downloading = document.createElement('i') - downloading.classList.add('mdi', 'mdi-18px', 'downloading', 'mdi-download') - downloading.innerHTML = '下载中' - dq(`li[data-key=${key}] label`).insertAdjacentElement('beforeend', downloading) - dq(`input[key=${key}]`).disabled = true - } - await this.styleManager.fetchStyleByKey(key) - await this.fetchByKey(key) - removeSettingsListener(key, fetchListener) - checkAttribute(key, this.attributes[key]) - } finally { - if (isDownloading) { - dq(`li[data-key=${key}] i.downloading`).remove() - dq(`input[key=${key}]`).disabled = false - } - } - } - } - addSettingsListener(key, fetchListener) - } else { - checkAttribute(key, attributes) - } - } - } - applyComponent (key, text) { - const func = typeof text === 'string' ? eval(text) : text - if (func) { - try { - const attribute = func(settings, this) || {} - this.attributes[key] = attribute - } catch (error) { - console.error(`Failed to apply feature "${key}": ${error}`) - const displayName = Resource.all[key].displayName - let toastMessage = `加载组件${displayName || key}失败` - if (settings.toastInternalError) { - toastMessage += '\n' + error - } - Toast.error(toastMessage, '错误') - } - } - } - async checkUpdates () { - if (isOffline()) { - return - } - // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest - // const getHash = async (message) => { - // const msgUint8 = new TextEncoder().encode(message) - // const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8) - // const hashArray = Array.from(new Uint8Array(hashBuffer)) - // const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('') - // return hashHex - // } - // if (fullDownload) { - const url = (Resource.cdnRoot || Resource.root) + 'min/bundle.zip' - const zip = new JSZip() - let isTimeout = true - setTimeout(() => { - if (isTimeout) { - console.log('bundle request timeout, saving onlineData to cache...') - let cache = {} - for (const [url, data] of Object.entries(onlineData)) { - const resource = Object.values(Resource.all).find(it => it.rawUrl === url) - if (resource) { - if (scriptVersion === 'Stable' && resource.alwaysPreview) { - continue - } - cache[resource.key] = data - } - } - settings.cache = Object.assign(settings.cache, cache) - } - }, 60 * 1000) - await zip.loadAsync(await Ajax.monkey({ - url, - responseType: 'blob', - })) - let latestVersion - const zipVersion = zip.file('version.txt') - if (zipVersion) { - latestVersion = await zipVersion.async('text') - console.log('zip version =', latestVersion) - } else { - latestVersion = await Ajax.monkey({ url: (Resource.cdnRoot || Resource.root) + 'version.txt' }) - console.log('txt version =', latestVersion) - } - isTimeout = false - if (settings.currentVersion !== latestVersion) { - console.log(`bundle version not match. current = ${settings.currentVersion}, latest = ${latestVersion}`) - return - } - let cache = {} - const files = zip.file(/.+/) - for (const file of files) { - const url = Resource.root + 'min/' + file.name - const resource = Object.values(Resource.all).find(it => it.rawUrl === url) - if (resource) { - if (scriptVersion === 'Stable' && resource.alwaysPreview) { - continue - } - const text = await file.async('text') - cache[resource.key] = text - // console.log(`bundle update: saved ${resource.key}`) - } - } - settings.cache = Object.assign(settings.cache, cache) - console.log('bundle updated') - // } else { - // const hashJson = await Ajax.monkey({ - // url: Resource.root + 'min/bundle.json', - // responseType: 'json', - // }) - // const scriptHashWrap = h => `(()=>{return${h}})();` - // await Promise.all(Object.entries(hashJson).map(async ([name, hash]) => { - // const url = Resource.root + 'min/' + name - // const resource = Object.values(Resource.all).find(it => it.rawUrl === url) - // if (!resource) { - // return - // } - // const cache = settings.cache[resource.key] - // if (cache) { - // const cacheHash = await getHash(cache) - // if (cacheHash.toLowerCase() !== hash.toLowerCase() && - // scriptHashWrap(cacheHash).toLowerCase() !== hash.toLowerCase()) { - // console.log(`hash not match: ${resource.key} (${cacheHash.toLowerCase()}) !== (${hash.toLowerCase()})`) - // await resource.download() - // settings.cache = Object.assign(settings.cache, { - // [resource.key]: resource.text - // }) - // console.log(`downloaded ${resource.key}`) - // } else { - // console.log(`checked hash: ${resource.key}`) - // } - // } - // })) - // } - - } - async applyWidget (info) { - let condition = true - if (typeof info.condition === 'function') { - condition = info.condition() - if (condition instanceof Promise && 'then' in condition) { - condition = await condition.catch(() => { return false }) - } - } - if (condition === true) { - if (info.content) { - document.querySelector('.widgets-container').insertAdjacentHTML('beforeend', info.content) - } - if (info.success) { - info.success() - } - } - } - async applyWidgets () { - await Promise.all(Object.values(this.attributes) - .filter(it => it.widget) - .map(it => this.applyWidget(it.widget)) - ) - } - async applyDropdownOptions () { - async function applyDropdownOption (info) { - if (Array.isArray(info)) { - await Promise.all(info.map(applyDropdownOption)) - } else { - const dropdownInput = dq(`.gui-settings-dropdown input[key=${info.key}]`) - if (!dropdownInput) { - return - } - dropdownInput.value = settings[info.key] - dropdownInput.setAttribute('data-name', settings[info.key]) - const dropdown = dropdownInput.parentElement - const list = dropdown.querySelector('ul') - const input = dropdown.querySelector('input') - info.items.forEach(itemHtml => { - list.insertAdjacentHTML('beforeend', `
  • ${itemHtml}
  • `) - }) - list.querySelectorAll('li').forEach(li => li.addEventListener('click', () => { - input.value = li.innerText - input.setAttribute('data-name', li.getAttribute('data-name')) - settings[info.key] = li.getAttribute('data-name') - })) - } - } - const manifests = Object.values(Resource.manifest).filter(it => it.dropdown).map(it => it.dropdown) - Object.values(Resource.all) - // .concat(Object.values(this.attributes)) - .filter(it => it.dropdown) - .map(it => it.dropdown) - .forEach(it => { - if (!manifests.some(m => m.key === it.key)) { - manifests.push(it) - } - }) - await Promise.all(manifests.map(it => applyDropdownOption(it))) - } - toggleStyle (content, id, urlPattern) { - if (urlPattern !== undefined) { - const { include, exclude } = urlPattern - const url = document.URL - if (exclude && exclude.some(p => matchPattern(url, p))) { - return - } - if (include && include.every(p => !matchPattern(url, p))) { - return - } - } - if (id === undefined) { // content is resource name - this.styleManager.applyStyle(content) - return { - reload: () => this.styleManager.applyStyle(content), - unload: () => this.styleManager.removeStyle(content) - } - } else { // content is style text - this.styleManager.applyStyleFromText(content, id) - return { - reload: () => this.styleManager.applyStyleFromText(content, id), - unload: () => document.getElementById(id).remove() - } - } - } - validateCache () { - if (typeof offlineData !== 'undefined') { // offline version always has cache - return true - } - if (Object.getOwnPropertyNames(settings.cache).length === 0) { // has no cache - return false - } - if (settings.cache.version === undefined) { // Has newly downloaded cache - settings.cache = Object.assign(settings.cache, { version: settings.currentVersion }) - // settings.cache.version = settings.currentVersion; - return true - } - if (settings.cache.version !== settings.currentVersion) { // Has old version cache - settings.cache = {} - return false - } - return true // Has cache - } -} - -let scriptBlocker -const getScriptBlocker = async () => { - if (scriptBlocker) { - return scriptBlocker - } - let blockPatterns = (await GM.getValue('scriptBlockPatterns')) || [] - // 开启简化首页和自定义顶栏时, 阻断所有其他的非内联