diff --git a/components.d.ts b/components.d.ts index 6e9eb42..266874d 100644 --- a/components.d.ts +++ b/components.d.ts @@ -20,6 +20,7 @@ declare module 'vue' { NDialogProvider: typeof import('naive-ui')['NDialogProvider'] NDropdown: typeof import('naive-ui')['NDropdown'] NEl: typeof import('naive-ui')['NEl'] + NEmpty: typeof import('naive-ui')['NEmpty'] NIcon: typeof import('naive-ui')['NIcon'] NInput: typeof import('naive-ui')['NInput'] NInputGroup: typeof import('naive-ui')['NInputGroup'] diff --git a/src/panes/FavPane/FavPane.vue b/src/panes/FavPane/FavPane.vue index 56ebaae..e089830 100644 --- a/src/panes/FavPane/FavPane.vue +++ b/src/panes/FavPane/FavPane.vue @@ -1,3 +1,41 @@ + + diff --git a/src/panes/FavPane/components/FavCard.vue b/src/panes/FavPane/components/FavCard.vue new file mode 100644 index 0000000..c0564ca --- /dev/null +++ b/src/panes/FavPane/components/FavCard.vue @@ -0,0 +1,151 @@ + + + diff --git a/src/panes/FavPane/components/FavPanel.vue b/src/panes/FavPane/components/FavPanel.vue new file mode 100644 index 0000000..8db720e --- /dev/null +++ b/src/panes/FavPane/components/FavPanel.vue @@ -0,0 +1,236 @@ + + + + + diff --git a/src/panes/SearchPane/SearchPane.vue b/src/panes/SearchPane/SearchPane.vue index 8f07dd7..8db024c 100644 --- a/src/panes/SearchPane/SearchPane.vue +++ b/src/panes/SearchPane/SearchPane.vue @@ -7,6 +7,7 @@ import { commands, GetBangumiInfoParams, GetCheeseInfoParams, + GetFavInfoParams, GetNormalInfoParams, GetUserVideoInfoParams, SearchParams, @@ -14,13 +15,14 @@ import { } from '../../bindings.ts' import NormalSeasonPanel from './components/NormalSeasonPanel.vue' import NormalSinglePanel from './components/NormalSinglePanel.vue' -import { extractBvid, extractAid, extractEpId, extractSeasonId, extractUid } from '../../utils.tsx' -import { useStore } from '../../store.ts' import BangumiPanel from './components/BangumiPanel.vue' import CheesePanel from './components/CheesePanel.vue' +import { extractBvid, extractAid, extractEpId, extractSeasonId, extractUid, extractMediaListId } from '../../utils.tsx' +import { useStore } from '../../store.ts' import UserVideoPanel from './components/UserVideoPanel.vue' +import FavPanel from '../FavPane/components/FavPanel.vue' -export type SearchType = 'Auto' | 'Normal' | 'Bangumi' | 'Cheese' | 'UserVideo' +export type SearchType = 'Auto' | 'Normal' | 'Bangumi' | 'Cheese' | 'UserVideo' | 'Fav' const searchTypeOptions: SelectProps['options'] = [ { label: '自动', value: 'Auto' }, @@ -28,6 +30,7 @@ const searchTypeOptions: SelectProps['options'] = [ { label: '番剧', value: 'Bangumi' }, { label: '课程', value: 'Cheese' }, { label: 'UP投稿', value: 'UserVideo' }, + { label: '收藏夹', value: 'Fav' }, ] const store = useStore() @@ -48,8 +51,10 @@ const searchLabel = computed(() => { return '链接 / ep... / ss...' } else if (searchTypeSelected.value === 'UserVideo') { return '个人空间链接 / uid...' + } else if (searchTypeSelected.value === 'Fav') { + return '收藏夹链接 / fid...' } - return '链接 / av... / BV... / ep... / ss... / uid...' + return '链接 / av... / BV... / ep... / ss... / uid... / fid...' }) async function search(input: string, searchType: SearchType) { @@ -74,6 +79,8 @@ async function search(input: string, searchType: SearchType) { await searchCheese(input, isUrl) } else if (searchType === 'UserVideo') { await searchUserVideo(input, isUrl) + } else if (searchType === 'Fav') { + await searchFav(input, isUrl) } else { message.error('未知的搜索类型') } @@ -89,6 +96,7 @@ async function searchAuto(input: string, isUrl: boolean) { const epId = extractEpId(input) const seasonId = extractSeasonId(input) const uid = extractUid(input) + const mediaListId = extractMediaListId(input) if (bvid !== undefined) { params = { Normal: { Bvid: bvid } } @@ -98,6 +106,8 @@ async function searchAuto(input: string, isUrl: boolean) { params = { Bangumi: { EpId: epId } } } else if (seasonId !== undefined) { params = { Bangumi: { SeasonId: seasonId } } + } else if (mediaListId !== undefined) { + params = { Fav: { media_list_id: mediaListId, pn: 1 } } } else if (uid !== undefined) { params = { UserVideo: { mid: uid, pn: 1 } } } @@ -123,6 +133,11 @@ async function searchAuto(input: string, isUrl: boolean) { if (!isNaN(uid)) { params = { UserVideo: { mid: uid, pn: 1 } } } + } else if (input.toLowerCase().startsWith('fid')) { + const mediaListId = parseInt(input.substring(3), 10) + if (!isNaN(mediaListId)) { + params = { Fav: { media_list_id: mediaListId, pn: 1 } } + } } if (params === undefined) { @@ -276,6 +291,39 @@ async function searchUserVideo(input: string, isUrl: boolean) { searchResult.value = result.data } +async function searchFav(input: string, isUrl: boolean) { + let params: GetFavInfoParams | undefined + + if (isUrl) { + const mediaListId = extractMediaListId(input) + if (mediaListId !== undefined) { + params = { media_list_id: mediaListId, pn: 1 } + } + } else if (input.toLowerCase().startsWith('fid')) { + const mediaListId = parseInt(input.substring(3), 10) + if (!isNaN(mediaListId)) { + params = { media_list_id: mediaListId, pn: 1 } + } + } else { + const mediaListId = parseInt(input, 10) + if (!isNaN(mediaListId)) { + params = { media_list_id: mediaListId, pn: 1 } + } + } + + if (params === undefined) { + message.error('解析输入失败,请输入正确的收藏夹链接或ID(如 fid...)') + return + } + + const result = await commands.search({ Fav: params }) + if (result.status === 'error') { + console.error(result.error) + return + } + searchResult.value = result.data +} + defineExpose({ search }) @@ -316,6 +364,7 @@ defineExpose({ search }) + diff --git a/src/utils.tsx b/src/utils.tsx index e521025..a046a12 100644 --- a/src/utils.tsx +++ b/src/utils.tsx @@ -73,6 +73,18 @@ export function extractUid(url: string): number | undefined { } } +export function extractMediaListId(url: string): number | undefined { + const parsedUrl = new URL(url) + const params = new URLSearchParams(parsedUrl.search) + const fid = params.get('fid') + if (fid !== null) { + const mediaListId = parseInt(fid, 10) + if (!isNaN(mediaListId)) { + return mediaListId + } + } +} + export function useEpisodeDropdown(onCheck: () => void, onUncheck: () => void, onSelectAll: () => void) { const dropdownX = ref(0) const dropdownY = ref(0)