From 4979500d2c08fab161771a689c6f046531a537fd Mon Sep 17 00:00:00 2001 From: WakelessSloth56 Date: Fri, 26 Apr 2024 16:36:14 +0800 Subject: [PATCH] feat: wasm-output plugin supports multiple pages Co-authored-by: lainio24 --- .vscode/settings.json | 3 +- .../video/download/wasm-output/handler.ts | 64 ++++++++++++++++--- .../video/download/wasm-output/index.ts | 44 ++----------- 3 files changed, 62 insertions(+), 49 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 81dbe2a6b..586e80f5f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -62,6 +62,7 @@ "linebreak", "Liveroom", "materialdesignicons", + "matroska", "medialist", "mimetype", "minmax", @@ -133,6 +134,6 @@ "*.tsx": "${capture}.ts", "tsconfig.json": "tsconfig.*.json", "package.json": "package-lock.json, yarn.lock, pnpm-lock.yaml, .*", - "index.ts": "index.*.ts, index.md, index.*.md", + "index.ts": "index.*.ts, index.md, index.*.md" } } diff --git a/registry/lib/plugins/video/download/wasm-output/handler.ts b/registry/lib/plugins/video/download/wasm-output/handler.ts index d4353e233..bc977c3cd 100644 --- a/registry/lib/plugins/video/download/wasm-output/handler.ts +++ b/registry/lib/plugins/video/download/wasm-output/handler.ts @@ -1,12 +1,17 @@ import { DownloadPackage } from '@/core/download' import { meta } from '@/core/meta' +import { getComponentSettings } from '@/core/settings' import { Toast } from '@/core/toast' +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' const ffmpeg = new FFmpeg() -async function load(toast: Toast) { +async function loadFFmpeg() { + const toast = Toast.info('初始化', pluginTitle) await ffmpeg.load({ workerLoadURL: toBlobUrl( await getCacheOrGet( @@ -33,24 +38,26 @@ async function load(toast: Toast) { 'application/wasm', ), }) + toast.message = '完成!' + toast.close() } -export async function run( + +async function single( name: string, - toast: Toast, videoUrl: string, audioUrl: string, isFlac: boolean, + pageIndex = 1, + totalPages = 1, ) { - if (!ffmpeg.loaded) { - await load(toast) - } + const toast = Toast.info('', `${pluginTitle} - ${pageIndex} / ${totalPages}`) ffmpeg.writeFile('video', await httpGet(videoUrl, toastProgress(toast, '正在下载视频流'))) ffmpeg.writeFile('audio', await httpGet(audioUrl, toastProgress(toast, '正在下载音频流'))) - toast.message = '混流中……' + toast.message = '混流中……' const outputExt = isFlac ? 'mkv' : 'mp4' - name = isFlac ? name.replace(/.[^/.]+$/, `.${outputExt}`) : name + name = name.replace(/.[^/.]+$/, `.${outputExt}`) await ffmpeg.exec([ '-i', 'video', @@ -59,7 +66,7 @@ export async function run( '-c:v', 'copy', '-c:a', - isFlac ? 'flac' : 'copy', + 'copy', '-f', isFlac ? 'matroska' : 'mp4', `output.${outputExt}`, @@ -71,7 +78,44 @@ export async function run( }) toast.message = '完成!' - toast.duration = 1500 + toast.duration = 1000 await DownloadPackage.single(name, outputBlob) } + +export async function run(action: DownloadVideoAction) { + if (!ffmpeg.loaded) { + await loadFFmpeg() + } + + const pages = lodash.chunk( + action.infos.flatMap(it => it.titledFragments), + 2, + ) + + const { dashAudioExtension, dashFlacAudioExtension, dashVideoExtension } = + getComponentSettings('downloadVideo').options + + for (let i = 0; i < pages.length; i++) { + const page = pages[i] + const [video, audio] = page + if ( + !( + page.length === 2 && + video.extension === dashVideoExtension && + (audio.extension === dashAudioExtension || audio.extension === dashFlacAudioExtension) + ) + ) { + throw new Error('仅支持 DASH 格式视频和音频') + } + + await single( + video.title, + video.url, + audio.url, + 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 12ad5fe00..878bff1fe 100644 --- a/registry/lib/plugins/video/download/wasm-output/index.ts +++ b/registry/lib/plugins/video/download/wasm-output/index.ts @@ -1,11 +1,9 @@ -import { Toast, ToastType } from '@/core/toast' +import { Toast } from '@/core/toast' import { PluginMetadata } from '@/plugins/plugin' import { DownloadVideoOutput } from '../../../../components/video/download/types' import { run } from './handler' -import { getComponentSettings } from '@/core/settings' -import type { Options } from '../../../../components/video/download' -const title = 'WASM 混流输出' +export const title = 'WASM 混流输出' const desc = '使用 WASM 在浏览器中下载并合并音视频' export const plugin: PluginMetadata = { @@ -23,40 +21,10 @@ export const plugin: PluginMetadata = { displayName: 'WASM', description: `${desc},运行过程中请勿关闭页面,初次使用或清除缓存后需要加载约 30 MB 的 WASM 文件`, runAction: async action => { - const fragments = action.infos.flatMap(it => it.titledFragments) - const { dashAudioExtension, dashFlacAudioExtension, dashVideoExtension } = - getComponentSettings('downloadVideo').options - - if ( - fragments.length > 2 || - (fragments.length === 2 && - !( - fragments[0].extension === dashVideoExtension && - (fragments[1].extension === dashAudioExtension || - fragments[1].extension === dashFlacAudioExtension) - )) - ) { - Toast.error('仅支持单个视频下载', title).duration = 1500 - } else { - const toast = Toast.info('正在加载', title) - try { - if (fragments.length === 2) { - await run( - fragments[0].title, - toast, - fragments[0].url, - fragments[1].url, - fragments[1].extension === dashFlacAudioExtension, - ) // [dash] - } else { - toast.type = ToastType.Error - toast.message = '仅支持 dash 格式视频下载' - toast.duration = 1500 - } - } catch (error) { - toast.close() - Toast.error(String(error), title) - } + try { + await run(action) + } catch (error) { + Toast.error(String(error), title) } }, })