diff --git a/src/app/private-library/page.tsx b/src/app/private-library/page.tsx index d006d30..f39267a 100644 --- a/src/app/private-library/page.tsx +++ b/src/app/private-library/page.tsx @@ -75,6 +75,7 @@ export default function PrivateLibraryPage() { const pageSize = 20; const observerTarget = useRef(null); const isFetchingRef = useRef(false); + const abortControllerRef = useRef(null); const scrollContainerRef = useRef(null); const embyScrollContainerRef = useRef(null); const isDraggingRef = useRef(false); @@ -160,6 +161,8 @@ export default function PrivateLibraryPage() { setHasMore(true); setError(''); setSelectedView('all'); + setLoading(false); + setLoadingMore(false); isFetchingRef.current = false; }, [sourceType, embyKey]); @@ -171,6 +174,8 @@ export default function PrivateLibraryPage() { setVideos([]); setHasMore(true); setError(''); + setLoading(false); + setLoadingMore(false); isFetchingRef.current = false; }, [selectedView]); @@ -191,13 +196,15 @@ export default function PrivateLibraryPage() { } else { setEmbyViews(data.views || []); - // 分类加载完成后,检查URL中是否有view参数 - const urlView = searchParams.get('view'); - if (urlView && data.views && data.views.length > 0) { - // 检查该view是否存在于分类列表中 - const viewExists = data.views.some((v: EmbyView) => v.id === urlView); - if (viewExists) { - setSelectedView(urlView); + // 分类加载完成后,检查URL中是否有view参数(仅在初始化时) + if (!isInitializedRef.current) { + const urlView = searchParams.get('view'); + if (urlView && data.views && data.views.length > 0) { + // 检查该view是否存在于分类列表中 + const viewExists = data.views.some((v: EmbyView) => v.id === urlView); + if (viewExists) { + setSelectedView(urlView); + } } } } @@ -210,7 +217,7 @@ export default function PrivateLibraryPage() { }; fetchEmbyViews(); - }, [sourceType, embyKey, searchParams]); + }, [sourceType, embyKey]); // 鼠标拖动滚动 const handleMouseDown = (e: React.MouseEvent) => { @@ -249,9 +256,9 @@ export default function PrivateLibraryPage() { const fetchVideos = async () => { const isInitial = page === 1; - // 防止重复请求 - if (isFetchingRef.current) { - return; + // 取消之前的请求 + if (abortControllerRef.current) { + abortControllerRef.current.abort(); } // 如果选择了 openlist 但未配置,不发起请求 @@ -266,6 +273,9 @@ export default function PrivateLibraryPage() { return; } + // 创建新的 AbortController + const abortController = new AbortController(); + abortControllerRef.current = abortController; isFetchingRef.current = true; try { @@ -280,7 +290,7 @@ export default function PrivateLibraryPage() { ? `/api/openlist/list?page=${page}&pageSize=${pageSize}` : `/api/emby/list?page=${page}&pageSize=${pageSize}${selectedView !== 'all' ? `&parentId=${selectedView}` : ''}&embyKey=${embyKey}`; - const response = await fetch(endpoint); + const response = await fetch(endpoint, { signal: abortController.signal }); if (!response.ok) { throw new Error('获取视频列表失败'); @@ -308,23 +318,37 @@ export default function PrivateLibraryPage() { const hasMoreData = currentPage < totalPages; setHasMore(hasMoreData); } - } catch (err) { + } catch (err: any) { + // 忽略取消请求的错误 + if (err.name === 'AbortError') { + return; + } console.error('获取视频列表失败:', err); setError('获取视频列表失败'); if (isInitial) { setVideos([]); } } finally { - if (isInitial) { - setLoading(false); - } else { - setLoadingMore(false); + // 只有当这个请求没有被取消时才更新状态 + if (!abortController.signal.aborted) { + if (isInitial) { + setLoading(false); + } else { + setLoadingMore(false); + } + isFetchingRef.current = false; } - isFetchingRef.current = false; } }; fetchVideos(); + + // 清理函数:组件卸载时取消请求 + return () => { + if (abortControllerRef.current) { + abortControllerRef.current.abort(); + } + }; }, [sourceType, embyKey, page, selectedView, runtimeConfig]); const handleVideoClick = (video: Video) => { @@ -380,33 +404,22 @@ export default function PrivateLibraryPage() { {/* 第一级:源类型选择(OpenList / Emby) */}
-
- - -
+ setSourceType(value as LibrarySourceType)} + />
{/* 第二级:Emby源选择(仅当选择Emby且有多个源时显示) */} {sourceType === 'emby' && embySourceOptions.length > 1 && (
+
+ 服务 +
+
+ 分类 +
{loadingViews ? (