'use client'; import { Blend, Loader2 } from 'lucide-react'; import { useRouter, useSearchParams } from 'next/navigation'; import { useEffect, useRef, useState } from 'react'; import { SearchResult } from '@/lib/types'; import CapsuleSwitch from '@/components/CapsuleSwitch'; import PageLayout from '@/components/PageLayout'; import VideoCard from '@/components/VideoCard'; interface ScriptSourceOption { key: string; name: string; description?: string; } export default function AdvancedRecommendationPage() { const router = useRouter(); const searchParams = useSearchParams(); const loadMoreRef = useRef(null); const initialUrlSourceRef = useRef(searchParams.get('source') || ''); const [sources, setSources] = useState([]); const [selectedSource, setSelectedSource] = useState(''); const [videos, setVideos] = useState([]); const [isLoadingSources, setIsLoadingSources] = useState(true); const [isLoadingVideos, setIsLoadingVideos] = useState(false); const [error, setError] = useState(''); const [page, setPage] = useState(1); const [hasMore, setHasMore] = useState(true); const initializedRef = useRef(false); const hasSyncedUrlRef = useRef(false); useEffect(() => { const fetchSources = async () => { setIsLoadingSources(true); try { const response = await fetch('/api/advanced-recommendation/sources'); const data = await response.json(); if (!response.ok) { throw new Error(data.error || '获取脚本源失败'); } const nextSources: ScriptSourceOption[] = Array.isArray(data.sources) ? data.sources : []; setSources(nextSources); const initialSource = nextSources.find((item) => item.key === initialUrlSourceRef.current) ?.key || nextSources[0]?.key || ''; setSelectedSource(initialSource); } catch (err) { setError(err instanceof Error ? err.message : '获取脚本源失败'); } finally { setIsLoadingSources(false); initializedRef.current = true; } }; fetchSources(); }, []); useEffect(() => { if (!initializedRef.current || !selectedSource) return; if (!hasSyncedUrlRef.current) { hasSyncedUrlRef.current = true; if (initialUrlSourceRef.current === selectedSource) return; } const params = new URLSearchParams(); params.set('source', selectedSource); router.replace(`/advanced-recommendation?${params.toString()}`, { scroll: false, }); }, [selectedSource, router]); useEffect(() => { if (!selectedSource) return; setVideos([]); setPage(1); setHasMore(true); setError(''); }, [selectedSource]); useEffect(() => { if (!selectedSource) return; const fetchVideos = async () => { setIsLoadingVideos(true); try { const response = await fetch( `/api/advanced-recommendation/videos?source=${encodeURIComponent(selectedSource)}&page=${page}` ); const data = await response.json(); if (!response.ok) { throw new Error(data.error || '获取推荐失败'); } const nextResults = Array.isArray(data.results) ? data.results : []; setVideos((prev) => (page === 1 ? nextResults : [...prev, ...nextResults])); setHasMore(Number(data.page || page) < Number(data.pageCount || 1)); } catch (err) { setError(err instanceof Error ? err.message : '获取推荐失败'); setHasMore(false); } finally { setIsLoadingVideos(false); } }; fetchVideos(); }, [selectedSource, page]); useEffect(() => { if (!loadMoreRef.current || !hasMore || isLoadingVideos || !!error) return; const observer = new IntersectionObserver( (entries) => { if (entries[0]?.isIntersecting) { setPage((prev) => prev + 1); } }, { threshold: 0.1 } ); observer.observe(loadMoreRef.current); return () => observer.disconnect(); }, [error, hasMore, isLoadingVideos]); return (

高级推荐

浏览视频源脚本提供的推荐内容

{isLoadingSources ? (
加载脚本源中...
) : sources.length === 0 ? (
暂无可用的视频源脚本
) : (
({ label: item.name, value: item.key, }))} active={selectedSource} onChange={setSelectedSource} />
)}
{!!error && (
{error}
)} {!isLoadingSources && sources.length > 0 && ( <> {videos.length > 0 ? (
{videos.map((video, index) => ( ))}
) : !isLoadingVideos && !error ? (
当前脚本暂无推荐内容
) : null} {isLoadingVideos && (
)}
)}
); }