From dd96a32b354b798c5e07dbfe5ee69a683c615c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=80=E1=B4=8D=E1=B4=9B=E1=B4=8F=E1=B4=80=E1=B4=87?= =?UTF-8?q?=CA=80?= Date: Sun, 15 Mar 2026 21:53:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9C=A8=E8=A7=86=E9=A2=91=E9=A1=B5?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E8=A7=86=E9=A2=91=E5=B1=9E=E4=BA=8E=E5=93=AA?= =?UTF-8?q?=E4=B8=AA=E8=A7=86=E9=A2=91=E6=BA=90=20(#676)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/bili_sync/src/api/response.rs | 4 ++ crates/bili_sync/src/api/routes/videos/mod.rs | 4 ++ web/src/lib/components/video-card.svelte | 28 ++++++++++++-- web/src/lib/types.ts | 4 ++ web/src/routes/videos/+page.svelte | 37 ++++++++++++++++++- 5 files changed, 72 insertions(+), 5 deletions(-) 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); }}