修复emby分类加载旧数据
This commit is contained in:
@@ -75,6 +75,7 @@ export default function PrivateLibraryPage() {
|
|||||||
const pageSize = 20;
|
const pageSize = 20;
|
||||||
const observerTarget = useRef<HTMLDivElement>(null);
|
const observerTarget = useRef<HTMLDivElement>(null);
|
||||||
const isFetchingRef = useRef(false);
|
const isFetchingRef = useRef(false);
|
||||||
|
const abortControllerRef = useRef<AbortController | null>(null);
|
||||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const embyScrollContainerRef = useRef<HTMLDivElement>(null);
|
const embyScrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const isDraggingRef = useRef(false);
|
const isDraggingRef = useRef(false);
|
||||||
@@ -160,6 +161,8 @@ export default function PrivateLibraryPage() {
|
|||||||
setHasMore(true);
|
setHasMore(true);
|
||||||
setError('');
|
setError('');
|
||||||
setSelectedView('all');
|
setSelectedView('all');
|
||||||
|
setLoading(false);
|
||||||
|
setLoadingMore(false);
|
||||||
isFetchingRef.current = false;
|
isFetchingRef.current = false;
|
||||||
}, [sourceType, embyKey]);
|
}, [sourceType, embyKey]);
|
||||||
|
|
||||||
@@ -171,6 +174,8 @@ export default function PrivateLibraryPage() {
|
|||||||
setVideos([]);
|
setVideos([]);
|
||||||
setHasMore(true);
|
setHasMore(true);
|
||||||
setError('');
|
setError('');
|
||||||
|
setLoading(false);
|
||||||
|
setLoadingMore(false);
|
||||||
isFetchingRef.current = false;
|
isFetchingRef.current = false;
|
||||||
}, [selectedView]);
|
}, [selectedView]);
|
||||||
|
|
||||||
@@ -191,13 +196,15 @@ export default function PrivateLibraryPage() {
|
|||||||
} else {
|
} else {
|
||||||
setEmbyViews(data.views || []);
|
setEmbyViews(data.views || []);
|
||||||
|
|
||||||
// 分类加载完成后,检查URL中是否有view参数
|
// 分类加载完成后,检查URL中是否有view参数(仅在初始化时)
|
||||||
const urlView = searchParams.get('view');
|
if (!isInitializedRef.current) {
|
||||||
if (urlView && data.views && data.views.length > 0) {
|
const urlView = searchParams.get('view');
|
||||||
// 检查该view是否存在于分类列表中
|
if (urlView && data.views && data.views.length > 0) {
|
||||||
const viewExists = data.views.some((v: EmbyView) => v.id === urlView);
|
// 检查该view是否存在于分类列表中
|
||||||
if (viewExists) {
|
const viewExists = data.views.some((v: EmbyView) => v.id === urlView);
|
||||||
setSelectedView(urlView);
|
if (viewExists) {
|
||||||
|
setSelectedView(urlView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,7 +217,7 @@ export default function PrivateLibraryPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fetchEmbyViews();
|
fetchEmbyViews();
|
||||||
}, [sourceType, embyKey, searchParams]);
|
}, [sourceType, embyKey]);
|
||||||
|
|
||||||
// 鼠标拖动滚动
|
// 鼠标拖动滚动
|
||||||
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
|
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
@@ -249,9 +256,9 @@ export default function PrivateLibraryPage() {
|
|||||||
const fetchVideos = async () => {
|
const fetchVideos = async () => {
|
||||||
const isInitial = page === 1;
|
const isInitial = page === 1;
|
||||||
|
|
||||||
// 防止重复请求
|
// 取消之前的请求
|
||||||
if (isFetchingRef.current) {
|
if (abortControllerRef.current) {
|
||||||
return;
|
abortControllerRef.current.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果选择了 openlist 但未配置,不发起请求
|
// 如果选择了 openlist 但未配置,不发起请求
|
||||||
@@ -266,6 +273,9 @@ export default function PrivateLibraryPage() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建新的 AbortController
|
||||||
|
const abortController = new AbortController();
|
||||||
|
abortControllerRef.current = abortController;
|
||||||
isFetchingRef.current = true;
|
isFetchingRef.current = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -280,7 +290,7 @@ export default function PrivateLibraryPage() {
|
|||||||
? `/api/openlist/list?page=${page}&pageSize=${pageSize}`
|
? `/api/openlist/list?page=${page}&pageSize=${pageSize}`
|
||||||
: `/api/emby/list?page=${page}&pageSize=${pageSize}${selectedView !== 'all' ? `&parentId=${selectedView}` : ''}&embyKey=${embyKey}`;
|
: `/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) {
|
if (!response.ok) {
|
||||||
throw new Error('获取视频列表失败');
|
throw new Error('获取视频列表失败');
|
||||||
@@ -308,23 +318,37 @@ export default function PrivateLibraryPage() {
|
|||||||
const hasMoreData = currentPage < totalPages;
|
const hasMoreData = currentPage < totalPages;
|
||||||
setHasMore(hasMoreData);
|
setHasMore(hasMoreData);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
|
// 忽略取消请求的错误
|
||||||
|
if (err.name === 'AbortError') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.error('获取视频列表失败:', err);
|
console.error('获取视频列表失败:', err);
|
||||||
setError('获取视频列表失败');
|
setError('获取视频列表失败');
|
||||||
if (isInitial) {
|
if (isInitial) {
|
||||||
setVideos([]);
|
setVideos([]);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (isInitial) {
|
// 只有当这个请求没有被取消时才更新状态
|
||||||
setLoading(false);
|
if (!abortController.signal.aborted) {
|
||||||
} else {
|
if (isInitial) {
|
||||||
setLoadingMore(false);
|
setLoading(false);
|
||||||
|
} else {
|
||||||
|
setLoadingMore(false);
|
||||||
|
}
|
||||||
|
isFetchingRef.current = false;
|
||||||
}
|
}
|
||||||
isFetchingRef.current = false;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchVideos();
|
fetchVideos();
|
||||||
|
|
||||||
|
// 清理函数:组件卸载时取消请求
|
||||||
|
return () => {
|
||||||
|
if (abortControllerRef.current) {
|
||||||
|
abortControllerRef.current.abort();
|
||||||
|
}
|
||||||
|
};
|
||||||
}, [sourceType, embyKey, page, selectedView, runtimeConfig]);
|
}, [sourceType, embyKey, page, selectedView, runtimeConfig]);
|
||||||
|
|
||||||
const handleVideoClick = (video: Video) => {
|
const handleVideoClick = (video: Video) => {
|
||||||
@@ -380,33 +404,22 @@ export default function PrivateLibraryPage() {
|
|||||||
|
|
||||||
{/* 第一级:源类型选择(OpenList / Emby) */}
|
{/* 第一级:源类型选择(OpenList / Emby) */}
|
||||||
<div className='mb-6 flex justify-center'>
|
<div className='mb-6 flex justify-center'>
|
||||||
<div className='inline-flex gap-2 bg-gray-100 dark:bg-gray-800 rounded-lg p-1'>
|
<CapsuleSwitch
|
||||||
<button
|
options={[
|
||||||
onClick={() => setSourceType('openlist')}
|
{ label: 'OpenList', value: 'openlist' },
|
||||||
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
|
{ label: 'Emby', value: 'emby' },
|
||||||
sourceType === 'openlist'
|
]}
|
||||||
? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow'
|
active={sourceType}
|
||||||
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
|
onChange={(value) => setSourceType(value as LibrarySourceType)}
|
||||||
}`}
|
/>
|
||||||
>
|
|
||||||
OpenList
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => setSourceType('emby')}
|
|
||||||
className={`px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
|
|
||||||
sourceType === 'emby'
|
|
||||||
? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow'
|
|
||||||
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
Emby
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 第二级:Emby源选择(仅当选择Emby且有多个源时显示) */}
|
{/* 第二级:Emby源选择(仅当选择Emby且有多个源时显示) */}
|
||||||
{sourceType === 'emby' && embySourceOptions.length > 1 && (
|
{sourceType === 'emby' && embySourceOptions.length > 1 && (
|
||||||
<div className='mb-6'>
|
<div className='mb-6'>
|
||||||
|
<div className='text-xs text-gray-500 dark:text-gray-400 mb-2 px-4'>
|
||||||
|
服务
|
||||||
|
</div>
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<div
|
<div
|
||||||
ref={embyScrollContainerRef}
|
ref={embyScrollContainerRef}
|
||||||
@@ -462,6 +475,9 @@ export default function PrivateLibraryPage() {
|
|||||||
{/* 第三级:Emby 媒体库分类选择器 */}
|
{/* 第三级:Emby 媒体库分类选择器 */}
|
||||||
{sourceType === 'emby' && (
|
{sourceType === 'emby' && (
|
||||||
<div className='mb-6'>
|
<div className='mb-6'>
|
||||||
|
<div className='text-xs text-gray-500 dark:text-gray-400 mb-2 px-4'>
|
||||||
|
分类
|
||||||
|
</div>
|
||||||
{loadingViews ? (
|
{loadingViews ? (
|
||||||
<div className='flex justify-center'>
|
<div className='flex justify-center'>
|
||||||
<div className='w-5 h-5 border-2 border-blue-600 border-t-transparent rounded-full animate-spin' />
|
<div className='w-5 h-5 border-2 border-blue-600 border-t-transparent rounded-full animate-spin' />
|
||||||
|
|||||||
Reference in New Issue
Block a user