diff --git a/client/src/work/data.ts b/client/src/work/data.ts index 9233dad..29ddfe0 100644 --- a/client/src/work/data.ts +++ b/client/src/work/data.ts @@ -1,5 +1,5 @@ import { ResJSON, timeoutController } from '../mixin' -import { PlayInfo, SeasonInfo, TaskInitData, VideoInfo } from './type' +import { FavList, PlayInfo, SeasonInfo, TaskInitData, VideoInfo } from './type' /** * 获取视频信息 @@ -75,4 +75,14 @@ export const getRedirectedLocation = async (url: string): Promise => { if (!data.success) throw new Error(data.message) return data.data }) +} + +/** 获取收藏夹内视频列表 */ +export const getFavList = async (mediaId: number): Promise => { + return fetch(`/api/getFavList?mediaId=${mediaId}`) + .then(res => res.json()) + .then((body: ResJSON) => { + if (!body.success) throw new Error(body.message) + return body.data + }) } \ No newline at end of file diff --git a/client/src/work/index.ts b/client/src/work/index.ts index f3a2cd9..97f4ab4 100644 --- a/client/src/work/index.ts +++ b/client/src/work/index.ts @@ -96,7 +96,8 @@ export class WorkRoute { value = popularBvids[Math.floor(Math.random() * popularBvids.length)] } if (idType == 'bv' && !value.match(/^BV1[a-zA-Z0-9]+$/)) return goto('work') - if ((idType == 'ep' || idType == 'ss') && !value.match(/^\d+$/)) return goto('work') + if ((idType == 'ep' || idType == 'ss' || idType == 'fav') + && !value.match(/^\d+$/)) return goto('work') if (idType == 'bv' && !_that.isInitPopular.val) _that.urlValue.val = value else if (idType == 'ep' || idType == 'ss') _that.urlValue.val = `${idType}${value}` start(_that, { diff --git a/client/src/work/mixin.ts b/client/src/work/mixin.ts index 2b1d142..43f2fc8 100644 --- a/client/src/work/mixin.ts +++ b/client/src/work/mixin.ts @@ -1,7 +1,7 @@ -import { getRedirectedLocation, getSeasonInfo, getVideoInfo } from './data' +import { getFavList, getRedirectedLocation, getSeasonInfo, getVideoInfo } from './data' import { WorkRoute } from '.' import van from 'vanjs-core' -import { Episode, PageInParseResult } from './type' +import { Episode, PageInParseResult, VideoParseResult } from './type' import { ResJSON } from '../mixin' /** 点击按钮开始解析 */ @@ -90,6 +90,36 @@ export const start = async ( } workRoute.videoInfoCardMode.val = 'season' }) + } else if (option.idType == 'fav') { + const mediaId = option.value as number + await getFavList(mediaId).then(favList => { + workRoute.videoInfocardData.val = { + areas: [], + cover: favList[0].cover, + description: favList[0].intro, + dimension: { height: 0, width: 0, rotate: 0 }, + duration: favList[0].duration, + owner: favList[0].upper, + pages: favList.map((info, index) => ({ + bandge: (index + 1).toString(), + selected: van.state(index == 0), + bvid: info.bvid, + cid: info.ugc.first_cid, + dimension: { height: 0, width: 0, rotate: 0 }, + duration: info.duration, + page: index, + part: info.title, + })), + publishData: new Date(favList[0].pubtime * 1000).toLocaleString(), + section: [], + staff: [], + status: '', + styles: [], + targetURL: `https://www.bilibili.com/video/${favList[0].bvid}`, + title: favList[0].title + } + workRoute.videoInfoCardMode.val = 'video' + }) } } @@ -106,7 +136,7 @@ const episodeToPage = (episode: Episode, index: number): PageInParseResult => { } } -export type IDType = 'bv' | 'ep' | 'ss' +export type IDType = 'bv' | 'ep' | 'ss' | 'fav' /** * 校验用户输入的待解析的视频链接 @@ -123,6 +153,15 @@ export const checkURL = (url: string): { const matchSeason = url.match(/^(?:https?:\/\/www\.bilibili\.com\/bangumi\/play\/)?(ep|ss)(\d+)/) if (matchSeason) return { type: matchSeason[1] as 'ep' | 'ss', value: parseInt(matchSeason[2]) } + try { + const _url = new URL(url) + const mediaId = parseInt(_url.searchParams.get('fid') || '') + if (_url.hostname == 'space.bilibili.com' && _url.pathname.match(/^\/\d+\/favlist$/) && !isNaN(mediaId)) { + return { type: 'fav', value: mediaId } + } + const mlMatch = url.match(/^https:\/\/www.bilibili.com\/medialist\/detail\/ml(\d+)/) + if (mlMatch) return { type: 'fav', value: mlMatch[1] } + } catch { } throw new Error('您输入的视频链接格式错误') } diff --git a/client/src/work/type.ts b/client/src/work/type.ts index 39ffac0..5357069 100644 --- a/client/src/work/type.ts +++ b/client/src/work/type.ts @@ -254,4 +254,23 @@ export type TaskInDB = TaskInitData & { status: TaskStatus } -export type TaskStatus = 'done' | 'waiting' | 'running' | 'error' \ No newline at end of file +export type TaskStatus = 'done' | 'waiting' | 'running' | 'error' + +export type FavList = FavListItem[] + +export type FavListItem = { + title: string + cover: string + intro: string + duration: number + upper: { + mid: number + name: string + face: string + } + pubtime: number + bvid: string + ugc: { + first_cid: number + } +} \ No newline at end of file diff --git a/client/src/work/view/inputBox.ts b/client/src/work/view/inputBox.ts index db6dc23..8ed6cfc 100644 --- a/client/src/work/view/inputBox.ts +++ b/client/src/work/view/inputBox.ts @@ -57,7 +57,7 @@ const ParseButton = (parent: InputBoxComp, large: boolean, id: string = '') => { } const { type, value } = checkURL(workRoute.urlValue.val) workRoute.urlInvalid.val = false - start(workRoute, { + await start(workRoute, { idType: type, value, from: 'click' diff --git a/server/bilibili/type.go b/server/bilibili/type.go index d39b258..882fb51 100644 --- a/server/bilibili/type.go +++ b/server/bilibili/type.go @@ -247,5 +247,7 @@ type FavList []struct { } `json:"upper"` PubTime int `json:"pubtime"` Bvid string `json:"bvid"` - Aid int `json:"id"` + Ugc struct { + FirstCid int `json:"first_cid"` + } `json:"ugc"` }