mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Merge branch 'the1812:preview-features' into preview-features
This commit is contained in:
commit
959e2c5628
@ -1,5 +1,5 @@
|
|||||||
import { defineComponentMetadata } from '@/components/define'
|
import { defineComponentMetadata } from '@/components/define'
|
||||||
import { getBlobByAid } from '@/components/video/video-cover'
|
import { getVideoCoverUrlByAid, getBlobByAid } from '@/components/video/video-cover'
|
||||||
import { PackageEntry } from '@/core/download'
|
import { PackageEntry } from '@/core/download'
|
||||||
import { videoAndBangumiUrls } from '@/core/utils/urls'
|
import { videoAndBangumiUrls } from '@/core/utils/urls'
|
||||||
import { Toast } from '@/core/toast'
|
import { Toast } from '@/core/toast'
|
||||||
@ -55,6 +55,26 @@ export const component = defineComponentMetadata({
|
|||||||
toast.message = `获取完成. 成功 ${success.length} 个, 失败 ${fail.length} 个.`
|
toast.message = `获取完成. 成功 ${success.length} 个, 失败 ${fail.length} 个.`
|
||||||
return success.map(it => it.value)
|
return success.map(it => it.value)
|
||||||
},
|
},
|
||||||
|
getUrls: async (
|
||||||
|
infos,
|
||||||
|
instance: {
|
||||||
|
type: CoverDownloadType
|
||||||
|
enabled: boolean
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
const { type, enabled } = instance
|
||||||
|
if (!enabled) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return Promise.all(
|
||||||
|
infos.map(async info => {
|
||||||
|
return {
|
||||||
|
name: `${info.input.title}.${type}`,
|
||||||
|
url: await getVideoCoverUrlByAid(info.input.aid),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
},
|
||||||
component: () => import('./Plugin.vue').then(m => m.default),
|
component: () => import('./Plugin.vue').then(m => m.default),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -330,19 +330,15 @@ export default Vue.extend({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const action = new DownloadVideoAction(videoInfos)
|
const action = new DownloadVideoAction(videoInfos)
|
||||||
const extraAssets = (
|
assets.forEach(a => {
|
||||||
await Promise.all(
|
const assetsType = a?.getUrls ? action.extraOnlineAssets : action.extraAssets
|
||||||
assets.map(a =>
|
assetsType.push({
|
||||||
a.getAssets(
|
asset: a,
|
||||||
videoInfos,
|
instance: this.$refs.assetsOptions.find((c: any) => c.$attrs.name === a.name),
|
||||||
this.$refs.assetsOptions.find((c: any) => c.$attrs.name === a.name),
|
})
|
||||||
),
|
})
|
||||||
),
|
|
||||||
)
|
|
||||||
).flat()
|
|
||||||
action.extraAssets.push(...extraAssets)
|
|
||||||
await action.downloadExtraAssets()
|
|
||||||
await output.runAction(action, instance)
|
await output.runAction(action, instance)
|
||||||
|
await action.downloadExtraAssets()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError(error)
|
logError(error)
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -77,11 +77,19 @@ export interface DownloadVideoApi extends WithName {
|
|||||||
/** 表示下载时额外附带的产物, 如弹幕 / 字幕等 */
|
/** 表示下载时额外附带的产物, 如弹幕 / 字幕等 */
|
||||||
export interface DownloadVideoAssets<AssetsParameter = any> extends VueInstanceInput, WithName {
|
export interface DownloadVideoAssets<AssetsParameter = any> extends VueInstanceInput, WithName {
|
||||||
getAssets: (infos: DownloadVideoInfo[], instance: AssetsParameter) => Promise<PackageEntry[]>
|
getAssets: (infos: DownloadVideoInfo[], instance: AssetsParameter) => Promise<PackageEntry[]>
|
||||||
|
/** 获取可直接下载的链接 */
|
||||||
|
getUrls?: (
|
||||||
|
infos: DownloadVideoInfo[],
|
||||||
|
instance: AssetsParameter,
|
||||||
|
) => Promise<{ name: string; url: string }[]>
|
||||||
}
|
}
|
||||||
/** 表示视频的下载信息以及携带的额外产物 */
|
/** 表示视频的下载信息以及携带的额外产物 */
|
||||||
export class DownloadVideoAction {
|
export class DownloadVideoAction<AssetsParameter = any> {
|
||||||
readonly inputs: DownloadVideoInputItem[] = []
|
readonly inputs: DownloadVideoInputItem[] = []
|
||||||
extraAssets: PackageEntry[] = []
|
/** 可调用处理的asset和对应的参数 */
|
||||||
|
extraAssets: { asset: DownloadVideoAssets; instance: AssetsParameter }[] = []
|
||||||
|
/** 可直接下载的asset和对应的参数 */
|
||||||
|
extraOnlineAssets: { asset: DownloadVideoAssets; instance: AssetsParameter }[] = []
|
||||||
|
|
||||||
constructor(public infos: DownloadVideoInfo[]) {
|
constructor(public infos: DownloadVideoInfo[]) {
|
||||||
this.inputs = infos.map(it => it.input)
|
this.inputs = infos.map(it => it.input)
|
||||||
@ -92,7 +100,15 @@ export class DownloadVideoAction {
|
|||||||
async downloadExtraAssets() {
|
async downloadExtraAssets() {
|
||||||
console.log('[downloadExtraAssets]', this.extraAssets)
|
console.log('[downloadExtraAssets]', this.extraAssets)
|
||||||
const filename = `${getFriendlyTitle(false)}.zip`
|
const filename = `${getFriendlyTitle(false)}.zip`
|
||||||
await new DownloadPackage(this.extraAssets).emit(filename)
|
const { infos } = this
|
||||||
|
const extraAssetsBlob = (
|
||||||
|
await Promise.all(
|
||||||
|
[...this.extraAssets, ...this.extraOnlineAssets].map(({ asset, instance }) =>
|
||||||
|
asset.getAssets(infos, instance),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
).flat()
|
||||||
|
await new DownloadPackage(extraAssetsBlob).emit(filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** 下载视频的最终输出处理 */
|
/** 下载视频的最终输出处理 */
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="rpc-config download-video-config-section">
|
<div class="rpc-config download-video-config-section">
|
||||||
|
<div>
|
||||||
|
<div>aria2下载附属资源(若支持):</div>
|
||||||
|
<SwitchBox v-model="isPluginDownloadAssets" @change="saveSettings" />
|
||||||
|
</div>
|
||||||
<div v-if="isRenaming" class="profile-select">
|
<div v-if="isRenaming" class="profile-select">
|
||||||
<div class="profile-item-name">重命名 RPC 预设:</div>
|
<div class="profile-item-name">重命名 RPC 预设:</div>
|
||||||
<TextBox ref="renameInput" v-model="profileRename" />
|
<TextBox ref="renameInput" v-model="profileRename" />
|
||||||
@ -69,17 +73,19 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getComponentSettings } from '@/core/settings'
|
import { getComponentSettings } from '@/core/settings'
|
||||||
import { Toast } from '@/core/toast'
|
import { Toast } from '@/core/toast'
|
||||||
import { TextBox, VButton, VIcon, VDropdown, TextArea } from '@/ui'
|
import { TextBox, VButton, VIcon, VDropdown, TextArea, SwitchBox } from '@/ui'
|
||||||
import { Aria2RpcProfile, defaultProfile } from './rpc-profiles'
|
import { Aria2RpcProfile, defaultProfile } from './rpc-profiles'
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
rpcProfiles: Aria2RpcProfile[]
|
rpcProfiles: Aria2RpcProfile[]
|
||||||
selectedRpcProfileName: string
|
selectedRpcProfileName: string
|
||||||
|
isPluginDownloadAssets: boolean
|
||||||
}
|
}
|
||||||
const { options: storedOptions } = getComponentSettings('downloadVideo')
|
const { options: storedOptions } = getComponentSettings('downloadVideo')
|
||||||
const defaultOptions: Options = {
|
const defaultOptions: Options = {
|
||||||
rpcProfiles: [defaultProfile],
|
rpcProfiles: [defaultProfile],
|
||||||
selectedRpcProfileName: defaultProfile.name,
|
selectedRpcProfileName: defaultProfile.name,
|
||||||
|
isPluginDownloadAssets: false,
|
||||||
}
|
}
|
||||||
const options = { ...defaultOptions, ...storedOptions }
|
const options = { ...defaultOptions, ...storedOptions }
|
||||||
const handleMissingProfile = () => {
|
const handleMissingProfile = () => {
|
||||||
@ -99,6 +105,7 @@ export default Vue.extend({
|
|||||||
VIcon,
|
VIcon,
|
||||||
VDropdown,
|
VDropdown,
|
||||||
TextArea,
|
TextArea,
|
||||||
|
SwitchBox,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -106,12 +113,14 @@ export default Vue.extend({
|
|||||||
profileRename: '',
|
profileRename: '',
|
||||||
rpcProfiles: options.rpcProfiles,
|
rpcProfiles: options.rpcProfiles,
|
||||||
selectedRpcProfile: lastSelectedProfile,
|
selectedRpcProfile: lastSelectedProfile,
|
||||||
|
isPluginDownloadAssets: options.isPluginDownloadAssets,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
saveSettings() {
|
saveSettings() {
|
||||||
options.selectedRpcProfileName = this.selectedRpcProfile.name
|
options.selectedRpcProfileName = this.selectedRpcProfile.name
|
||||||
options.rpcProfiles = this.rpcProfiles
|
options.rpcProfiles = this.rpcProfiles
|
||||||
|
options.isPluginDownloadAssets = this.isPluginDownloadAssets
|
||||||
Object.assign(storedOptions, options)
|
Object.assign(storedOptions, options)
|
||||||
},
|
},
|
||||||
async startRename() {
|
async startRename() {
|
||||||
|
|||||||
@ -131,35 +131,59 @@ export const aria2Rpc: DownloadVideoOutput = {
|
|||||||
action,
|
action,
|
||||||
instance: Vue & {
|
instance: Vue & {
|
||||||
selectedRpcProfile: Aria2RpcProfile
|
selectedRpcProfile: Aria2RpcProfile
|
||||||
|
isPluginDownloadAssets?: boolean
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
const { infos } = action
|
const { infos, extraOnlineAssets } = action
|
||||||
const { selectedRpcProfile } = instance
|
const { selectedRpcProfile, isPluginDownloadAssets } = instance
|
||||||
const { secretKey, dir, other } = selectedRpcProfile
|
const { secretKey, dir, other } = selectedRpcProfile
|
||||||
const referer = document.URL.replace(window.location.search, '')
|
const referer = document.URL.replace(window.location.search, '')
|
||||||
const totalParams = infos
|
const ariaParamsGenerator = (url: string, title: string) => {
|
||||||
.map(info =>
|
|
||||||
info.titledFragments.map(fragment => {
|
|
||||||
const singleInfoParams = []
|
const singleInfoParams = []
|
||||||
if (secretKey) {
|
if (secretKey) {
|
||||||
singleInfoParams.push(`token:${secretKey}`)
|
singleInfoParams.push(`token:${secretKey}`)
|
||||||
}
|
}
|
||||||
singleInfoParams.push([fragment.url])
|
singleInfoParams.push([url])
|
||||||
singleInfoParams.push({
|
singleInfoParams.push({
|
||||||
referer,
|
referer,
|
||||||
'user-agent': UserAgent,
|
'user-agent': UserAgent,
|
||||||
out: fragment.title,
|
out: title,
|
||||||
dir: dir || undefined,
|
dir: dir || undefined,
|
||||||
...parseRpcOptions(other),
|
...parseRpcOptions(other),
|
||||||
})
|
})
|
||||||
const id = encodeURIComponent(fragment.title)
|
const id = encodeURIComponent(title)
|
||||||
return {
|
return {
|
||||||
params: singleInfoParams,
|
params: singleInfoParams,
|
||||||
id,
|
id,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle video params
|
||||||
|
const videoParams = infos
|
||||||
|
.map(info =>
|
||||||
|
info.titledFragments.map(fragment => {
|
||||||
|
const { url, title } = fragment
|
||||||
|
return ariaParamsGenerator(url, title)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.flat()
|
.flat()
|
||||||
|
|
||||||
|
// handle assets
|
||||||
|
const assetsAriaParams = []
|
||||||
|
const extraAssetsForBrowerDownload = []
|
||||||
|
for (const { asset, instance: assetInstance } of extraOnlineAssets) {
|
||||||
|
if (isPluginDownloadAssets && 'getUrls' in asset) {
|
||||||
|
// get asset from aria2
|
||||||
|
const results = await asset.getUrls(infos, assetInstance)
|
||||||
|
assetsAriaParams.push(...results.map(({ name, url }) => ariaParamsGenerator(url, name)))
|
||||||
|
} else {
|
||||||
|
// remain asset in `extraOnlineAssets`
|
||||||
|
extraAssetsForBrowerDownload.push({ asset, instance: assetInstance })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action.extraOnlineAssets = extraAssetsForBrowerDownload
|
||||||
|
|
||||||
|
const totalParams = [...videoParams, ...assetsAriaParams]
|
||||||
const results = await sendRpc(selectedRpcProfile, totalParams)
|
const results = await sendRpc(selectedRpcProfile, totalParams)
|
||||||
console.table(results)
|
console.table(results)
|
||||||
if (results.length === 1) {
|
if (results.length === 1) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user