diff --git a/registry/dist/components/video/download.js b/registry/dist/components/video/download.js index a65e3231c..59cfd14c6 100644 --- a/registry/dist/components/video/download.js +++ b/registry/dist/components/video/download.js @@ -26,7 +26,7 @@ return /******/ (function() { // webpackBootstrap /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_settings__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @/core/settings */ \"@/core/settings\");\n/* harmony import */ var _core_settings__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_core_settings__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/core/utils */ \"@/core/utils\");\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_core_utils__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _core_utils_log__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/core/utils/log */ \"@/core/utils/log\");\n/* harmony import */ var _core_utils_log__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_core_utils_log__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _core_utils_formatters__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @/core/utils/formatters */ \"@/core/utils/formatters\");\n/* harmony import */ var _core_utils_formatters__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_core_utils_formatters__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _ui__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @/ui */ \"@/ui\");\n/* harmony import */ var _ui__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_ui__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _plugins_data__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @/plugins/data */ \"@/plugins/data\");\n/* harmony import */ var _plugins_data__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_plugins_data__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @/components/video/video-quality */ \"@/components/video/video-quality\");\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_components_video_video_quality__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _core_toast__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @/core/toast */ \"@/core/toast\");\n/* harmony import */ var _core_toast__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_core_toast__WEBPACK_IMPORTED_MODULE_7__);\n/* harmony import */ var _core_utils_title__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/core/utils/title */ \"@/core/utils/title\");\n/* harmony import */ var _core_utils_title__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(_core_utils_title__WEBPACK_IMPORTED_MODULE_8__);\n/* harmony import */ var _inputs_bangumi_batch__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./inputs/bangumi/batch */ \"./registry/lib/components/video/download/inputs/bangumi/batch.ts\");\n/* harmony import */ var _inputs_video_batch__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./inputs/video/batch */ \"./registry/lib/components/video/download/inputs/video/batch.ts\");\n/* harmony import */ var _inputs_video_input__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./inputs/video/input */ \"./registry/lib/components/video/download/inputs/video/input.ts\");\n/* harmony import */ var _apis_dash__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./apis/dash */ \"./registry/lib/components/video/download/apis/dash.ts\");\n/* harmony import */ var _apis_flv__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./apis/flv */ \"./registry/lib/components/video/download/apis/flv.ts\");\n/* harmony import */ var _outputs_toast__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./outputs/toast */ \"./registry/lib/components/video/download/outputs/toast.ts\");\n/* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./types */ \"./registry/lib/components/video/download/types.ts\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst [inputs] = (0,_plugins_data__WEBPACK_IMPORTED_MODULE_5__.registerAndGetData)('downloadVideo.inputs', [_inputs_video_input__WEBPACK_IMPORTED_MODULE_11__.videoSingleInput, _inputs_video_batch__WEBPACK_IMPORTED_MODULE_10__.videoBatchInput, _inputs_bangumi_batch__WEBPACK_IMPORTED_MODULE_9__.bangumiBatchInput]);\nconst [apis] = (0,_plugins_data__WEBPACK_IMPORTED_MODULE_5__.registerAndGetData)('downloadVideo.apis', [_apis_flv__WEBPACK_IMPORTED_MODULE_13__.videoFlv, _apis_dash__WEBPACK_IMPORTED_MODULE_12__.videoDashAvc, _apis_dash__WEBPACK_IMPORTED_MODULE_12__.videoDashHevc, _apis_dash__WEBPACK_IMPORTED_MODULE_12__.videoDashAv1, _apis_dash__WEBPACK_IMPORTED_MODULE_12__.audioDash]);\nconst [assets] = (0,_plugins_data__WEBPACK_IMPORTED_MODULE_5__.registerAndGetData)('downloadVideo.assets', []);\nconst [outputs] = (0,_plugins_data__WEBPACK_IMPORTED_MODULE_5__.registerAndGetData)('downloadVideo.outputs', [_outputs_toast__WEBPACK_IMPORTED_MODULE_14__.toastOutput]);\nconst {\n basicConfig\n} = (0,_core_settings__WEBPACK_IMPORTED_MODULE_0__.getComponentSettings)('downloadVideo').options;\n\nconst filterData = items => {\n const matchedItems = items.filter(it => it.match?.some(p => (0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.matchUrlPattern)(p)) ?? true);\n return matchedItems;\n};\n\nconst getFallbackTestVideoInfo = () => ({\n aid: unsafeWindow.aid,\n cid: unsafeWindow.cid,\n title: (0,_core_utils_title__WEBPACK_IMPORTED_MODULE_8__.getFriendlyTitle)(true)\n});\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Vue.extend({\n components: {\n VPopup: _ui__WEBPACK_IMPORTED_MODULE_4__.VPopup,\n VButton: _ui__WEBPACK_IMPORTED_MODULE_4__.VButton,\n VDropdown: _ui__WEBPACK_IMPORTED_MODULE_4__.VDropdown,\n VIcon: _ui__WEBPACK_IMPORTED_MODULE_4__.VIcon\n },\n props: {\n triggerElement: {\n required: true\n }\n },\n\n data() {\n const lastApi = basicConfig.api;\n const lastOutput = basicConfig.output;\n return {\n open: false,\n busy: false,\n // 测试 videoInfo, 用于获取清晰度列表和预计大小\n testData: {\n // undefined: 无法获取; null: 获取中;\n videoInfo: null,\n // 是否有多P\n multiple: false\n },\n assets,\n qualities: [],\n selectedQuality: undefined,\n inputs: [],\n selectedInput: undefined,\n apis,\n selectedApi: apis.find(it => it.name === lastApi) || apis[0],\n outputs,\n selectedOutput: outputs.find(it => it.name === lastOutput) || outputs[0]\n };\n },\n\n computed: {\n assetsWithOptions() {\n return this.assets.filter(a => a.component);\n },\n\n filteredQualities() {\n if (this.qualities.length === 0) {\n return _components_video_video_quality__WEBPACK_IMPORTED_MODULE_6__.allQualities;\n }\n\n return this.qualities;\n },\n\n canStartDownload() {\n if (this.busy || !this.open) {\n return false;\n }\n\n const isAnySelectionEmpty = Object.entries(this).filter(([key]) => key.startsWith('selected')).some(([, value]) => !value);\n\n if (isAnySelectionEmpty) {\n return false;\n }\n\n return true;\n }\n\n },\n watch: {\n selectedInput(input) {\n if (input === undefined) {\n return;\n }\n\n this.updateTestVideoInfo();\n },\n\n selectedApi(api) {\n if (api === undefined) {\n return;\n }\n\n this.updateTestVideoInfo();\n basicConfig.api = api.name;\n },\n\n selectedOutput(output) {\n if (output === undefined) {\n return;\n }\n\n basicConfig.output = output.name;\n }\n\n },\n\n mounted() {\n coreApis.observer.videoChange(() => {\n const matchedInputs = filterData(inputs);\n this.inputs = matchedInputs;\n this.selectedInput = matchedInputs[0];\n });\n },\n\n methods: {\n formatFileSize: _core_utils_formatters__WEBPACK_IMPORTED_MODULE_3__.formatFileSize,\n\n // 只有手动选择的清晰度要记录, 因此不能直接 watch\n saveSelectedQuality() {\n const quality = this.selectedQuality;\n\n if (quality === undefined) {\n return;\n }\n\n basicConfig.quality = quality.value;\n this.updateTestVideoInfo();\n },\n\n async getVideoItems() {\n const input = this.selectedInput;\n const videoItems = await input.getInputs(this.$refs.inputOptions);\n return videoItems;\n },\n\n async updateTestVideoInfo() {\n if (!this.selectedInput) {\n return;\n }\n\n this.testData.videoInfo = null;\n const input = this.selectedInput;\n const testItem = input.getTestInput?.() ?? getFallbackTestVideoInfo();\n console.log('[updateTestVideoInfo]', testItem);\n this.testData.multiple = input.batch;\n const api = this.selectedApi; // 没有清晰度信息时先获取清晰度列表\n\n if (!this.selectedQuality) {\n const videoInfo = await api.downloadVideoInfo(testItem);\n this.qualities = videoInfo.qualities;\n this.selectedQuality = videoInfo.qualities[0];\n\n if (basicConfig.quality) {\n const [matchedQuality] = videoInfo.qualities.filter(q => q.value <= basicConfig.quality);\n\n if (matchedQuality) {\n this.selectedQuality = matchedQuality;\n }\n }\n }\n\n try {\n testItem.quality = this.selectedQuality;\n const videoInfo = await api.downloadVideoInfo(testItem);\n this.testData.videoInfo = videoInfo;\n } catch (error) {\n this.testData.videoInfo = undefined;\n }\n },\n\n async startDownload(instance, output) {\n try {\n this.busy = true;\n const input = this.selectedInput;\n const api = this.selectedApi;\n const videoInputs = await input.getInputs(this.$refs.inputOptions);\n\n if (videoInputs.length === 0) {\n _core_toast__WEBPACK_IMPORTED_MODULE_7__.Toast.info('未接收到视频, 如果输入源支持批量, 请至少选择一个视频.', '下载视频', 3000);\n return;\n }\n\n videoInputs.forEach(item => {\n item.quality = this.selectedQuality;\n });\n const videoInfos = await Promise.all(videoInputs.map(i => api.downloadVideoInfo(i)));\n\n if (videoInfos.length === 0 || lodash.sumBy(videoInfos, it => it.fragments.length) === 0) {\n _core_toast__WEBPACK_IMPORTED_MODULE_7__.Toast.info('未接收到可下载数据, 请检查输入源和格式是否适用于当前视频.', '下载视频', 3000);\n return;\n }\n\n const action = new _types__WEBPACK_IMPORTED_MODULE_15__.DownloadVideoAction(videoInfos);\n const extraAssets = (await Promise.all(assets.map(a => a.getAssets(videoInfos, this.$refs.assetsOptions.find(c => c.$attrs.name === a.name))))).flat();\n action.extraAssets.push(...extraAssets);\n await action.downloadExtraAssets();\n await output.runAction(action, instance);\n } catch (error) {\n (0,_core_utils_log__WEBPACK_IMPORTED_MODULE_2__.logError)(error);\n } finally {\n this.busy = false;\n }\n }\n\n }\n}));\n\n//# sourceURL=webpack://%5Bname%5D/./registry/lib/components/video/download/DownloadVideo.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-10%5B0%5D.rules%5B0%5D.use%5B0%5D!./node_modules/vue-loader/lib/index.js??vue-loader-options"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_settings__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @/core/settings */ \"@/core/settings\");\n/* harmony import */ var _core_settings__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_core_settings__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/core/utils */ \"@/core/utils\");\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_core_utils__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _core_utils_log__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/core/utils/log */ \"@/core/utils/log\");\n/* harmony import */ var _core_utils_log__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_core_utils_log__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _core_utils_formatters__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @/core/utils/formatters */ \"@/core/utils/formatters\");\n/* harmony import */ var _core_utils_formatters__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_core_utils_formatters__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _ui__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @/ui */ \"@/ui\");\n/* harmony import */ var _ui__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_ui__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _plugins_data__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @/plugins/data */ \"@/plugins/data\");\n/* harmony import */ var _plugins_data__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_plugins_data__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @/components/video/video-quality */ \"@/components/video/video-quality\");\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_components_video_video_quality__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _core_toast__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @/core/toast */ \"@/core/toast\");\n/* harmony import */ var _core_toast__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_core_toast__WEBPACK_IMPORTED_MODULE_7__);\n/* harmony import */ var _core_utils_title__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @/core/utils/title */ \"@/core/utils/title\");\n/* harmony import */ var _core_utils_title__WEBPACK_IMPORTED_MODULE_8___default = /*#__PURE__*/__webpack_require__.n(_core_utils_title__WEBPACK_IMPORTED_MODULE_8__);\n/* harmony import */ var _inputs_bangumi_batch__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./inputs/bangumi/batch */ \"./registry/lib/components/video/download/inputs/bangumi/batch.ts\");\n/* harmony import */ var _inputs_video_batch__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./inputs/video/batch */ \"./registry/lib/components/video/download/inputs/video/batch.ts\");\n/* harmony import */ var _inputs_video_input__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./inputs/video/input */ \"./registry/lib/components/video/download/inputs/video/input.ts\");\n/* harmony import */ var _apis_dash__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./apis/dash */ \"./registry/lib/components/video/download/apis/dash.ts\");\n/* harmony import */ var _apis_flv__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./apis/flv */ \"./registry/lib/components/video/download/apis/flv.ts\");\n/* harmony import */ var _outputs_toast__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./outputs/toast */ \"./registry/lib/components/video/download/outputs/toast.ts\");\n/* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./types */ \"./registry/lib/components/video/download/types.ts\");\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nconst [inputs] = (0,_plugins_data__WEBPACK_IMPORTED_MODULE_5__.registerAndGetData)('downloadVideo.inputs', [_inputs_video_input__WEBPACK_IMPORTED_MODULE_11__.videoSingleInput, _inputs_video_batch__WEBPACK_IMPORTED_MODULE_10__.videoBatchInput, _inputs_bangumi_batch__WEBPACK_IMPORTED_MODULE_9__.bangumiBatchInput]);\nconst [apis] = (0,_plugins_data__WEBPACK_IMPORTED_MODULE_5__.registerAndGetData)('downloadVideo.apis', [_apis_flv__WEBPACK_IMPORTED_MODULE_13__.videoFlv, _apis_dash__WEBPACK_IMPORTED_MODULE_12__.videoDashAvc, _apis_dash__WEBPACK_IMPORTED_MODULE_12__.videoDashHevc, _apis_dash__WEBPACK_IMPORTED_MODULE_12__.videoDashAv1, _apis_dash__WEBPACK_IMPORTED_MODULE_12__.videoAudioDash]);\nconst [assets] = (0,_plugins_data__WEBPACK_IMPORTED_MODULE_5__.registerAndGetData)('downloadVideo.assets', []);\nconst [outputs] = (0,_plugins_data__WEBPACK_IMPORTED_MODULE_5__.registerAndGetData)('downloadVideo.outputs', [_outputs_toast__WEBPACK_IMPORTED_MODULE_14__.toastOutput]);\nconst {\n basicConfig\n} = (0,_core_settings__WEBPACK_IMPORTED_MODULE_0__.getComponentSettings)('downloadVideo').options;\n\nconst filterData = items => {\n const matchedItems = items.filter(it => it.match?.some(p => (0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.matchUrlPattern)(p)) ?? true);\n return matchedItems;\n};\n\nconst getFallbackTestVideoInfo = () => ({\n aid: unsafeWindow.aid,\n cid: unsafeWindow.cid,\n title: (0,_core_utils_title__WEBPACK_IMPORTED_MODULE_8__.getFriendlyTitle)(true)\n});\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Vue.extend({\n components: {\n VPopup: _ui__WEBPACK_IMPORTED_MODULE_4__.VPopup,\n VButton: _ui__WEBPACK_IMPORTED_MODULE_4__.VButton,\n VDropdown: _ui__WEBPACK_IMPORTED_MODULE_4__.VDropdown,\n VIcon: _ui__WEBPACK_IMPORTED_MODULE_4__.VIcon\n },\n props: {\n triggerElement: {\n required: true\n }\n },\n\n data() {\n const lastOutput = basicConfig.output;\n return {\n open: false,\n busy: false,\n // 测试 videoInfo, 用于获取清晰度列表和预计大小\n testData: {\n // undefined: 无法获取; null: 获取中;\n videoInfo: null,\n // 是否有多P\n multiple: false\n },\n assets,\n qualities: [],\n selectedQuality: undefined,\n inputs: [],\n selectedInput: undefined,\n apis: [],\n selectedApi: undefined,\n outputs,\n selectedOutput: outputs.find(it => it.name === lastOutput) || outputs[0]\n };\n },\n\n computed: {\n assetsWithOptions() {\n return this.assets.filter(a => a.component);\n },\n\n filteredQualities() {\n if (this.qualities.length === 0) {\n return _components_video_video_quality__WEBPACK_IMPORTED_MODULE_6__.allQualities;\n }\n\n return this.qualities;\n },\n\n canStartDownload() {\n if (this.busy || !this.open) {\n return false;\n }\n\n const isAnySelectionEmpty = Object.entries(this).filter(([key]) => key.startsWith('selected')).some(([, value]) => !value);\n\n if (isAnySelectionEmpty) {\n return false;\n }\n\n return true;\n }\n\n },\n watch: {\n selectedInput(input) {\n if (input === undefined) {\n return;\n }\n\n this.updateTestVideoInfo();\n },\n\n selectedApi(api) {\n if (api === undefined) {\n return;\n }\n\n this.updateTestVideoInfo();\n basicConfig.api = api.name;\n },\n\n selectedOutput(output) {\n if (output === undefined) {\n return;\n }\n\n basicConfig.output = output.name;\n }\n\n },\n\n mounted() {\n coreApis.observer.videoChange(() => {\n const matchedInputs = filterData(inputs);\n this.inputs = matchedInputs;\n this.selectedInput = matchedInputs[0];\n const matchedApis = filterData(apis);\n this.apis = matchedApis;\n const lastApi = matchedApis.find(api => api.name === basicConfig.api);\n\n if (lastApi) {\n this.selectedApi = lastApi;\n } else {\n this.selectedApi = matchedApis[0];\n }\n });\n },\n\n methods: {\n formatFileSize: _core_utils_formatters__WEBPACK_IMPORTED_MODULE_3__.formatFileSize,\n\n // 只有手动选择的清晰度要记录, 因此不能直接 watch\n saveSelectedQuality() {\n const quality = this.selectedQuality;\n\n if (quality === undefined) {\n return;\n }\n\n basicConfig.quality = quality.value;\n this.updateTestVideoInfo();\n },\n\n async getVideoItems() {\n const input = this.selectedInput;\n const videoItems = await input.getInputs(this.$refs.inputOptions);\n return videoItems;\n },\n\n async updateTestVideoInfo() {\n if (!this.selectedInput || !this.selectedApi) {\n return;\n }\n\n this.testData.videoInfo = null;\n const input = this.selectedInput;\n const testItem = input.getTestInput?.() ?? getFallbackTestVideoInfo();\n console.log('[updateTestVideoInfo]', testItem);\n this.testData.multiple = input.batch;\n const api = this.selectedApi; // 没有清晰度信息时先获取清晰度列表\n\n if (!this.selectedQuality) {\n const videoInfo = await api.downloadVideoInfo(testItem);\n this.qualities = videoInfo.qualities;\n this.selectedQuality = videoInfo.qualities[0];\n\n if (basicConfig.quality) {\n const [matchedQuality] = videoInfo.qualities.filter(q => q.value <= basicConfig.quality);\n\n if (matchedQuality) {\n this.selectedQuality = matchedQuality;\n }\n }\n }\n\n try {\n testItem.quality = this.selectedQuality;\n const videoInfo = await api.downloadVideoInfo(testItem);\n this.testData.videoInfo = videoInfo;\n } catch (error) {\n this.testData.videoInfo = undefined;\n }\n },\n\n async startDownload(instance, output) {\n try {\n this.busy = true;\n const input = this.selectedInput;\n const api = this.selectedApi;\n const videoInputs = await input.getInputs(this.$refs.inputOptions);\n\n if (videoInputs.length === 0) {\n _core_toast__WEBPACK_IMPORTED_MODULE_7__.Toast.info('未接收到视频, 如果输入源支持批量, 请至少选择一个视频.', '下载视频', 3000);\n return;\n }\n\n videoInputs.forEach(item => {\n item.quality = this.selectedQuality;\n });\n const videoInfos = await Promise.all(videoInputs.map(i => api.downloadVideoInfo(i)));\n\n if (videoInfos.length === 0 || lodash.sumBy(videoInfos, it => it.fragments.length) === 0) {\n _core_toast__WEBPACK_IMPORTED_MODULE_7__.Toast.info('未接收到可下载数据, 请检查输入源和格式是否适用于当前视频.', '下载视频', 3000);\n return;\n }\n\n const action = new _types__WEBPACK_IMPORTED_MODULE_15__.DownloadVideoAction(videoInfos);\n const extraAssets = (await Promise.all(assets.map(a => a.getAssets(videoInfos, this.$refs.assetsOptions.find(c => c.$attrs.name === a.name))))).flat();\n action.extraAssets.push(...extraAssets);\n await action.downloadExtraAssets();\n await output.runAction(action, instance);\n } catch (error) {\n (0,_core_utils_log__WEBPACK_IMPORTED_MODULE_2__.logError)(error);\n } finally {\n this.busy = false;\n }\n }\n\n }\n}));\n\n//# sourceURL=webpack://%5Bname%5D/./registry/lib/components/video/download/DownloadVideo.vue?./node_modules/babel-loader/lib/index.js??clonedRuleSet-10%5B0%5D.rules%5B0%5D.use%5B0%5D!./node_modules/vue-loader/lib/index.js??vue-loader-options"); /***/ }), @@ -70,7 +70,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _cor /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"DashExtensions\": function() { return /* binding */ DashExtensions; },\n/* harmony export */ \"DashFragmentExtension\": function() { return /* binding */ DashFragmentExtension; },\n/* harmony export */ \"DashCodec\": function() { return /* binding */ DashCodec; },\n/* harmony export */ \"dashToFragments\": function() { return /* binding */ dashToFragments; },\n/* harmony export */ \"videoDashAvc\": function() { return /* binding */ videoDashAvc; },\n/* harmony export */ \"videoDashHevc\": function() { return /* binding */ videoDashHevc; },\n/* harmony export */ \"videoDashAv1\": function() { return /* binding */ videoDashAv1; },\n/* harmony export */ \"audioDash\": function() { return /* binding */ audioDash; }\n/* harmony export */ });\n/* harmony import */ var _core_ajax__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @/core/ajax */ \"@/core/ajax\");\n/* harmony import */ var _core_ajax__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_core_ajax__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/core/utils */ \"@/core/utils\");\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_core_utils__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _core_utils_sort__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/core/utils/sort */ \"@/core/utils/sort\");\n/* harmony import */ var _core_utils_sort__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_core_utils_sort__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @/components/video/video-quality */ \"@/components/video/video-quality\");\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_components_video_video_quality__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _error__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../error */ \"./registry/lib/components/video/download/error.ts\");\n/* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../types */ \"./registry/lib/components/video/download/types.ts\");\n\n\n\n\n\n\n/* spell-checker: disable */\n\n/** dash 格式更明确的扩展名 */\n\nconst DashExtensions = {\n video: '.mp4',\n audio: '.m4a'\n};\n/** dash 格式原本的扩展名 */\n\nconst DashFragmentExtension = '.m4s';\n/** dash 格式支持的编码类型 */\n\nlet DashCodec;\n\n(function (DashCodec) {\n DashCodec[\"Avc\"] = \"AVC/H.264\";\n DashCodec[\"Hevc\"] = \"HEVC/H.265\";\n DashCodec[\"Av1\"] = \"AV1\";\n})(DashCodec || (DashCodec = {}));\n\nconst dashToFragment = dash => ({\n url: dash.downloadUrl,\n backupUrls: dash.backupUrls,\n length: dash.duration,\n size: Math.trunc(dash.bandWidth * dash.duration / 8),\n extension: DashExtensions[dash.type] ?? DashFragmentExtension\n});\n\nconst dashToFragments = info => {\n const {\n videoDashes,\n audioDashes,\n videoCodec\n } = info;\n const results = []; // 画面按照首选编码选择, 若没有相应编码则选择大小较小的编码\n\n if (videoDashes.length !== 0) {\n const matchPreferredCodec = d => d.videoCodec === videoCodec;\n\n if (videoDashes.some(matchPreferredCodec)) {\n const dash = videoDashes.filter(matchPreferredCodec).sort((0,_core_utils_sort__WEBPACK_IMPORTED_MODULE_2__.ascendingSort)(d => d.bandWidth))[0];\n results.push(dashToFragment(dash));\n } else {\n results.push(dashToFragment(videoDashes.sort((0,_core_utils_sort__WEBPACK_IMPORTED_MODULE_2__.ascendingSort)(d => d.bandWidth))[0]));\n }\n }\n\n if (audioDashes.length !== 0) {\n // 声音倒序排, 选择最高音质\n const audio = audioDashes.sort((0,_core_utils_sort__WEBPACK_IMPORTED_MODULE_2__.descendingSort)(d => d.bandWidth))[0];\n results.push(dashToFragment(audio));\n }\n\n return results;\n};\n\nconst downloadDash = async (input, config) => {\n const {\n codec = DashCodec.Avc,\n filters\n } = config;\n const dashFilters = {\n video: () => true,\n audio: () => true,\n ...filters\n };\n const {\n aid,\n cid,\n quality\n } = input;\n const params = {\n avid: aid,\n cid,\n qn: quality?.value ?? '',\n otype: 'json',\n fourk: 1,\n fnver: 0,\n fnval: 4048\n };\n const api = `https://api.bilibili.com/x/player/playurl?${(0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.formData)(params)}`;\n const data = await (0,_core_ajax__WEBPACK_IMPORTED_MODULE_0__.bilibiliApi)((0,_core_ajax__WEBPACK_IMPORTED_MODULE_0__.getJsonWithCredentials)(api), '获取视频链接失败');\n\n if (!data.dash) {\n throw new Error('此视频没有 dash 格式, 请改用其他格式.');\n }\n\n const currentQuality = _components_video_video_quality__WEBPACK_IMPORTED_MODULE_3__.allQualities.find(q => q.value === data.quality);\n const {\n duration,\n video,\n audio,\n dolby\n } = data.dash;\n const videoDashes = video.filter(d => d.id === currentQuality.value).map(d => {\n const videoCodec = (() => {\n switch (d.codecid) {\n case 12:\n return DashCodec.Hevc;\n\n case 13:\n return DashCodec.Av1;\n\n default:\n case 7:\n return DashCodec.Avc;\n }\n })();\n\n const dash = {\n type: 'video',\n quality: currentQuality,\n width: d.width,\n height: d.height,\n codecs: d.codecs,\n codecId: d.codecid,\n bandWidth: d.bandwidth,\n frameRate: d.frameRate,\n backupUrls: (d.backupUrl || d.backup_url || []).map(it => it.replace('http:', 'https:')),\n downloadUrl: (d.baseUrl || d.base_url || '').replace('http:', 'https:'),\n duration,\n videoCodec\n };\n return dash;\n }).filter(d => dashFilters.video(d));\n const audioDashes = (audio || []).map(d => ({\n type: 'audio',\n bandWidth: d.bandwidth,\n codecs: d.codecs,\n codecId: d.codecid,\n backupUrls: (d.backupUrl || d.backup_url || []).map(it => it.replace('http:', 'https:')),\n downloadUrl: (d.baseUrl || d.base_url || '').replace('http:', 'https:'),\n duration\n })).filter(d => dashFilters.audio(d));\n\n if (dolby) {\n audioDashes.push(...(dolby.audio?.map(d => ({\n type: 'audio',\n bandWidth: d.bandwidth,\n codecs: d.codecs,\n codecId: -1,\n // unknown id\n backupUrls: [],\n downloadUrl: (d.baseUrl || d.base_url || '').replace('http:', 'https:'),\n duration\n })) ?? []));\n }\n\n const fragments = dashToFragments({\n audioDashes,\n videoDashes,\n videoCodec: codec\n });\n const qualities = data.accept_quality.map(qn => _components_video_video_quality__WEBPACK_IMPORTED_MODULE_3__.allQualities.find(q => q.value === qn)).filter(q => q !== undefined);\n const info = new _types__WEBPACK_IMPORTED_MODULE_5__.DownloadVideoInfo({\n input,\n jsonData: data,\n fragments,\n qualities,\n currentQuality\n });\n (0,_error__WEBPACK_IMPORTED_MODULE_4__.compareQuality)(input, info);\n return info;\n};\n\nconst videoDashAvc = {\n name: 'video.dash.avc',\n displayName: 'dash (AVC/H.264)',\n description: '音画分离的 mp4 格式, 编码为 H.264, 兼容性较好. 下载后可以合并为单个 mp4 文件.',\n downloadVideoInfo: async input => downloadDash(input, {\n codec: DashCodec.Avc\n })\n};\nconst videoDashHevc = {\n name: 'video.dash.hevc',\n displayName: 'dash (HEVC/H.265)',\n description: '音画分离的 mp4 格式, 编码为 H.265, 体积较小, 兼容性较差. 下载后可以合并为单个 mp4 文件.',\n downloadVideoInfo: async input => downloadDash(input, {\n codec: DashCodec.Hevc\n })\n};\nconst videoDashAv1 = {\n name: 'video.dash.av1',\n displayName: 'dash (AV1)',\n description: '音画分离的 mp4 格式, 编码为 AV1, 体积较小, 兼容性较差. 下载后可以合并为单个 mp4 文件.',\n downloadVideoInfo: async input => downloadDash(input, {\n codec: DashCodec.Av1\n })\n};\nconst audioDash = {\n name: 'video.dash.audio',\n displayName: 'dash (仅音频)',\n description: '仅下载视频中的音频轨道.',\n downloadVideoInfo: async input => downloadDash(input, {\n filters: {\n video: () => false\n }\n })\n};\n\n//# sourceURL=webpack://%5Bname%5D/./registry/lib/components/video/download/apis/dash.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"DashExtensions\": function() { return /* binding */ DashExtensions; },\n/* harmony export */ \"DashFragmentExtension\": function() { return /* binding */ DashFragmentExtension; },\n/* harmony export */ \"DashCodec\": function() { return /* binding */ DashCodec; },\n/* harmony export */ \"dashToFragments\": function() { return /* binding */ dashToFragments; },\n/* harmony export */ \"videoDashAvc\": function() { return /* binding */ videoDashAvc; },\n/* harmony export */ \"videoDashHevc\": function() { return /* binding */ videoDashHevc; },\n/* harmony export */ \"videoDashAv1\": function() { return /* binding */ videoDashAv1; },\n/* harmony export */ \"videoAudioDash\": function() { return /* binding */ videoAudioDash; }\n/* harmony export */ });\n/* harmony import */ var _core_ajax__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @/core/ajax */ \"@/core/ajax\");\n/* harmony import */ var _core_ajax__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_core_ajax__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/core/utils */ \"@/core/utils\");\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_core_utils__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _core_utils_sort__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/core/utils/sort */ \"@/core/utils/sort\");\n/* harmony import */ var _core_utils_sort__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_core_utils_sort__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @/components/video/video-quality */ \"@/components/video/video-quality\");\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_components_video_video_quality__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _core_utils_urls__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @/core/utils/urls */ \"@/core/utils/urls\");\n/* harmony import */ var _core_utils_urls__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_core_utils_urls__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _error__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../error */ \"./registry/lib/components/video/download/error.ts\");\n/* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../types */ \"./registry/lib/components/video/download/types.ts\");\n/* harmony import */ var _url__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./url */ \"./registry/lib/components/video/download/apis/url.ts\");\n\n\n\n\n\n\n\n\n/** dash 格式更明确的扩展名 */\n\nconst DashExtensions = {\n video: '.mp4',\n audio: '.m4a'\n};\n/** dash 格式原本的扩展名 */\n\nconst DashFragmentExtension = '.m4s';\n/** dash 格式支持的编码类型 */\n\nlet DashCodec;\n\n(function (DashCodec) {\n DashCodec[\"Avc\"] = \"AVC/H.264\";\n DashCodec[\"Hevc\"] = \"HEVC/H.265\";\n DashCodec[\"Av1\"] = \"AV1\";\n})(DashCodec || (DashCodec = {}));\n\nconst dashToFragment = dash => ({\n url: dash.downloadUrl,\n backupUrls: dash.backupUrls,\n length: dash.duration,\n size: Math.trunc(dash.bandWidth * dash.duration / 8),\n extension: DashExtensions[dash.type] ?? DashFragmentExtension\n});\n\nconst dashToFragments = info => {\n const {\n videoDashes,\n audioDashes,\n videoCodec\n } = info;\n const results = []; // 画面按照首选编码选择, 若没有相应编码则选择大小较小的编码\n\n if (videoDashes.length !== 0) {\n const matchPreferredCodec = d => d.videoCodec === videoCodec;\n\n if (videoDashes.some(matchPreferredCodec)) {\n const dash = videoDashes.filter(matchPreferredCodec).sort((0,_core_utils_sort__WEBPACK_IMPORTED_MODULE_2__.ascendingSort)(d => d.bandWidth))[0];\n results.push(dashToFragment(dash));\n } else {\n results.push(dashToFragment(videoDashes.sort((0,_core_utils_sort__WEBPACK_IMPORTED_MODULE_2__.ascendingSort)(d => d.bandWidth))[0]));\n }\n }\n\n if (audioDashes.length !== 0) {\n // 声音倒序排, 选择最高音质\n const audio = audioDashes.sort((0,_core_utils_sort__WEBPACK_IMPORTED_MODULE_2__.descendingSort)(d => d.bandWidth))[0];\n results.push(dashToFragment(audio));\n }\n\n return results;\n};\n/* spell-checker: disable */\n\nconst downloadDash = async (input, config = {}) => {\n const {\n codec = DashCodec.Avc,\n filters\n } = config;\n const dashFilters = {\n video: () => true,\n audio: () => true,\n ...filters\n };\n const {\n aid,\n cid,\n quality\n } = input;\n const params = {\n avid: aid,\n cid,\n qn: quality?.value ?? '',\n otype: 'json',\n fourk: 1,\n fnver: 0,\n fnval: 4048\n };\n const isBanugmi = _core_utils_urls__WEBPACK_IMPORTED_MODULE_4__.bangumiUrls.some(url => (0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.matchUrlPattern)(url));\n const api = isBanugmi ? (0,_url__WEBPACK_IMPORTED_MODULE_7__.bangumiApi)((0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.formData)(params)) : (0,_url__WEBPACK_IMPORTED_MODULE_7__.videoApi)((0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.formData)(params));\n const data = await (0,_core_ajax__WEBPACK_IMPORTED_MODULE_0__.bilibiliApi)((0,_core_ajax__WEBPACK_IMPORTED_MODULE_0__.getJsonWithCredentials)(api), '获取视频链接失败');\n\n if (!data.dash) {\n throw new Error('此视频没有 dash 格式, 请改用其他格式.');\n }\n\n const currentQuality = _components_video_video_quality__WEBPACK_IMPORTED_MODULE_3__.allQualities.find(q => q.value === data.quality);\n const {\n duration,\n video,\n audio,\n dolby\n } = data.dash;\n const videoDashes = video.filter(d => d.id === currentQuality.value).map(d => {\n const videoCodec = (() => {\n switch (d.codecid) {\n case 12:\n return DashCodec.Hevc;\n\n case 13:\n return DashCodec.Av1;\n\n default:\n case 7:\n return DashCodec.Avc;\n }\n })();\n\n const dash = {\n type: 'video',\n quality: currentQuality,\n width: d.width,\n height: d.height,\n codecs: d.codecs,\n codecId: d.codecid,\n bandWidth: d.bandwidth,\n frameRate: d.frameRate,\n backupUrls: (d.backupUrl || d.backup_url || []).map(it => it.replace('http:', 'https:')),\n downloadUrl: (d.baseUrl || d.base_url || '').replace('http:', 'https:'),\n duration,\n videoCodec\n };\n return dash;\n }).filter(d => dashFilters.video(d));\n const audioDashes = (audio || []).map(d => ({\n type: 'audio',\n bandWidth: d.bandwidth,\n codecs: d.codecs,\n codecId: d.codecid,\n backupUrls: (d.backupUrl || d.backup_url || []).map(it => it.replace('http:', 'https:')),\n downloadUrl: (d.baseUrl || d.base_url || '').replace('http:', 'https:'),\n duration\n })).filter(d => dashFilters.audio(d));\n\n if (dolby) {\n audioDashes.push(...(dolby.audio?.map(d => ({\n type: 'audio',\n bandWidth: d.bandwidth,\n codecs: d.codecs,\n codecId: -1,\n // unknown id\n backupUrls: [],\n downloadUrl: (d.baseUrl || d.base_url || '').replace('http:', 'https:'),\n duration\n })) ?? []));\n }\n\n const fragments = dashToFragments({\n audioDashes,\n videoDashes,\n videoCodec: codec\n });\n const qualities = data.accept_quality.map(qn => _components_video_video_quality__WEBPACK_IMPORTED_MODULE_3__.allQualities.find(q => q.value === qn)).filter(q => q !== undefined);\n const info = new _types__WEBPACK_IMPORTED_MODULE_6__.DownloadVideoInfo({\n input,\n jsonData: data,\n fragments,\n qualities,\n currentQuality\n });\n (0,_error__WEBPACK_IMPORTED_MODULE_5__.compareQuality)(input, info);\n return info;\n};\n\nconst videoDashAvc = {\n name: 'video.dash.avc',\n displayName: 'dash (AVC/H.264)',\n description: '音画分离的 mp4 格式, 编码为 H.264, 兼容性较好. 下载后可以合并为单个 mp4 文件.',\n downloadVideoInfo: async input => downloadDash(input, {\n codec: DashCodec.Avc\n })\n};\nconst videoDashHevc = {\n name: 'video.dash.hevc',\n displayName: 'dash (HEVC/H.265)',\n description: '音画分离的 mp4 格式, 编码为 H.265, 体积较小, 兼容性较差. 下载后可以合并为单个 mp4 文件.',\n downloadVideoInfo: async input => downloadDash(input, {\n codec: DashCodec.Hevc\n })\n};\nconst videoDashAv1 = {\n name: 'video.dash.av1',\n displayName: 'dash (AV1)',\n description: '音画分离的 mp4 格式, 编码为 AV1, 体积较小, 兼容性较差. 下载后可以合并为单个 mp4 文件.',\n downloadVideoInfo: async input => downloadDash(input, {\n codec: DashCodec.Av1\n })\n};\nconst videoAudioDash = {\n name: 'video.dash.audio',\n displayName: 'dash (仅音频)',\n description: '仅下载视频中的音频轨道.',\n downloadVideoInfo: async input => downloadDash(input, {\n filters: {\n video: () => false\n }\n })\n};\n\n//# sourceURL=webpack://%5Bname%5D/./registry/lib/components/video/download/apis/dash.ts?"); /***/ }), @@ -81,7 +81,18 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"videoFlv\": function() { return /* binding */ videoFlv; }\n/* harmony export */ });\n/* harmony import */ var _core_ajax__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @/core/ajax */ \"@/core/ajax\");\n/* harmony import */ var _core_ajax__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_core_ajax__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/core/utils */ \"@/core/utils\");\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_core_utils__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/components/video/video-quality */ \"@/components/video/video-quality\");\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_components_video_video_quality__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _error__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../error */ \"./registry/lib/components/video/download/error.ts\");\n/* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../types */ \"./registry/lib/components/video/download/types.ts\");\n\n\n\n\n\n\nconst parseInfoFromJson = (data, extensions) => {\n const getExtension = index => {\n if (extensions.length > index) {\n return extensions[index];\n }\n\n return extensions[extensions.length - 1];\n };\n\n const fragments = data.durl.map((it, index) => ({\n length: it.length,\n size: it.size,\n url: it.url,\n backupUrls: it.backup_url,\n extension: getExtension(index)\n }));\n const qualities = data.accept_quality.map(qn => _components_video_video_quality__WEBPACK_IMPORTED_MODULE_2__.allQualities.find(q => q.value === qn)).filter(q => q !== undefined);\n const currentQuality = _components_video_video_quality__WEBPACK_IMPORTED_MODULE_2__.allQualities.find(q => q.value === data.quality);\n return {\n fragments,\n qualities,\n currentQuality\n };\n};\n/* spell-checker: disable */\n\n\nconst videoFlv = {\n name: 'video.flv',\n displayName: 'flv',\n description: '使用 flv 格式下载, 兼容 H.264 编码.',\n downloadVideoInfo: async input => {\n const {\n aid,\n cid,\n quality\n } = input;\n const params = {\n avid: aid,\n cid,\n qn: quality?.value ?? '',\n otype: 'json',\n fourk: 1,\n fnver: 0,\n fnval: 0\n };\n const api = `https://api.bilibili.com/x/player/playurl?${(0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.formData)(params)}`;\n const data = await (0,_core_ajax__WEBPACK_IMPORTED_MODULE_0__.bilibiliApi)((0,_core_ajax__WEBPACK_IMPORTED_MODULE_0__.getJsonWithCredentials)(api), '获取视频链接失败');\n const info = new _types__WEBPACK_IMPORTED_MODULE_4__.DownloadVideoInfo({\n input,\n jsonData: data,\n ...parseInfoFromJson(data, ['.flv'])\n });\n (0,_error__WEBPACK_IMPORTED_MODULE_3__.compareQuality)(input, info);\n return info;\n }\n};\n\n//# sourceURL=webpack://%5Bname%5D/./registry/lib/components/video/download/apis/flv.ts?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"videoFlv\": function() { return /* binding */ videoFlv; }\n/* harmony export */ });\n/* harmony import */ var _core_ajax__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @/core/ajax */ \"@/core/ajax\");\n/* harmony import */ var _core_ajax__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_core_ajax__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/core/utils */ \"@/core/utils\");\n/* harmony import */ var _core_utils__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_core_utils__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/components/video/video-quality */ \"@/components/video/video-quality\");\n/* harmony import */ var _components_video_video_quality__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_components_video_video_quality__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _core_utils_urls__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @/core/utils/urls */ \"@/core/utils/urls\");\n/* harmony import */ var _core_utils_urls__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_core_utils_urls__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _error__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../error */ \"./registry/lib/components/video/download/error.ts\");\n/* harmony import */ var _types__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../types */ \"./registry/lib/components/video/download/types.ts\");\n/* harmony import */ var _url__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./url */ \"./registry/lib/components/video/download/apis/url.ts\");\n\n\n\n\n\n\n\n\nconst parseInfoFromJson = (data, extensions) => {\n const getExtension = index => {\n if (extensions.length > index) {\n return extensions[index];\n }\n\n return extensions[extensions.length - 1];\n };\n\n const fragments = data.durl.map((it, index) => ({\n length: it.length,\n size: it.size,\n url: it.url,\n backupUrls: it.backup_url,\n extension: getExtension(index)\n }));\n const qualities = data.accept_quality.map(qn => _components_video_video_quality__WEBPACK_IMPORTED_MODULE_2__.allQualities.find(q => q.value === qn)).filter(q => q !== undefined);\n const currentQuality = _components_video_video_quality__WEBPACK_IMPORTED_MODULE_2__.allQualities.find(q => q.value === data.quality);\n return {\n fragments,\n qualities,\n currentQuality\n };\n};\n/* spell-checker: disable */\n\n\nconst downloadFlv = async (input) => {\n const {\n aid,\n cid,\n quality\n } = input;\n const params = {\n avid: aid,\n cid,\n qn: quality?.value ?? '',\n otype: 'json',\n fourk: 1,\n fnver: 0,\n fnval: 0\n };\n const isBanugmi = _core_utils_urls__WEBPACK_IMPORTED_MODULE_3__.bangumiUrls.some(url => (0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.matchUrlPattern)(url));\n const api = isBanugmi ? (0,_url__WEBPACK_IMPORTED_MODULE_6__.bangumiApi)((0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.formData)(params)) : (0,_url__WEBPACK_IMPORTED_MODULE_6__.videoApi)((0,_core_utils__WEBPACK_IMPORTED_MODULE_1__.formData)(params));\n const data = await (0,_core_ajax__WEBPACK_IMPORTED_MODULE_0__.bilibiliApi)((0,_core_ajax__WEBPACK_IMPORTED_MODULE_0__.getJsonWithCredentials)(api), '获取视频链接失败');\n const info = new _types__WEBPACK_IMPORTED_MODULE_5__.DownloadVideoInfo({\n input,\n jsonData: data,\n ...parseInfoFromJson(data, ['.flv'])\n });\n (0,_error__WEBPACK_IMPORTED_MODULE_4__.compareQuality)(input, info);\n return info;\n};\n\nconst videoFlv = {\n name: 'video.flv',\n displayName: 'flv',\n description: '使用 flv 格式下载, 兼容 H.264 编码.',\n downloadVideoInfo: input => downloadFlv(input)\n};\n\n//# sourceURL=webpack://%5Bname%5D/./registry/lib/components/video/download/apis/flv.ts?"); + +/***/ }), + +/***/ "./registry/lib/components/video/download/apis/url.ts": +/*!************************************************************!*\ + !*** ./registry/lib/components/video/download/apis/url.ts ***! + \************************************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"videoApi\": function() { return /* binding */ videoApi; },\n/* harmony export */ \"bangumiApi\": function() { return /* binding */ bangumiApi; }\n/* harmony export */ });\nconst videoApi = params => `https://api.bilibili.com/x/player/playurl?${params}`;\nconst bangumiApi = params => `https://api.bilibili.com/pgc/player/web/playurl?${params}`;\n\n//# sourceURL=webpack://%5Bname%5D/./registry/lib/components/video/download/apis/url.ts?"); /***/ }), diff --git a/registry/lib/components/video/download/DownloadVideo.vue b/registry/lib/components/video/download/DownloadVideo.vue index 6bf946b06..20feb093d 100644 --- a/registry/lib/components/video/download/DownloadVideo.vue +++ b/registry/lib/components/video/download/DownloadVideo.vue @@ -144,7 +144,7 @@ import { videoDashAvc, videoDashHevc, videoDashAv1, - audioDash, + videoAudioDash, } from './apis/dash' import { videoFlv } from './apis/flv' import { toastOutput } from './outputs/toast' @@ -170,7 +170,7 @@ const [apis] = registerAndGetData( videoDashAvc, videoDashHevc, videoDashAv1, - audioDash, + videoAudioDash, ] as DownloadVideoApi[], ) const [assets] = registerAndGetData( @@ -188,7 +188,7 @@ const { basicConfig } = getComponentSettings('downloadVideo').options as { output: string } } -const filterData = (items: { match?: TestPattern }[]) => { +const filterData = (items: T[]) => { const matchedItems = items.filter(it => it.match?.some(p => matchUrlPattern(p)) ?? true) return matchedItems } @@ -208,7 +208,6 @@ export default Vue.extend({ }, }, data() { - const lastApi = basicConfig.api const lastOutput = basicConfig.output return { open: false, @@ -225,8 +224,8 @@ export default Vue.extend({ selectedQuality: undefined, inputs: [], selectedInput: undefined, - apis, - selectedApi: apis.find(it => it.name === lastApi) || apis[0], + apis: [], + selectedApi: undefined, outputs, selectedOutput: outputs.find(it => it.name === lastOutput) || outputs[0], } @@ -278,6 +277,14 @@ export default Vue.extend({ const matchedInputs = filterData(inputs) this.inputs = matchedInputs this.selectedInput = matchedInputs[0] + const matchedApis = filterData(apis) + this.apis = matchedApis + const lastApi = matchedApis.find(api => api.name === basicConfig.api) + if (lastApi) { + this.selectedApi = lastApi + } else { + this.selectedApi = matchedApis[0] + } }) }, methods: { @@ -297,7 +304,7 @@ export default Vue.extend({ return videoItems }, async updateTestVideoInfo() { - if (!this.selectedInput) { + if (!this.selectedInput || !this.selectedApi) { return } this.testData.videoInfo = null diff --git a/registry/lib/components/video/download/apis/dash.ts b/registry/lib/components/video/download/apis/dash.ts index 44a57cbe9..a39775d1f 100644 --- a/registry/lib/components/video/download/apis/dash.ts +++ b/registry/lib/components/video/download/apis/dash.ts @@ -1,13 +1,13 @@ import { bilibiliApi, getJsonWithCredentials } from '@/core/ajax' -import { formData } from '@/core/utils' +import { formData, matchUrlPattern } from '@/core/utils' import { ascendingSort, descendingSort } from '@/core/utils/sort' import { allQualities, VideoQuality } from '@/components/video/video-quality' +import { bangumiUrls } from '@/core/utils/urls' import { compareQuality } from '../error' import { DownloadVideoApi, DownloadVideoFragment, DownloadVideoInfo, DownloadVideoInputItem, } from '../types' - -/* spell-checker: disable */ +import { bangumiApi, videoApi } from './url' /** dash 格式更明确的扩展名 */ export const DashExtensions = { @@ -79,12 +79,14 @@ export const dashToFragments = (info: { } return results } + +/* spell-checker: disable */ const downloadDash = async ( input: DownloadVideoInputItem, config: { codec?: DashCodec filters?: DashFilters - }, + } = {}, ) => { const { codec = DashCodec.Avc, filters } = config const dashFilters = { @@ -102,7 +104,8 @@ const downloadDash = async ( fnver: 0, fnval: 4048, } - const api = `https://api.bilibili.com/x/player/playurl?${formData(params)}` + const isBanugmi = bangumiUrls.some(url => matchUrlPattern(url)) + const api = isBanugmi ? bangumiApi(formData(params)) : videoApi(formData(params)) const data = await bilibiliApi( getJsonWithCredentials(api), '获取视频链接失败', @@ -208,7 +211,7 @@ export const videoDashAv1: DownloadVideoApi = { description: '音画分离的 mp4 格式, 编码为 AV1, 体积较小, 兼容性较差. 下载后可以合并为单个 mp4 文件.', downloadVideoInfo: async input => downloadDash(input, { codec: DashCodec.Av1 }), } -export const audioDash: DownloadVideoApi = { +export const videoAudioDash: DownloadVideoApi = { name: 'video.dash.audio', displayName: 'dash (仅音频)', description: '仅下载视频中的音频轨道.', diff --git a/registry/lib/components/video/download/apis/flv.ts b/registry/lib/components/video/download/apis/flv.ts index 4363d4a8d..9b4719c5b 100644 --- a/registry/lib/components/video/download/apis/flv.ts +++ b/registry/lib/components/video/download/apis/flv.ts @@ -1,12 +1,15 @@ import { bilibiliApi, getJsonWithCredentials } from '@/core/ajax' -import { formData } from '@/core/utils' +import { formData, matchUrlPattern } from '@/core/utils' import { allQualities } from '@/components/video/video-quality' +import { bangumiUrls } from '@/core/utils/urls' import { compareQuality } from '../error' import { DownloadVideoApi, DownloadVideoFragment, DownloadVideoInfo, + DownloadVideoInputItem, } from '../types' +import { bangumiApi, videoApi } from './url' const parseInfoFromJson = (data: any, extensions: string[]) => { const getExtension = (index: number) => { @@ -32,33 +35,39 @@ const parseInfoFromJson = (data: any, extensions: string[]) => { currentQuality, } } + /* spell-checker: disable */ +const downloadFlv = async ( + input: DownloadVideoInputItem, +) => { + const { aid, cid, quality } = input + const params = { + avid: aid, + cid, + qn: quality?.value ?? '', + otype: 'json', + fourk: 1, + fnver: 0, + fnval: 0, + } + const isBanugmi = bangumiUrls.some(url => matchUrlPattern(url)) + const api = isBanugmi ? bangumiApi(formData(params)) : videoApi(formData(params)) + const data = await bilibiliApi( + getJsonWithCredentials(api), + '获取视频链接失败', + ) + const info = new DownloadVideoInfo({ + input, + jsonData: data, + ...parseInfoFromJson(data, ['.flv']), + }) + compareQuality(input, info) + return info +} + export const videoFlv: DownloadVideoApi = { name: 'video.flv', displayName: 'flv', description: '使用 flv 格式下载, 兼容 H.264 编码.', - downloadVideoInfo: async input => { - const { aid, cid, quality } = input - const params = { - avid: aid, - cid, - qn: quality?.value ?? '', - otype: 'json', - fourk: 1, - fnver: 0, - fnval: 0, - } - const api = `https://api.bilibili.com/x/player/playurl?${formData(params)}` - const data = await bilibiliApi( - getJsonWithCredentials(api), - '获取视频链接失败', - ) - const info = new DownloadVideoInfo({ - input, - jsonData: data, - ...parseInfoFromJson(data, ['.flv']), - }) - compareQuality(input, info) - return info - }, + downloadVideoInfo: input => downloadFlv(input), } diff --git a/registry/lib/components/video/download/apis/url.ts b/registry/lib/components/video/download/apis/url.ts new file mode 100644 index 000000000..06d5d28cf --- /dev/null +++ b/registry/lib/components/video/download/apis/url.ts @@ -0,0 +1,2 @@ +export const videoApi = (params: string) => `https://api.bilibili.com/x/player/playurl?${params}` +export const bangumiApi = (params: string) => `https://api.bilibili.com/pgc/player/web/playurl?${params}` diff --git a/registry/lib/components/video/download/types.ts b/registry/lib/components/video/download/types.ts index 3f80b7110..3f26ef548 100644 --- a/registry/lib/components/video/download/types.ts +++ b/registry/lib/components/video/download/types.ts @@ -72,6 +72,8 @@ export class DownloadVideoInfo { export interface DownloadVideoApi extends WithName { downloadVideoInfo: (input: DownloadVideoInputItem) => Promise description?: string + /** 网址匹配规则 */ + match?: TestPattern } /** 表示下载时额外附带的产物, 如弹幕 / 字幕等 */ export interface DownloadVideoAssets extends VueInstanceInput, WithName { diff --git a/src/components/video/watchlater.ts b/src/components/video/watchlater.ts index c839f0405..6a73a0688 100644 --- a/src/components/video/watchlater.ts +++ b/src/components/video/watchlater.ts @@ -88,6 +88,11 @@ export async function getWatchlaterList(): Promise export async function getWatchlaterList(raw: true): Promise export async function getWatchlaterList(raw: false): Promise export async function getWatchlaterList(raw = false): Promise { + const { getUID } = await import('@/core/utils') + if (!getUID()) { + console.warn('[稍后再看列表] 账号未登录') + return [] + } const api = 'https://api.bilibili.com/x/v2/history/toview/web' const { getJsonWithCredentials } = await import('@/core/ajax') const response = await getJsonWithCredentials(api) diff --git a/src/core/ajax.ts b/src/core/ajax.ts index 3086abf28..400f367d8 100644 --- a/src/core/ajax.ts +++ b/src/core/ajax.ts @@ -234,6 +234,7 @@ export interface BilibiliApiResponse { msg?: string ttl: number data: any + result?: any } /** * 进行 bilibili API 标准响应处理 @@ -252,5 +253,5 @@ export const bilibiliApi = async ( logError(error) throw error } - return (json.data || {}) as T + return (json.data || json.result || {}) as T }