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 @@
+
+
- FavPane
+
+
+
+
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)