diff --git a/crates/bili_sync/src/api/response.rs b/crates/bili_sync/src/api/response.rs index 0dc9a77..ba1b4f4 100644 --- a/crates/bili_sync/src/api/response.rs +++ b/crates/bili_sync/src/api/response.rs @@ -77,6 +77,10 @@ pub struct VideoInfo { pub should_download: bool, #[serde(serialize_with = "serde_video_download_status")] pub download_status: u32, + pub collection_id: Option, + pub favorite_id: Option, + pub submission_id: Option, + pub watch_later_id: Option, } #[derive(Serialize, DerivePartialModel, FromQueryResult)] diff --git a/crates/bili_sync/src/api/routes/videos/mod.rs b/crates/bili_sync/src/api/routes/videos/mod.rs index 687832b..2aa5144 100644 --- a/crates/bili_sync/src/api/routes/videos/mod.rs +++ b/crates/bili_sync/src/api/routes/videos/mod.rs @@ -200,6 +200,10 @@ pub async fn clear_and_reset_video_status( valid: video_info.valid, should_download: video_info.should_download, download_status: video_info.download_status, + collection_id: video_info.collection_id, + favorite_id: video_info.favorite_id, + submission_id: video_info.submission_id, + watch_later_id: video_info.watch_later_id, }, })) } diff --git a/web/src/lib/components/video-card.svelte b/web/src/lib/components/video-card.svelte index b679383..7714c64 100644 --- a/web/src/lib/components/video-card.svelte +++ b/web/src/lib/components/video-card.svelte @@ -13,13 +13,17 @@ BrushCleaningIcon, UserIcon, SquareArrowOutUpRightIcon, - EllipsisIcon + EllipsisIcon, + HeartIcon, + FolderIcon, + ClockIcon } from '@lucide/svelte/icons'; import { goto } from '$app/navigation'; import * as Tooltip from '$lib/components/ui/tooltip/index.js'; // 将 bvid 设置为可选属性,但保留 VideoInfo 的其它所有属性 export let video: Omit & { bvid?: string }; + export let source: { type: string; name: string } | null = null; // 视频源信息 export let showActions: boolean = true; // 控制是否显示操作按钮 export let mode: 'default' | 'detail' | 'page' = 'default'; // 卡片模式 export let customTitle: string = ''; // 自定义标题 @@ -132,8 +136,8 @@ - -
+ +
+ + {#if source.type === 'favorite'} + + {:else if source.type === 'collection'} + + {:else if source.type === 'submission'} + + {:else if source.type === 'watch_later'} + + {/if} + + {source.name} + + +
+ {/if}
| null = null; + let sourceMap: SvelteMap = new SvelteMap(); function getApiParams(searchParams: URLSearchParams) { let videoSource = null; @@ -246,6 +250,22 @@ } } + function getVideoSource(video: VideoInfo): { type: string; name: string } | null { + if (video.collection_id != null) { + return sourceMap.get(`collection:${video.collection_id}`) || null; + } + if (video.favorite_id != null) { + return sourceMap.get(`favorite:${video.favorite_id}`) || null; + } + if (video.submission_id != null) { + return sourceMap.get(`submission:${video.submission_id}`) || null; + } + if (video.watch_later_id != null) { + return sourceMap.get(`watch_later:${video.watch_later_id}`) || null; + } + return null; + } + // 获取筛选条件的显示数组 function getFilterDescriptionParts(): string[] { const state = $appStateStore; @@ -284,7 +304,7 @@ return parts; } - $: if ($page.url.search !== lastSearch) { + $: if (videoSourcesLoaded && $page.url.search !== lastSearch) { lastSearch = $page.url.search; handleSearchParamsChange($page.url.searchParams); } @@ -304,8 +324,19 @@ } ]) ); + sourceMap.clear(); + for (const source of Object.values(VIDEO_SOURCES)) { + const sourceList = videoSources[source.type as keyof VideoSourcesResponse] as VideoSource[]; + for (const item of sourceList) { + sourceMap.set(`${source.type}:${item.id}`, { + type: source.type, + name: item.name + }); + } + } } else { filters = null; + sourceMap.clear(); } onMount(async () => { @@ -315,6 +346,7 @@ } ]); videoSources = (await api.getVideoSources()).data; + videoSourcesLoaded = true; }); $: totalPages = videosData ? Math.ceil(videosData.total_count / pageSize) : 0; @@ -435,6 +467,7 @@ {#each videosData.videos as video (video.id)} { await handleResetVideo(video.id, forceReset); }}