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"] = `
`;
@@ -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"] = ``;
-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`;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`,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`,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=``;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}}
{{like}}{{coins}}{{favorites}}{{playCount}}{{danmakuCount}}
`;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')) || []
- // 开启简化首页和自定义顶栏时, 阻断所有其他的非内联