重命名 RPC 预设:
@@ -69,17 +73,19 @@
diff --git a/registry/lib/plugins/video/download/wasm-output/handler.ts b/registry/lib/plugins/video/download/wasm-output/handler.ts
index 1c48e12fd3..7d6842e1cf 100644
--- a/registry/lib/plugins/video/download/wasm-output/handler.ts
+++ b/registry/lib/plugins/video/download/wasm-output/handler.ts
@@ -1,4 +1,4 @@
-import { DownloadPackage } from '@/core/download'
+import { DownloadPackage, PackageEntry } from '@/core/download'
import { meta } from '@/core/meta'
import { getComponentSettings } from '@/core/settings'
import { Toast } from '@/core/toast'
@@ -6,38 +6,38 @@ import { title as pluginTitle } from '.'
import type { Options } from '../../../../components/video/download'
import { DownloadVideoAction } from '../../../../components/video/download/types'
import { FFmpeg } from './ffmpeg'
-import { getCacheOrGet, httpGet, toastProgress, toBlobUrl } from './utils'
+import { getCacheOrFetch, httpGet, toastProgress, toBlobUrl } from './utils'
const ffmpeg = new FFmpeg()
async function loadFFmpeg() {
const toast = Toast.info('正在加载 FFmpeg', `${pluginTitle} - 初始化`)
- await ffmpeg.load({
- workerLoadURL: toBlobUrl(
- await getCacheOrGet(
- 'ffmpeg-worker',
- meta.compilationInfo.altCdn.library.ffmpeg.worker,
- toastProgress(toast, '正在加载 FFmpeg Worker'),
- ),
- 'text/javascript',
+
+ const progress = toastProgress(toast)
+ const [worker, core, wasm] = await Promise.all([
+ getCacheOrFetch(
+ 'ffmpeg-worker',
+ meta.compilationInfo.altCdn.library.ffmpeg.worker,
+ progress(0, '正在加载 FFmpeg Worker'),
),
- coreURL: toBlobUrl(
- await getCacheOrGet(
- 'ffmpeg-core',
- meta.compilationInfo.altCdn.library.ffmpeg.core,
- toastProgress(toast, '正在加载 FFmpeg Core'),
- ),
- 'text/javascript',
+ getCacheOrFetch(
+ 'ffmpeg-core',
+ meta.compilationInfo.altCdn.library.ffmpeg.core,
+ progress(1, '正在加载 FFmpeg Core'),
),
- wasmURL: toBlobUrl(
- await getCacheOrGet(
- 'ffmpeg-wasm',
- meta.compilationInfo.altCdn.library.ffmpeg.wasm,
- toastProgress(toast, '正在加载 FFmpeg WASM'),
- ),
- 'application/wasm',
+ getCacheOrFetch(
+ 'ffmpeg-wasm',
+ meta.compilationInfo.altCdn.library.ffmpeg.wasm,
+ progress(2, '正在加载 FFmpeg WASM'),
),
+ ])
+
+ await ffmpeg.load({
+ workerLoadURL: toBlobUrl(worker, 'text/javascript'),
+ coreURL: toBlobUrl(core, 'text/javascript'),
+ wasmURL: toBlobUrl(wasm, 'application/wasm'),
})
+
toast.message = '完成!'
toast.close()
}
@@ -46,52 +46,76 @@ async function single(
name: string,
videoUrl: string,
audioUrl: string,
- isFlac: boolean,
+ ffmetadata: string,
+ outputMkv: boolean,
pageIndex = 1,
totalPages = 1,
) {
const toast = Toast.info('', `${pluginTitle} - ${pageIndex} / ${totalPages}`)
- ffmpeg.writeFile('video', await httpGet(videoUrl, toastProgress(toast, '正在下载视频流')))
- ffmpeg.writeFile('audio', await httpGet(audioUrl, toastProgress(toast, '正在下载音频流')))
+ const progress = toastProgress(toast)
+ const [video, audio] = await Promise.all([
+ httpGet(videoUrl, progress(0, '正在下载视频流')),
+ httpGet(audioUrl, progress(1, '正在下载音频流')),
+ ])
+
+ ffmpeg.writeFile('video', video)
+ ffmpeg.writeFile('audio', audio)
+
+ const args = ['-i', 'video', '-i', 'audio']
+
+ if (ffmetadata) {
+ ffmpeg.writeFile('ffmetadata', new TextEncoder().encode(ffmetadata))
+ args.push('-i', 'ffmetadata', '-map_metadata', '2')
+ if (!outputMkv) {
+ args.push('-movflags', '+use_metadata_tags')
+ }
+ }
+
+ args.push('-codec', 'copy', '-f', outputMkv ? 'matroska' : 'mp4', 'output')
+
+ console.debug('FFmpeg commandline args:', args.join(' '))
toast.message = '混流中……'
- const outputExt = isFlac ? 'mkv' : 'mp4'
- name = name.replace(/.[^/.]+$/, `.${outputExt}`)
- await ffmpeg.exec([
- '-i',
- 'video',
- '-i',
- 'audio',
- '-c:v',
- 'copy',
- '-c:a',
- 'copy',
- '-f',
- isFlac ? 'matroska' : 'mp4',
- `output.${outputExt}`,
- ])
+ await ffmpeg.exec(args)
- const output = await ffmpeg.readFile(`output.${outputExt}`)
+ const output = await ffmpeg.readFile('output')
const outputBlob = new Blob([output], {
- type: isFlac ? 'video/x-matroska' : 'video/mp4',
+ type: outputMkv ? 'video/x-matroska' : 'video/mp4',
})
toast.message = '完成!'
toast.duration = 1000
- await DownloadPackage.single(name, outputBlob)
+ await DownloadPackage.single(
+ name.replace(/.[^/.]+$/, `.${outputMkv ? 'mkv' : 'mp4'}`),
+ outputBlob,
+ )
}
-export async function run(action: DownloadVideoAction) {
+export async function run(action: DownloadVideoAction, muxWithMetadata: boolean) {
if (!ffmpeg.loaded) {
await loadFFmpeg()
}
+ const { infos: pages, extraAssets } = action
+
+ let ffmetadata: PackageEntry[]
+ if (muxWithMetadata) {
+ const extraAssetsForBrowser = []
+ for (const { asset, instance } of extraAssets) {
+ if (!ffmetadata && asset.name === 'saveVideoMetadata' && instance.type === 'ffmetadata') {
+ ffmetadata = await asset.getAssets(pages, instance)
+ } else {
+ extraAssetsForBrowser.push({ asset, instance })
+ }
+ }
+ action.extraAssets = extraAssetsForBrowser
+ }
+
const { dashAudioExtension, dashFlacAudioExtension, dashVideoExtension } =
getComponentSettings
('downloadVideo').options
- const pages = action.infos
for (let i = 0; i < pages.length; i++) {
const page = pages[i]
const [video, audio] = page.titledFragments
@@ -109,6 +133,7 @@ export async function run(action: DownloadVideoAction) {
video.title,
video.url,
audio.url,
+ ffmetadata?.[i]?.data,
audio.extension === dashFlacAudioExtension,
i + 1,
pages.length,
diff --git a/registry/lib/plugins/video/download/wasm-output/index.ts b/registry/lib/plugins/video/download/wasm-output/index.ts
index 3cde08f64c..d5039f2592 100644
--- a/registry/lib/plugins/video/download/wasm-output/index.ts
+++ b/registry/lib/plugins/video/download/wasm-output/index.ts
@@ -19,14 +19,15 @@ export const plugin: PluginMetadata = {
outputs.push({
name: 'wasm',
displayName: 'WASM',
- description: `${desc},运行过程中请勿关闭页面,初次使用或清除缓存后需要加载约 30 MB 的 WASM 文件`,
- runAction: async action => {
+ description: `${desc}。运行过程中请勿关闭页面,初次使用或清除缓存后需要加载约 30 MB 的 WASM 文件。`,
+ runAction: async (action, instance) => {
try {
- await run(action)
+ await run(action, instance.muxWithMetadata)
} catch (error) {
Toast.error(String(error), title)
}
},
+ component: () => import('./Config.vue').then(m => m.default),
})
})
},
diff --git a/registry/lib/plugins/video/download/wasm-output/utils.ts b/registry/lib/plugins/video/download/wasm-output/utils.ts
index 165e3559d2..fe2ec33d7b 100644
--- a/registry/lib/plugins/video/download/wasm-output/utils.ts
+++ b/registry/lib/plugins/video/download/wasm-output/utils.ts
@@ -1,14 +1,23 @@
import { Toast } from '@/core/toast'
import { formatFileSize, formatPercent } from '@/core/utils/formatters'
import { getOrLoad, storeNames } from './database'
+import { RuntimeLibraryDefinition, RuntimeLibrary } from '@/core/runtime-library'
-type OnProgress = (received: number, length: number) => void
+type OnProgress = (received: number, total: number) => void
-export function toastProgress(toast: Toast, message: string): OnProgress {
- return (r, l) => {
- toast.message = `${message}: ${formatFileSize(r)}${
- l > 0 ? ` / ${formatFileSize(l)} @ ${formatPercent(r / l)}` : ''
- }`
+function formatProgress(received: number, total: number) {
+ return `${formatFileSize(received)}${
+ total > 0 ? ` / ${formatFileSize(total)} @ ${formatPercent(received / total)}` : ''
+ }`
+}
+
+export function toastProgress(toast: Toast) {
+ const lines = []
+ return (line: number, message: string): OnProgress => {
+ return (r, l) => {
+ lines[line] = `${message}: ${formatProgress(r, l)}`
+ toast.message = lines.join('\n')
+ }
}
}
@@ -48,8 +57,21 @@ export async function httpGet(url: string, onprogress: OnProgress) {
return chunksAll
}
-export async function getCacheOrGet(key: string, url: string, loading: OnProgress) {
- return getOrLoad(storeNames.cache, key, async () => httpGet(url, loading))
+export async function getCacheOrFetch(
+ key: string,
+ library: RuntimeLibraryDefinition,
+ loading: OnProgress,
+) {
+ return getOrLoad(storeNames.cache, key, async () => {
+ const content = await httpGet(library.url, loading)
+ const sha256 = await RuntimeLibrary.sha256(content)
+ if (sha256 !== library.sha256) {
+ throw new Error(
+ `Check integrity failed from ${library.url}, expected = ${library.sha256}, actual = ${sha256}`,
+ )
+ }
+ return content
+ })
}
export function toBlobUrl(buffer: Uint8Array, mimeType: string) {
diff --git a/src/client/common.meta.json b/src/client/common.meta.json
index 3b3e06411f..f5a6c2d70f 100644
--- a/src/client/common.meta.json
+++ b/src/client/common.meta.json
@@ -1,5 +1,5 @@
{
- "version": "2.9.2",
+ "version": "2.9.3",
"author": "Grant Howard, Coulomb-G",
"copyright": "[year], Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G)",
"license": "MIT",
@@ -38,7 +38,7 @@
"*"
],
"require": [
- "[altCdn.library.lodash]"
+ "[altCdn.library.lodash.url]#sha256=[altCdn.library.lodash.sha256]"
],
"icon": "[altCdn.smallLogo]",
"icon64": "[altCdn.logo]"
diff --git a/src/components/SwitchOptions.vue b/src/components/SwitchOptions.vue
index 152b871fc3..68fe1d1614 100644
--- a/src/components/SwitchOptions.vue
+++ b/src/components/SwitchOptions.vue
@@ -5,7 +5,7 @@
{{ options.optionDisplayName }}
@@ -128,6 +128,7 @@ export default Vue.extend({
}
.switch-icon {
margin-right: 8px;
+ opacity: 0.75;
transform: scale(0.9);
}
.dim {
diff --git a/src/components/utils/comment/areas/v3.ts b/src/components/utils/comment/areas/v3.ts
index 8d0b741e69..b1a2011ed0 100644
--- a/src/components/utils/comment/areas/v3.ts
+++ b/src/components/utils/comment/areas/v3.ts
@@ -33,7 +33,6 @@ export class CommentAreaV3 extends CommentArea {
constructor(element: HTMLElement) {
super(element)
- shadowDomObserver.observe()
this.shadowDomObserver = shadowDomObserver
}
diff --git a/src/components/video/video-info.ts b/src/components/video/video-info.ts
index 43f5d3af78..9251d5689b 100644
--- a/src/components/video/video-info.ts
+++ b/src/components/video/video-info.ts
@@ -1,5 +1,17 @@
import { getJsonWithCredentials, getText } from '@/core/ajax'
+export interface UpInfo {
+ uid: number
+ name: string
+ faceUrl: string
+}
+
+export interface VideoPageInfo {
+ cid: number
+ title: string
+ pageNumber: number
+}
+
export class VideoInfo {
aid: string
bvid: string
@@ -13,16 +25,8 @@ export class VideoInfo {
tagName: string
title: string
description: string
- up: {
- uid: number
- name: string
- faceUrl: string
- }
- pages: {
- cid: number
- title: string
- pageNumber: number
- }[]
+ up: UpInfo
+ pages: VideoPageInfo[]
constructor(id: string, bvid = false) {
if (bvid) {
diff --git a/src/core/runtime-library.ts b/src/core/runtime-library.ts
index 73f2a31401..4ba753410d 100644
--- a/src/core/runtime-library.ts
+++ b/src/core/runtime-library.ts
@@ -5,26 +5,54 @@ import type StreamSaverType from 'streamsaver'
import { monkey } from './ajax'
import { meta } from './meta'
+export type RuntimeLibraryDefinition = { url: string; sha256: string }
export interface RuntimeLibraryConfig {
- url: string
+ library: RuntimeLibraryDefinition
getModule: (window: Window) => LibraryType
}
+
export class RuntimeLibrary implements PromiseLike {
private modulePromise: Promise
constructor(public config: RuntimeLibraryConfig) {}
+ static async sha256(content: string | BufferSource) {
+ const hashBuffer = await window.crypto.subtle.digest(
+ 'SHA-256',
+ typeof content === 'string' ? new TextEncoder().encode(content) : content,
+ )
+ const hashArray = Array.from(new Uint8Array(hashBuffer))
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
+ return hashHex
+ }
+
+ private async checkIntegrity(content: string | BufferSource) {
+ const sha256 = await RuntimeLibrary.sha256(content)
+ if (sha256 !== this.config.library.sha256) {
+ throw new Error(
+ `[RuntimeLibrary] Check integrity failed from ${this.config.library.url}, expected = ${this.config.library.sha256}, actual = ${sha256}`,
+ )
+ }
+ console.log(
+ `[Runtime Library] Checked integrity from ${this.config.library.url}, hash = ${sha256}`,
+ )
+ }
+
async then(
resolve?: (value: LibraryType) => Resolve | PromiseLike,
reject?: (reason: any) => Reject | PromiseLike,
) {
try {
- const { url, getModule } = this.config
+ const {
+ library: { url },
+ getModule,
+ } = this.config
if (!this.modulePromise) {
this.modulePromise = (async () => {
console.log(`[Runtime Library] Start download from ${url}`)
const code: string = await monkey({ url })
- console.log(`[Runtime Library] Downloaded from ${url} , length = ${code.length}`)
+ console.log(`[Runtime Library] Downloaded from ${url}, length = ${code.length}`)
+ await this.checkIntegrity(code)
;(function runEval() {
return eval(code)
// eslint-disable-next-line no-extra-bind
@@ -41,18 +69,18 @@ export class RuntimeLibrary implements PromiseLike {
}
}
export const protobufLibrary = new RuntimeLibrary({
- url: meta.compilationInfo.altCdn.library.protobuf,
+ library: meta.compilationInfo.altCdn.library.protobuf,
getModule: window => window.protobuf,
})
export const JSZipLibrary = new RuntimeLibrary({
- url: meta.compilationInfo.altCdn.library.jszip,
+ library: meta.compilationInfo.altCdn.library.jszip,
getModule: window => window.JSZip,
})
export const SortableJSLibrary = new RuntimeLibrary({
- url: meta.compilationInfo.altCdn.library.sortable,
+ library: meta.compilationInfo.altCdn.library.sortable,
getModule: window => window.Sortable,
})
export const StreamSaverLibrary = new RuntimeLibrary({
- url: meta.compilationInfo.altCdn.library.streamsaver,
+ library: meta.compilationInfo.altCdn.library.streamsaver,
getModule: window => window.streamSaver,
})
diff --git a/src/core/shadow-root/dom-observer.ts b/src/core/shadow-root/dom-observer.ts
index 8d9184d6b4..7f2c8011e2 100644
--- a/src/core/shadow-root/dom-observer.ts
+++ b/src/core/shadow-root/dom-observer.ts
@@ -1,3 +1,4 @@
+import { contentLoaded } from '../life-cycle'
import { childListSubtree } from '../observer'
import { deleteValue } from '../utils'
import { ShadowDomCallback, ShadowDomEntry } from './dom-entry'
@@ -81,6 +82,7 @@ export class ShadowDomObserver extends ShadowRootObserver {
}
forEachShadowDom(callback: ShadowDomCallback) {
+ this.observe()
const callCurrentAndNextLevel = (currentEntry: ShadowDomEntry) => {
callback(currentEntry)
currentEntry.children.forEach(child => {
@@ -94,6 +96,7 @@ export class ShadowDomObserver extends ShadowRootObserver {
}
watchShadowDom(callbacks: { added?: ShadowDomCallback; removed?: ShadowDomCallback }) {
+ this.observe()
this.forEachShadowDom(it => callbacks.added?.(it))
const addedListener = (e: CustomEvent) => callbacks?.added?.(e.detail)
const removedListener = (e: CustomEvent) => callbacks?.removed?.(e.detail)
@@ -109,10 +112,14 @@ export class ShadowDomObserver extends ShadowRootObserver {
if (this.observing) {
return
}
- const existingRoots = ShadowRootObserver.queryAllShadowRoots()
- existingRoots.forEach(root => this.addEntry(root))
- ;[this.rootObserver] = childListSubtree(document.body, records => this.mutationHandler(records))
this.observing = true
+ contentLoaded(() => {
+ const existingRoots = ShadowRootObserver.queryAllShadowRoots()
+ existingRoots.forEach(root => this.addEntry(root))
+ ;[this.rootObserver] = childListSubtree(document.body, records =>
+ this.mutationHandler(records),
+ )
+ })
}
disconnect() {
diff --git a/src/core/shadow-root/styles.ts b/src/core/shadow-root/styles.ts
index cbe942435d..0524e8a597 100644
--- a/src/core/shadow-root/styles.ts
+++ b/src/core/shadow-root/styles.ts
@@ -29,7 +29,6 @@ export class ShadowRootStyles {
async addStyle(definition: ShadowRootStyleDefinition) {
const { id, style } = definition
- this.observer.observe()
const entryId = `shadow-dom-style-${id !== undefined ? lodash.kebabCase(id) : getRandomId()}`
const styleSheet = new CSSStyleSheet()
await styleSheet.replace(style)
diff --git a/src/core/utils/index.ts b/src/core/utils/index.ts
index b8adab0443..239d6c41e1 100644
--- a/src/core/utils/index.ts
+++ b/src/core/utils/index.ts
@@ -518,9 +518,18 @@ export const playerReady = async () => {
// unsafeWindow.aid = info.aid.toString()
// return info.aid as string
// }
+
+/** 获取当前聚焦的元素 */
+export const getActiveElement = () => {
+ let { activeElement } = document
+ while (activeElement.shadowRoot !== null) {
+ activeElement = activeElement.shadowRoot.activeElement
+ }
+ return activeElement
+}
/** 是否正在打字 */
export const isTyping = () => {
- const { activeElement } = document
+ const activeElement = getActiveElement()
if (!activeElement) {
return false
}
diff --git a/webpack/cdn/github.ts b/webpack/cdn/github.ts
index 05872c69fe..f23bf1994c 100644
--- a/webpack/cdn/github.ts
+++ b/webpack/cdn/github.ts
@@ -10,12 +10,26 @@ export const github: CdnConfig = {
stableClient: `https://${host}/${owner}/Bilibili-Evolved/master/dist/bilibili-evolved.user.js`,
previewClient: `https://${host}/${owner}/Bilibili-Evolved/preview/dist/bilibili-evolved.preview.user.js`,
library: {
- lodash: `https://${host}/lodash/lodash/4.17.21/dist/lodash.min.js`,
- protobuf: `https://${host}/protobufjs/protobuf.js/v6.10.1/dist/light/protobuf.min.js`,
- jszip: `https://${host}/Stuk/jszip/v3.7.1/dist/jszip.min.js`,
- sortable: `https://${host}/SortableJS/Sortable/1.14.0/Sortable.min.js`,
- mdi: `https://${owner}.github.io/Bilibili-Evolved/static/mdi/mdi.css`,
- streamsaver: `https://${host}/jimmywarting/StreamSaver.js/2.0.6/StreamSaver.js`,
+ lodash: {
+ url: `https://${host}/lodash/lodash/4.17.21/dist/lodash.min.js`,
+ sha256: 'a9705dfc47c0763380d851ab1801be6f76019f6b67e40e9b873f8b4a0603f7a9',
+ },
+ protobuf: {
+ url: `https://${host}/protobufjs/protobuf.js/v6.10.1/dist/light/protobuf.min.js`,
+ sha256: '8978daf871b02d683ecaee371861702a6f31d0a4c52925b7db2bb1655a8bc7d1',
+ },
+ jszip: {
+ url: `https://${host}/Stuk/jszip/v3.7.1/dist/jszip.min.js`,
+ sha256: 'c9e4a52bac18aee4f3f90d05fbca603f5b0f5bf1ce8c45e60bb4ed3a2cb2ed86',
+ },
+ sortable: {
+ url: `https://${host}/SortableJS/Sortable/1.14.0/Sortable.min.js`,
+ sha256: '0ea5a6fbfbf5434b606878533cb7a66bcf700f0f08afe908335d0978fb63ad94',
+ },
+ streamsaver: {
+ url: `https://${host}/jimmywarting/StreamSaver.js/2.0.6/StreamSaver.js`,
+ sha256: 'a110f78e0b092481dc372901c4d57ae50681d773bc9d55e62356f9a22f17e24b',
+ },
// https://github.com/the1812/Bilibili-Evolved/pull/4521#discussion_r1402084486
ffmpeg: jsDelivr.library.ffmpeg,
},
diff --git a/webpack/cdn/jsdelivr.ts b/webpack/cdn/jsdelivr.ts
index 3765b97745..219c8ec276 100644
--- a/webpack/cdn/jsdelivr.ts
+++ b/webpack/cdn/jsdelivr.ts
@@ -9,16 +9,39 @@ export const jsDelivr: CdnConfig = {
stableClient: `https://${host}/gh/${owner}/Bilibili-Evolved@master/dist/bilibili-evolved.user.js`,
previewClient: `https://${host}/gh/${owner}/Bilibili-Evolved@preview/dist/bilibili-evolved.preview.user.js`,
library: {
- lodash: `https://${host}/npm/lodash@4.17.21/lodash.min.js`,
- protobuf: `https://${host}/npm/protobufjs@6.10.1/dist/light/protobuf.min.js`,
- jszip: `https://${host}/npm/jszip@3.7.1/dist/jszip.min.js`,
- sortable: `https://${host}/npm/sortablejs@1.14.0/Sortable.min.js`,
- mdi: `https://${host}/gh/${owner}/Bilibili-Evolved@master/docs/static/mdi/mdi.css`,
- streamsaver: `https://${host}/npm/streamsaver@2.0.6/StreamSaver.min.js`,
+ lodash: {
+ url: `https://${host}/npm/lodash@4.17.21/lodash.min.js`,
+ sha256: 'a9705dfc47c0763380d851ab1801be6f76019f6b67e40e9b873f8b4a0603f7a9',
+ },
+ protobuf: {
+ url: `https://${host}/npm/protobufjs@6.10.1/dist/light/protobuf.min.js`,
+ sha256: '8978daf871b02d683ecaee371861702a6f31d0a4c52925b7db2bb1655a8bc7d1',
+ },
+ jszip: {
+ url: `https://${host}/npm/jszip@3.7.1/dist/jszip.min.js`,
+ sha256: 'c9e4a52bac18aee4f3f90d05fbca603f5b0f5bf1ce8c45e60bb4ed3a2cb2ed86',
+ },
+ sortable: {
+ url: `https://${host}/npm/sortablejs@1.14.0/Sortable.min.js`,
+ sha256: '0ea5a6fbfbf5434b606878533cb7a66bcf700f0f08afe908335d0978fb63ad94',
+ },
+ streamsaver: {
+ url: `https://${host}/npm/streamsaver@2.0.6/StreamSaver.min.js`,
+ sha256: '64f465e51e5992be894c5d42330b781544eda5462069fe6be4c7421f02d28c92',
+ },
ffmpeg: {
- worker: `https://${host}/npm/@ffmpeg/ffmpeg@0.12.4/dist/umd/814.ffmpeg.js`,
- core: `https://${host}/npm/@ffmpeg/core@0.12.4/dist/umd/ffmpeg-core.js`,
- wasm: `https://${host}/npm/@ffmpeg/core@0.12.4/dist/umd/ffmpeg-core.wasm`,
+ worker: {
+ url: `https://${host}/npm/@ffmpeg/ffmpeg@0.12.4/dist/umd/814.ffmpeg.js`,
+ sha256: 'baf19437171b1bccae4416e4da69fb40455b8e67142f79c8ec9da36b1de7fd8a',
+ },
+ core: {
+ url: `https://${host}/npm/@ffmpeg/core@0.12.4/dist/umd/ffmpeg-core.js`,
+ sha256: '6af6b8cd8c878dec6f61f3cd6be16e88f9391dd265e51f20afea5c0f718bfba0',
+ },
+ wasm: {
+ url: `https://${host}/npm/@ffmpeg/core@0.12.4/dist/umd/ffmpeg-core.wasm`,
+ sha256: '925bd7ef35d4e0f715254cd650f4cfc68c4ec6ecebf293face72b92da904ddda',
+ },
},
},
smallLogo: `https://${host}/gh/${owner}/Bilibili-Evolved@preview/images/logo-small.png`,
diff --git a/webpack/cdn/types.ts b/webpack/cdn/types.ts
index 841d97d4df..5860ee74e3 100644
--- a/webpack/cdn/types.ts
+++ b/webpack/cdn/types.ts
@@ -1,3 +1,4 @@
+export type ExternalLibrary = { url: string; sha256: string }
export interface CdnConfig {
name: string
owner: string
@@ -5,16 +6,15 @@ export interface CdnConfig {
stableClient: string
previewClient: string
library: {
- lodash: string
- protobuf: string
- jszip: string
- sortable: string
- mdi: string
- streamsaver: string
+ lodash: ExternalLibrary
+ protobuf: ExternalLibrary
+ jszip: ExternalLibrary
+ sortable: ExternalLibrary
+ streamsaver: ExternalLibrary
ffmpeg: {
- worker: string
- core: string
- wasm: string
+ worker: ExternalLibrary
+ core: ExternalLibrary
+ wasm: ExternalLibrary
}
}
smallLogo: string