mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
4353 lines
2.1 MiB
4353 lines
2.1 MiB
// ==UserScript==
|
||
// @name Bilibili Evolved
|
||
// @version 1.8.20
|
||
// @description 强大的哔哩哔哩增强脚本: 下载视频, 音乐, 封面, 弹幕 / 自定义播放器画质, 模式, 布局 / 自定义顶栏, 删除广告, 夜间模式 / 触屏设备支持
|
||
// @author Grant Howard, Coulomb-G
|
||
// @copyright 2019, Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G)
|
||
// @license MIT
|
||
// @match *://*.bilibili.com/*
|
||
// @match *://*.bilibili.com
|
||
// @run-at document-start
|
||
// @updateURL https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.user.js
|
||
// @downloadURL https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.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
|
||
// @connect *
|
||
// @require https://code.jquery.com/jquery-3.4.0.min.js
|
||
// @require https://cdn.bootcss.com/jszip/3.1.5/jszip.min.js
|
||
// @require https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js
|
||
// @icon https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/images/logo-small.png
|
||
// @icon64 https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/images/logo.png
|
||
// ==/UserScript==
|
||
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().mouseout()
|
||
}
|
||
async function loadDanmakuSettingsPanel () {
|
||
const style = document.createElement('style')
|
||
style.innerText = `.bilibili-player-video-danmaku-setting-wrap { display: none !important; }`
|
||
document.body.insertAdjacentElement('beforeend', style)
|
||
await loadLazyPanel('.bilibili-player-video-danmaku-setting')
|
||
setTimeout(() => style.remove(), 300)
|
||
}
|
||
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) => document.querySelector(selector)
|
||
const dqa = (selector) => [...document.querySelectorAll(selector)]
|
||
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,<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"></svg>'
|
||
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]
|
||
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 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,
|
||
userInfo: 12,
|
||
messages: 13,
|
||
activities: 14,
|
||
bangumi: 15,
|
||
watchlaterList: 16,
|
||
favoritesList: 17,
|
||
historyList: 18,
|
||
upload: 19,
|
||
blank3: 20,
|
||
}
|
||
const settings = {
|
||
useDarkStyle: false,
|
||
compactLayout: false,
|
||
// showBanner: true,
|
||
hideBanner: false,
|
||
expandDanmakuList: true,
|
||
expandDescription: true,
|
||
watchLaterRedirect: true,
|
||
touchNavBar: false,
|
||
touchVideoPlayer: false,
|
||
customControlBackgroundOpacity: 0.64,
|
||
customControlBackground: true,
|
||
darkScheduleStart: '18:00',
|
||
darkScheduleEnd: '6:00',
|
||
darkSchedule: false,
|
||
blurVideoControl: 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: '旧版',
|
||
useDefaultPlayerLayout: false,
|
||
skipChargeList: false,
|
||
comboLike: false,
|
||
autoLightOff: false,
|
||
useCache: true,
|
||
autoContinue: false,
|
||
allowJumpContinue: false,
|
||
autoPlay: false,
|
||
deadVideoTitleProvider: '稍后再看',
|
||
useBiliplusRedirect: false,
|
||
biliplusRedirect: false,
|
||
framePlayback: true,
|
||
useCommentStyle: true,
|
||
imageResolution: false,
|
||
imageResolutionScale: 'auto',
|
||
toastInternalError: false,
|
||
i18n: false,
|
||
i18nLanguage: '日本語',
|
||
playerFocus: false,
|
||
playerFocusOffset: -10,
|
||
oldTweets: false,
|
||
simplifyLiveroom: false,
|
||
simplifyLiveroomSettings: {
|
||
vip: true,
|
||
fansMedal: true,
|
||
title: true,
|
||
userLevel: true,
|
||
guard: true,
|
||
systemMessage: true,
|
||
welcomeMessage: true,
|
||
giftMessage: true,
|
||
guardPurchase: true,
|
||
popup: false,
|
||
skin: false,
|
||
},
|
||
customNavbar: true,
|
||
customNavbarFill: false,
|
||
customNavbarShadow: true,
|
||
customNavbarCompact: false,
|
||
customNavbarBlur: true,
|
||
customNavbarBlurOpacity: 0.7,
|
||
customNavbarOrder: { ...customNavbarDefaultOrders },
|
||
customNavbarHidden: [],
|
||
customNavbarBoundsPadding: 5,
|
||
playerShadow: false,
|
||
narrowDanmaku: true,
|
||
favoritesRedirect: true,
|
||
outerWatchlater: true,
|
||
hideOldEntry: true,
|
||
videoScreenshot: false,
|
||
hideBangumiReviews: false,
|
||
filenameFormat: '[title][ - ep]',
|
||
sideBarOffset: 0,
|
||
noLiveAutoplay: false,
|
||
hideHomeLive: false,
|
||
noMiniVideoAutoplay: false,
|
||
useDefaultVideoSpeed: false,
|
||
defaultVideoSpeed: '1.0',
|
||
hideCategory: false,
|
||
foldComment: true,
|
||
downloadVideoDefaultDanmaku: '无',
|
||
aria2RpcOption: {
|
||
secretKey: '',
|
||
dir: '',
|
||
host: '127.0.0.1',
|
||
port: '6800',
|
||
method: 'get',
|
||
skipByDefault: false,
|
||
maxDownloadLimit: '',
|
||
},
|
||
searchHistory: [],
|
||
seedsToCoins: true,
|
||
autoSeedsToCoins: true,
|
||
lastSeedsToCoinsDate: 0,
|
||
autoDraw: false,
|
||
keymap: false,
|
||
doubleClickFullscreen: false,
|
||
doubleClickFullscreenPreventSingleClick: false,
|
||
cache: {},
|
||
}
|
||
const fixedSettings = {
|
||
guiSettings: true,
|
||
viewCover: true,
|
||
notifyNewVersion: true,
|
||
clearCache: true,
|
||
downloadVideo: true,
|
||
downloadDanmaku: true,
|
||
downloadAudio: true,
|
||
playerLayout: true,
|
||
medalHelper: true,
|
||
about: true,
|
||
forceWide: false,
|
||
useNewStyle: false,
|
||
overrideNavBar: false,
|
||
touchVideoPlayerAnimation: false,
|
||
allNavbarFill: false,
|
||
showDeadVideoTitle: false,
|
||
latestVersionLink: 'https://github.com/the1812/Bilibili-Evolved/raw/master/bilibili-evolved.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)
|
||
}
|
||
function loadSettings () {
|
||
for (const key in fixedSettings) {
|
||
settings[key] = fixedSettings[key]
|
||
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 = GM_getValue(key)
|
||
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
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
function saveSettings (newSettings) {
|
||
}
|
||
function onSettingsChange () {
|
||
console.warn('此功能已弃用.')
|
||
}
|
||
|
||
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)
|
||
})
|
||
}
|
||
}
|
||
// https://github.com/the1812/Bilibili-Evolved/issues/84
|
||
function setupAjaxHook () {
|
||
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)
|
||
}
|
||
}
|
||
|
||
function loadResources () {
|
||
Resource.root = 'https://raw.githubusercontent.com/the1812/Bilibili-Evolved/master/'
|
||
Resource.all = {}
|
||
Resource.displayNames = {}
|
||
Resource.reloadables = [
|
||
'useDarkStyle',
|
||
'hideBanner',
|
||
'customNavbar',
|
||
'playerShadow',
|
||
'narrowDanmaku',
|
||
'compactLayout',
|
||
'useCommentStyle',
|
||
'removeVideoTopMask',
|
||
'hideOldEntry',
|
||
'hideBangumiReviews',
|
||
'videoScreenshot',
|
||
'blurVideoControl',
|
||
'customControlBackground',
|
||
'harunaScale',
|
||
'removeLiveWatermark',
|
||
'framePlayback',
|
||
'hideCategory',
|
||
'fullTweetsTitle',
|
||
]
|
||
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.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 (element, callback) {
|
||
this.element = element
|
||
this.callback = callback
|
||
this.observer = null
|
||
this.options = undefined
|
||
}
|
||
start () {
|
||
if (this.element) {
|
||
this.observer = new MutationObserver(this.callback)
|
||
this.observer.observe(this.element, this.options)
|
||
}
|
||
return this
|
||
}
|
||
stop () {
|
||
this.observer && this.observer.disconnect()
|
||
return 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]
|
||
}
|
||
return elements.map(
|
||
it => {
|
||
const observer = new Observer(it, 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
|
||
if (color && this.grey < 0.35) {
|
||
return '#000'
|
||
}
|
||
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 onlineData = {};
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/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(-100%);transition:.3s cubic-bezier(0,.86,.58,1);display:flex;flex-direction:column;box-shadow:4px 0 16px 0 #0000}body.dark .bilibili-evolved-about{background:#222;color:#eee}.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..."}`;
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/about.min.html"] = `<div class=bilibili-evolved-about><div class=about-header><i class="mdi mdi-information-outline mdi-24px"></i><span class=about-title>关于</span></div><div class=about-content><p v-if=branch class="name light"v-html=logoImage><p v-if=branch class="name dark"v-html=logoImageDark><p class=version>v{{version}} · {{clientType}}<p class=love><a target=_blank href=https://github.com/the1812/Bilibili-Evolved/ >Made with ❤ </a><a target=_blank href=https://github.com/the1812/Bilibili-Evolved/blob/master/donate.md>Buy me a coffee ☕</a><section class=authors><span class=title>Authors</span><a class=author target=_blank v-for="author of authors"v-bind:href=author.link>{{author.name}}</a></section><section class=contributors><span class=title>Contributors</span><a class=contributor target=_blank v-for="contributor of contributors"v-bind:href=contributor.link>{{contributor.name}}</a></section><section class=supporters><a class=title target=_blank href=https://github.com/the1812/Bilibili-Evolved/blob/preview/donate.md#历史>View Supporters</a></section><section class=participants><span class=title>Community Power</span><span class=fetching v-if=fetching></span><a class=participant target=_blank v-for="participant of participants"v-bind:href=participant.link>{{participant.name}}</a></section><section class=websites><span class=title>Websites</span><a class=website target=_blank v-for="website of websites"v-bind:href=website.link>{{website.name}}</a></section><section class=components><span class=title>Components</span><a class=component target=_blank v-for="component of components"v-bind:href=component.link>{{component.name}}</a></section></div></div>`;
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/about.min.js"] = (()=>{return(t,e)=>{(async()=>{const i=await e.importAsync("aboutHtml");document.body.insertAdjacentHTML("beforeend",i);const o=(t,e)=>t.charCodeAt(0)-e.charCodeAt(0);const n=(t,e)=>o(t.name,e.name);const s=GM_info.script.name.match(/Bilibili Evolved \((.*)\)/);const a=s?s[1]:"Stable";new Vue({el:".bilibili-evolved-about",data:{version:t.currentVersion,clientType:a,logoImage:null,logoImageDark:null,branch:null,authors:[{name:"Grant Howard",link:"https://github.com/the1812"},{name:"Coulomb-G",link:"https://github.com/Coulomb-G"}],contributors:[{name:"PleiadeSubaru",link:"https://github.com/Etherrrr"}].sort(n),fetching:true,participants:[],websites:[{name:"GitHub",link:"https://github.com/the1812/Bilibili-Evolved/"},{name:"Greasy Fork",link:"https://greasyfork.org/zh-CN/scripts/373563-bilibili-evolved"}],components:[{name:"Vue.js",link:"https://cn.vuejs.org/index.html"},{name:"JSZip",link:"https://stuk.github.io/jszip/"},{name:"jQuery",link:"http://jquery.com/"},{name:"debounce",link:"https://github.com/component/debounce/"},{name:"Slip.js",link:"https://github.com/kornelski/slip"},{name:"MDI",link:"https://materialdesignicons.com"}]},mounted(){document.querySelector(".bilibili-evolved-about").addEventListener("be:about-load",()=>{this.init()},{once:true})},methods:{async getLogos(){this.logoImage=await Ajax.getText(`https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/images/bilibili-evolved-wide.svg`);this.logoImageDark=await Ajax.getText(`https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/images/bilibili-evolved-wide-dark.svg`)},async init(){this.branch=/Preview|Local/.test(a)?"preview":"master";this.getLogos();const t=new Set;let e=[];let i=1;do{e=await Ajax.getJson(`https://api.github.com/repos/the1812/Bilibili-Evolved/issues?state=all&direction=asc&per_page=100&page=${i}`).catch(()=>{e=[{name:"电波无法到达(´・_・`)",link:null}]});i++;for(const i of e){t.add(i.user.login)}}while(e.length>0);this.participants=[...t].map(t=>{return{name:t,link:`https://github.com/${t}`}}).filter(({link:t})=>{return!this.authors.some(e=>e.link===t)&&!this.contributors.some(e=>e.link===t)}).sort(n);this.fetching=false}}})})()}})();
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/aria2-rpc.min.js"] = (()=>{return(t,e)=>{function o(){const e=t.aria2RpcOption;const o=e.host.match(/^http[s]?:\/\//)?e.host:"http://"+e.host;const r="aria2.addUri";return{option:e,host:o,methodName:r}}async function r(t,e=false){try{let o=await t();if(typeof o==="string"){o=JSON.parse(o)}if(o.error!==undefined){if(o.error.code===1){logError(`请求遭到拒绝, 请检查您的密钥相关设置.`)}else{logError(`请求发生错误, code = ${o.error.code}, message = ${o.error.message}`)}return false}if(!e){Toast.success(`成功发送了请求, GID = ${o.result}`,"aria2 RPC",5e3)}return true}catch(t){logError(`无法连接到RPC主机.`);return false}}async function s(t,e=false){const{option:s,host:n,methodName:a}=o();return await r(async()=>{const e=window.btoa(unescape(encodeURIComponent(JSON.stringify(t.params))));const o=`${n}:${s.port}/jsonrpc?method=${a}&id=${t.id}¶ms=${e}`;console.log(`RPC request:`,o);if(o.startsWith("http:")){return await new Promise((t,e)=>{GM_xmlhttpRequest({method:"GET",url:o,responseType:"json",onload:e=>t(e.response),onerror:t=>e(t)})})}else{return await Ajax.getJson(o)}},e)}async function n(t,e=false){const{option:s,host:n,methodName:a}=o();return await r(async()=>{const e=`${n}:${s.port}/jsonrpc`;const o={method:a,id:t.id,params:t.params};if(e.startsWith("http:")){return await new Promise((t,r)=>{GM_xmlhttpRequest({method:"POST",url:e,responseType:"json",data:JSON.stringify(o),onload:e=>t(e.response),onerror:t=>r(t)})})}else{return await Ajax.postJson(e,o)}},e)}async function a(e,o=false){const r=t.aria2RpcOption;for(const t of e){let e;if(r.method==="get"){e=await s(t,o)}else{e=await n(t,o)}if(o===true&&e===false){logError(`${decodeURIComponent(t.id)} 导出失败`)}}}return{export:{sendRpc:a}}}})();
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/auto-continue.min.js"] = (()=>{return(e,i)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}function t(i){const t=i.text();if(/第(\d+)话/.test(t)){if(e.allowJumpContinue){i.parent().find(".bilibili-player-video-toast-item-jump").click()}return}const n=/((\d)*:)?(\d)*:(\d)*/g;const r=t.match(n);if(!r){return}const o=r[0].split(":");const l=(()=>{if(o.length===3){const[e,i,t]=o.map(e=>parseInt(e));return e*60*60+i*60+t}else if(o.length===2){const[e,i]=o.map(e=>parseInt(e));return e*60+i}else{logError(`解析历史时间发生错误: historyTime=${JSON.stringify(o)}`);return NaN}})();const s=i.parent();const a=document.querySelector("video");if(l<a.duration){a.currentTime=l;a.play();s.find(".bilibili-player-video-toast-item-jump").remove();const e=$(`<div class="bilibili-player-video-toast-item-jump">从头开始</div>`);e.appendTo(s).on("click",()=>{a.currentTime=0;s.find(".bilibili-player-video-toast-item-close").get(0).click()});i.html(`<span>已跳转到上次历史记录</span><span>${r[0]}</span>`)}else{s.find(".bilibili-player-video-toast-item-close").get(0).click()}}function n(){SpinQuery.condition(()=>$(".bilibili-player-video-toast-item-text"),e=>e.text().indexOf("上次看到")!==-1,e=>t(e.filter((e,i)=>i.innerText.indexOf("上次看到")!==-1)))}Observer.videoChange(n)}})();
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/auto-draw.min.js"] = (()=>{return(t,n)=>{(async()=>{if(!/^https:\/\/live\.bilibili\.com\/[\d]+/.test(document.URL)){return}const t=await SpinQuery.condition(()=>dq(".chat-popups-section"),t=>t.querySelector("chat-draw-area")===null);if(!t){console.warn("[自动领奖] 未能找到弹窗容器");return}Observer.childListSubtree(t,()=>{let t;console.log("draw button = ",dq(".chat-popups-section .draw>span:nth-child(3)"));t=dq(".chat-popups-section .draw>span:nth-child(3)");if(t===null){const t=dq(".chat-popups-section .function-bar>span:nth-child(3)");if(t!==null){const n=Observer.attributes(t,()=>{if(t.style.display!=="none"){n.forEach(t=>t.stop());t.click()}})}}if(t!==null){t.click()}})})()}})();
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/auto-play.min.js"] = (()=>{return(e,d)=>{if(typeof isEmbeddedPlayer!=="undefined"&&isEmbeddedPlayer()){return}SpinQuery.condition(()=>document.querySelector(".bilibili-player-video video"),e=>e&&e.paused===true,e=>e.play())}})();
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/batch-download.min.js"] = (()=>{return(t,e)=>{const i=12;class r{constructor(){this.itemList=[];this.itemFilter=(()=>true)}async getItemList(){}async collectData(){}async collectAria2(r,s){const n=JSON.parse(await this.collectData(r));if(s){const r=t.aria2RpcOption;const{sendRpc:s}=await e.importAsync("aria2-rpc");for(const t of n){const e=t.fragments.map((e,s)=>{let n="";if(t.fragments.length>1){n=" - "+(s+1)}const a=[];if(r.secretKey!==""){a.push(`token:${r.secretKey}`)}a.push([e.url]);a.push({referer:document.URL.replace(window.location.search,""),"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0",out:`${t.title}${n}.flv`,split:i,dir:r.dir||undefined,"max-download-limit":r.maxDownloadLimit||undefined});const o=encodeURIComponent(`${t.title}${n}`);return{params:a,id:o}});await s(e,true)}}else{return`\n# Generated by Bilibili Evolved Video Export\n# https://github.com/the1812/Bilibili-Evolved/\n${n.map(t=>{return t.fragments.map(e=>{return`\n${e.url}\n referer=${t.referer}\n user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0\n out=${t.title}.flv\n split=${i}\n `.trim()})}).join("\n")}\n `.trim()}}}class s extends r{static async test(){if(!document.URL.includes("/www.bilibili.com/video/av")){return false}return await SpinQuery.select("#multi_page")!==null}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=`https://api.bilibili.com/x/web-interface/view?aid=${unsafeWindow.aid}`;const e=await Ajax.getJson(t);if(e.code!==0){Toast.error(`获取视频选集列表失败, message=${e.message}`,"批量下载");return""}const i=e.data.pages;if(i===undefined){Toast.error(`获取视频选集列表失败, 没有找到选集信息.`,"批量下载");return""}this.itemList=i.map(t=>{return{title:`P${t.page} ${t.part}`,cid:t.cid,aid:unsafeWindow.aid}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/x/player/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title,totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}class n extends r{static async test(){return document.URL.includes("/www.bilibili.com/bangumi")}async getItemList(){if(this.itemList.length>0){return this.itemList}const t=document.querySelector("meta[property='og:url']");if(t===null){Toast.error("获取番剧数据失败: 无法找到 Season ID","批量下载");return""}const e=t.getAttribute("content").match(/play\/ss(\d+)/)[1];if(e===undefined){Toast.error("获取番剧数据失败: 无法解析 Season ID","批量下载");return""}const i=await Ajax.getJson(`https://api.bilibili.com/pgc/web/season/section?season_id=${e}`);if(i.code!==0){Toast.error(`获取番剧数据失败: 无法获取番剧集数列表, message=${i.message}`,"批量下载");return""}this.itemList=i.result.main_section.episodes.map((t,e)=>{return{aid:t.aid,cid:t.cid,title:t.long_title?`${t.title} - ${t.long_title}`:`${e+1} - ${t.title}`}});return this.itemList}async collectData(t){const e=[];for(const i of(await this.getItemList()).filter(this.itemFilter)){const r=`https://api.bilibili.com/pgc/player/web/playurl?avid=${i.aid}&cid=${i.cid}&qn=${t}&otype=json`;const s=await Ajax.getJsonWithCredentials(r);const n=s.data||s.result||s;if(n.quality!==t){console.warn(`${i.title} 不支持所选画质, 已回退到较低画质. (quality=${n.quality})`)}const a=n.durl.map(t=>{return{length:t.length,size:t.size,url:t.url}});e.push({fragments:a,title:i.title,totalSize:a.map(t=>t.size).reduce((t,e)=>t+e),cid:i.cid,referer:document.URL.replace(window.location.search,"")})}return JSON.stringify(e)}}const a=[n,s];let o=null;class l{constructor(){this.itemFilter=(()=>true)}static async test(){for(const t of a){if(await t.test()===true){o=t;return true}}o=null;return false}getExtractor(){if(o===null){logError("[批量下载] 未找到合适的解析模块.");throw new Error(`[Batch Download] module not found.`)}const t=new o;t.itemFilter=this.itemFilter;return t}async getItemList(){const t=this.getExtractor();return await t.getItemList()}async collectData(t,e){const i=this.getExtractor();const r=await i.collectData(t.quality);e.dismiss();return r}async collectAria2(t,e,i){const r=this.getExtractor();const s=await r.collectAria2(t.quality,i);e.dismiss();return s}}return{export:{BatchExtractor:l}}}})();
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/biliplus-redirect.min.js"] = (()=>{return(i,e)=>{const n=`hd.biliplus.com`;const c=["bilibili.com/video/av","bilibili.com/bangumi/play","bilibili.com/bangumi/media","space.bilibili.com"];return{widget:{condition:()=>{return c.some(i=>document.URL.includes(i))},content:`\n <button class="gui-settings-flat-button" id="biliplus-redirect">\n <i class="icon-biliplus"></i>\n <span>转到BiliPlus</span>\n </button>`,success:()=>{const i=document.querySelector("#biliplus-redirect");i.addEventListener("click",()=>{if(location.host==="space.bilibili.com"){location.assign(document.URL.replace("space.bilibili.com/",`${n}/space/`))}else if(document.URL.includes("/bangumi/")){const i=unsafeWindow.aid||document.querySelector(".av-link,.info-sec-av").innerText.replace(/[aAvV]/g,"");location.assign(`https://${n}/video/av${i}/`)}else{location.host=n}})}}}}})();
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/blur-video-control.min.css"] = `.video-control-blur-layer{width:100%;height:100%;position:absolute;-webkit-backdrop-filter:blur(48px);backdrop-filter:blur(48px);z-index:-1;top:0}.bilibili-player-video-control-mask{background:0 0!important}.bilibili-player-video-control-bottom,.bui-slider .bui-track.bui-track-video-progress .bui-bar-wrap{background-color:transparent!important}.bilibili-player-video-control-bottom{position:relative}.bilibili-player-area .bilibili-player-video-control-bottom,.bilibili-player-area .bilibili-player-video-control-wrap{transition:none!important}`;
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/blur-video-control.min.js"] = (()=>{return(o,e)=>{const l=async()=>{const o=await SpinQuery.count(".bui-slider .bui-track.bui-track-video-progress,.bilibili-player-video-control-bottom",2);o.forEach(o=>{if(!o.classList.contains("video-control-blur-container")){o.classList.add("video-control-blur-container");o.insertAdjacentHTML("afterbegin",`<div class="video-control-blur-layer"></div>`)}})};e.applyStyle("blurVideoControlStyle");Observer.videoChange(l);return{reload:()=>{document.querySelectorAll(".video-control-blur-layer").forEach(o=>o.style.display="block");e.applyStyle("blurVideoControlStyle")},unload:()=>{document.querySelectorAll(".video-control-blur-layer").forEach(o=>o.style.display="none");e.removeStyle("blurVideoControlStyle")}}}})();
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/bundle.json"] = `{
|
||
"about.min.css": "86FA62FF7469866E6B04F037A52951A2A8FF44F5",
|
||
"about.min.html": "FDCCD18FA788F70703089795D8CEC94078759F63",
|
||
"about.min.js": "24627AA53E2D264367719AF49D11ECD089BA853D",
|
||
"aria2-rpc.min.js": "C73BBD8EA943758409ED6D42C8ACBDC0288DAB7A",
|
||
"auto-continue.min.js": "0E0B4CAEC2FD0AC9D643D38BB2040D6829232A03",
|
||
"auto-draw.min.js": "2D466B9C0C431DD155934892B2946DDED8536528",
|
||
"auto-play.min.js": "09A7F7A6F6B99211E0E3AD8611131C2F77BF9391",
|
||
"batch-download.min.js": "CBBB77466253770D76CB2935C16CA7FC16E839D6",
|
||
"biliplus-redirect.min.js": "9C250C7088E282EE4F39B1F2B2DAB653C2E395C1",
|
||
"blur-video-control.min.css": "C61974A5CD6AA8FF896AE5AC1D24D4018C852CC0",
|
||
"blur-video-control.min.js": "B6533333805AEEDB60D0EA1FF4F150E114C8ACAE",
|
||
"clear-cache.min.js": "D8F80BA4EE3BD553ED7914074891AD668E3BED49",
|
||
"combo-like.min.js": "8EA9E2D6078A46BFF6BF6C3730E8115F6A2632A6",
|
||
"comment-dark.min.css": "6204C3B3E9D0C2A12E0FCB0034475AC32F1FEBE7",
|
||
"comment.min.css": "1398A9BEC0B792152E303105F2F4EEBCEA7CD8EA",
|
||
"comment.min.js": "90F9490CF7368EB596FF94BBAEE360A79C91031F",
|
||
"compact-layout.min.css": "058EBDC087202FB2387A273544D63CE57990C5A6",
|
||
"compact-layout.min.js": "135AB9F5D8B93EF611A34594C3B552C188038777",
|
||
"custom-control-background.min.css": "3A5079E4725C0EE3FD1941728EEA372AB55B7517",
|
||
"custom-control-background.min.js": "EDD397D78935F16EC824E91013C7C062F8D73209",
|
||
"custom-navbar.min.css": "44F50E5D3A16517A3500145458E33E65B7A53F4C",
|
||
"custom-navbar.min.html": "B85D91C28F36AD5CD4082728EB0A1E102C4415CC",
|
||
"custom-navbar.min.js": "97A7874F6B45A3B5D665B8A08C3F18C2215A7038",
|
||
"danmaku-converter.min.js": "46B3F50018CE0CE7A22C734AF0AD1D25066976FC",
|
||
"dark-important.min.css": "0C2BE5279D3775F5BD9A3894613AC20E609210A3",
|
||
"dark-navbar.min.css": "81B8E4AA04CF6248CD373C1A880962DFDE4C0F2F",
|
||
"dark-schedule.min.js": "C6ADC63089262648122010B8A91BE0C70B275822",
|
||
"dark-styles.min.js": "045F76BA699DE85D37EFFDB4F38D9B80D3FA51B5",
|
||
"dark.min.css": "5DA07DABF88EF28A1E217F22B4096DCC3658C53C",
|
||
"debounce.min.js": "49CF926C92433B63519B5042FF45C8ADBB9A6DA4",
|
||
"default-danmaku-settings.min.css": "88517CF6E657C4746CC4B26517D081A12E43578A",
|
||
"default-danmaku-settings.min.js": "08F0110887814A8CCDB503EFDB7F634C88AAFFF8",
|
||
"default-player-layout.min.js": "9B2AFE500DC61BB2E33B38B0CC1653CF49A77AA7",
|
||
"default-player-mode.min.js": "E25E897D36D6BB3B52A4057C5C887CC0AB67E87B",
|
||
"default-video-quality.min.js": "4E5C35EBD13B8496690CFE631678DA96B2422F86",
|
||
"default-video-speed.min.js": "CC2E11E9D57FC2723B56660454994C86CB6426FF",
|
||
"double-click-fullscreen.min.js": "F6574BBFE0AB6D356B4B83A4446BEA317C9C6F5B",
|
||
"download-audio.min.js": "D763AFADC729D89162A0E10498CFE4115D63F1B6",
|
||
"download-danmaku.min.js": "2EBDDA04E723FD536A1995F87273C56752884826",
|
||
"download-video.min.css": "51FEB869D2E5DE01CBD8EF2D3C1D1E67333E7E2E",
|
||
"download-video.min.html": "3952BCA12FA63CA1B78A9936D36B357DAC72B843",
|
||
"download-video.min.js": "39300B948F09410F6BB74D57A9FAC50E2FA4EA39",
|
||
"expand-danmaku.min.js": "9D990E92B4C2417B664DD0A3E53CC89033A95029",
|
||
"expand-description.min.css": "67BB65BE81C4376E0ED59AFF456B89D28A75D8CD",
|
||
"expand-description.min.js": "A10BF51E596AF523BBAE21C3DEFCF40BFE26CB4C",
|
||
"favorites-redirect.min.js": "FCFFF0E9F08396AF6A28D8E999FEF0D7261FBF95",
|
||
"fix-fullscreen.min.js": "2AF7C74185E6270E03206CE712BCC3A6FA058DA8",
|
||
"fold-comment.min.css": "02BAFE53474A7B63CCE57F7AAB9E65843F4ADEB6",
|
||
"fold-comment.min.js": "5F20F55791BB48F352ECB9C4C4B197D4F2676ABE",
|
||
"frame-playback.min.css": "20B3EB4256CFC7A775CDF880044A6C8F6F265620",
|
||
"frame-playback.min.html": "E20EE14DE942C9B581D1A24616519DEF6D86D262",
|
||
"frame-playback.min.js": "04BC29E880A76F7D81DF891F10FDE3FAC7DDD88F",
|
||
"full-page-title.min.css": "54CC0813E3592F055AB44B74B411C17DE8EE1FFC",
|
||
"full-page-title.min.js": "2B0703A2E2D61B930BE3647675C5BFAA12A13D62",
|
||
"full-tweets-title.min.css": "E0059CC377CA217AC7673003C1C93D76CCC98EC9",
|
||
"full-tweets-title.min.js": "9613FC3B874D668AB812255339890336DD2656BD",
|
||
"gui-settings.min.css": "BC843012C12841D75C930D58A8D756335014A1F3",
|
||
"gui-settings.min.html": "0843A5F68EC1C8BF6A898DCFAF3CC713061A82EA",
|
||
"gui-settings.min.js": "29C33F90D65FA56CD9BA275F0D74C0988ADDC2D8",
|
||
"haruna-scale.min.js": "4504C23D2F3B8743C9A545F8A48A38F6C52F88C4",
|
||
"hide-bangumi-reviews.min.js": "6E3452013F039EAE1B864EDAC7EAEF9E27B6EBCE",
|
||
"hide-banner.min.css": "B5E140FB4A22CE3A5310EBC5D9D0CCE69F9D3A1A",
|
||
"hide-banner.min.js": "739863A6B98CBDB41EC93BB8BE1999E5421762CB",
|
||
"hide-category.min.js": "E8D445C3DA92058045DF09A969935437D2A45D07",
|
||
"hide-old-entry.min.js": "81127974CA0D88EE3F202006412044EB78426890",
|
||
"hide-top-search.min.js": "A6BA72841AE8180E320724430944B129A99972BD",
|
||
"i18n.de-DE.min.js": "D74F4A3CD52ECDE56793DFF218D57049B91D91F7",
|
||
"i18n.en-US.min.js": "71EB7755A96FA32A8B7C4FD66B6E605FB34200A9",
|
||
"i18n.ja-JP.min.js": "A1FFF6A247566A2D05A741BA1506E8500BDEA529",
|
||
"i18n.min.css": "329A63BECB26C1E26D07C8E665859308C3FED60B",
|
||
"i18n.min.js": "E6F863D48F42692AA3ABAA81426A2C536CB15E8B",
|
||
"i18n.zh-TW.min.js": "07AF202524BD56084554AAD87D9B337B3FD740C5",
|
||
"icons.min.css": "382CC84865AB0EE0D8BDB51A9ADEE79D6930AA41",
|
||
"image-resolution.min.js": "89D95D21E9DBB1BE6127515E5E17825882BDE3F5",
|
||
"image-viewer.min.css": "647D1BADA7307322299DF10037A6A9403E0963ED",
|
||
"image-viewer.min.html": "C86BD84F084760561ED0E62729F9F4F019071562",
|
||
"index.min.html": "936B617145931F26ADD66DF4D37F9AAB28775CC4",
|
||
"keymap.min.js": "9DA4392C0CCC4B7FEC8AAEE640F9238A63060DE8",
|
||
"magic-grid.min.js": "4E169F1B73BFE794256D3BA56F16342B059C4E59",
|
||
"mdi.min.js": "A6E3CF8FCA5C6A6BA90B3959259A879CA218B5A9",
|
||
"medal-helper.min.css": "2800728203E3A80B408A25178F64682813D00883",
|
||
"medal-helper.min.html": "01F010227BEF92D9926C386AA79A6D88C7086CBB",
|
||
"medal-helper.min.js": "84B06923EF414055D16607745CFB0238258AA700",
|
||
"narrow-danmaku.min.js": "10112E3101B47DA91D32F55C99B19C65EAD5E148",
|
||
"new-styles.min.js": "227A7E8297A53E9C56CBF45D42D665CEB6022ECB",
|
||
"no-banner.min.css": "93E7DAA6E93A2AAD95C348052C9B5CB0DE901C51",
|
||
"no-live-autoplay.min.js": "DB2ACEF0458CC8F502F7104DCAA99CD7D52A9AB6",
|
||
"no-mini-video-autoplay.min.js": "2891812319992F87679AB8CBF83C9953E52F81B8",
|
||
"notify-new-version.min.js": "127ED0C80CC3A854B4D618707AFA0837619AC43A",
|
||
"old-tweets.min.js": "127E70AAB00CFEFE690DF0DE46EEA95CD0ED314A",
|
||
"old.min.css": "31CD10AFC1C2FB79EAC91263B1A69A364C6A9713",
|
||
"outer-watchlater.min.css": "849EFDFC9690351B982987F920EF2F821A9396D2",
|
||
"outer-watchlater.min.js": "861A3A451006CC6A7F824CAB2BAF83145A069DC9",
|
||
"override-navbar.min.css": "63B8EAEDDB086D4F442CD9C77B088A6C75D4E4D0",
|
||
"override-navbar.min.js": "C047CEE9A65FB7A7E2808E7498F0836A82BB0F4A",
|
||
"player-focus.min.js": "943788D3E63548196446CFED5F3CDB6A40B3F6F0",
|
||
"player-shadow.min.js": "BDF976E12627608D3D71723F2DE8DF693DCADFD1",
|
||
"remove-promotions.min.css": "9D35FFA5872531C2C3EC27049D8B9493CA685414",
|
||
"remove-promotions.min.js": "DD26F898864D52862B5E4DB0E7D7165F2BF04273",
|
||
"remove-top-mask.min.js": "B9FC5E0D843E50AE4805BEBFB91C657DF49425F6",
|
||
"remove-watermark.min.js": "541BEA800F30AF018C62A2C3A227518BB4D69490",
|
||
"screenshot.min.css": "37FB59ED5F74BFE51F623CAD7C10C96BDC57FA94",
|
||
"screenshot.min.js": "9DE7966851921D5BA46F33B6298C15E4A46F2438",
|
||
"scrollbar.min.css": "BDDE799C6A499902742CA5A2F49EB3FEA8D6A4BA",
|
||
"seeds-to-coins.min.js": "382113069939CC2750CC3066E1F7DB0805FC4146",
|
||
"settings-search.min.js": "E40DBC279DC35A8C6FD5FCCADD4C8F92618A3EE2",
|
||
"settings-side-bar.min.js": "5B2888B0FA743F5CE1D2A06C00E65EB297211A1C",
|
||
"settings-tooltip.en-US.min.js": "B80A81B58F0DB4F61D396D0592249F9A0582775F",
|
||
"settings-tooltip.ja-JP.min.js": "E5552E41AB7CE8F6856AFB6C14EDB6FB8768823B",
|
||
"settings-tooltip.loader.min.js": "1262709D0C776EA8EC7BF8C298443CB03D85C7A4",
|
||
"settings-tooltip.min.css": "398B0FD750875F9CD85ABF52A245A6D14001C71A",
|
||
"settings-tooltip.min.js": "217D4E0521E98471E6204121E5279DF53FC3D11C",
|
||
"settings-tooltip.zh-CN.min.js": "6FCB5C64213D403AE661E26AE151D82D1998F707",
|
||
"show-dead-video-title.min.js": "4396DCCC77AE950ECEF3118DE4BBCC71897488B2",
|
||
"simplify-liveroom.min.css": "4AE41231E47FA544C253D39053D1A277AE32D49F",
|
||
"simplify-liveroom.min.js": "7630A9C9B298CFFC5AEA5C16A9CC85AE6876C42F",
|
||
"skip-charge-list.min.css": "6468722B03708E3A932A04A16C631E9D202B0769",
|
||
"skip-charge-list.min.js": "041CE3E335F21EFC0E9690DF30FCE317A1EF8723",
|
||
"slip.min.js": "11FD17D8798E44AAC410863B92713783CFB27454",
|
||
"style.min.css": "648B985AECA76C648767C8442C567E4B195D264C",
|
||
"text-validate.min.js": "F4EBB11EC114E00FDE728DC55315EADF19926C5D",
|
||
"theme-colors.min.js": "8797934CDEF9833A47AB5BCA074E00DCE14AF13B",
|
||
"title.min.js": "D219DFD96644E2C4680969FF3CC0D9B6200894C4",
|
||
"toast.min.css": "85D8CBA4E67442638073D449B90440D79CA4844B",
|
||
"toast.min.js": "4471B50E41BB5BFD94C4BB0C4DFCFE8E585F3422",
|
||
"touch-navbar.min.js": "4CF82B9BFABE0A226332494F86FE5B82A98C614A",
|
||
"touch-player.min.css": "EAC837A10E204A94F7DE0F1C3A43FA8D36123B5A",
|
||
"touch-player.min.js": "F922A7CCF4AC8282C2F1D356FF5D230D7117A1DD",
|
||
"tweets.min.css": "2854257C4DB7AB2BEC99C80C3C9BE715D5E92746",
|
||
"v-checkbox.vue.min.js": "538637DC1FA515E118169A465F7EE550F2F23FF9",
|
||
"v-dropdown.vue.min.js": "BAE8C472F3B8F217CC821219C983774133FA7A25",
|
||
"video-info.min.js": "356B63564464C81C5C7F45367F4CFF38B0B6FC25",
|
||
"video-story.min.js": "7EE63FC3328CFD2457E990FEA9AB16B1F8452014",
|
||
"view-cover.min.js": "658E2CDB9606D3AECB466572E0718EA7B4F363A6",
|
||
"watchlater-api.min.js": "112BE78EA600530F1C8CB406594856DEC9B684DC",
|
||
"watchlater.min.js": "6D8C28C5163FF4E80B9870DD3E65EA2D5A0E55A1"
|
||
}`;
|
||
onlineData["https://raw.githubusercontent.com/the1812/Bilibili-Evolved/preview/min/bundle.zip"] = `PK |