轮播图数据源增加豆瓣
This commit is contained in:
@@ -5,6 +5,7 @@ import Image from 'next/image';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { getTMDBImageUrl, getGenreNames, type TMDBItem } from '@/lib/tmdb.client';
|
||||
import { ChevronLeft, ChevronRight, Play } from 'lucide-react';
|
||||
import { processImageUrl, processVideoUrl } from '@/lib/utils';
|
||||
|
||||
interface BannerCarouselProps {
|
||||
autoPlayInterval?: number; // 自动播放间隔(毫秒)
|
||||
@@ -14,6 +15,8 @@ interface BannerCarouselProps {
|
||||
interface BannerItem extends TMDBItem {
|
||||
subtitle?: string; // TX数据源的子标题
|
||||
tags?: string[]; // TX数据源的标签
|
||||
trailer_url?: string | null; // 豆瓣预告片直链
|
||||
genres?: string[]; // 豆瓣数据源的类型标签
|
||||
}
|
||||
|
||||
export default function BannerCarousel({ autoPlayInterval = 5000 }: BannerCarouselProps) {
|
||||
@@ -25,6 +28,7 @@ export default function BannerCarousel({ autoPlayInterval = 5000 }: BannerCarous
|
||||
const [skipNextAutoPlay, setSkipNextAutoPlay] = useState(false); // 跳过下一次自动播放
|
||||
const [isYouTubeAccessible, setIsYouTubeAccessible] = useState(false); // YouTube连通性(默认false,检查后再决定)
|
||||
const [enableTrailers, setEnableTrailers] = useState(false); // 是否启用预告片(默认关闭)
|
||||
const [dataSource, setDataSource] = useState<string>(''); // 当前数据源
|
||||
const touchStartX = useRef(0);
|
||||
const touchEndX = useRef(0);
|
||||
const isManualChange = useRef(false); // 标记是否为手动切换
|
||||
@@ -45,14 +49,29 @@ export default function BannerCarousel({ autoPlayInterval = 5000 }: BannerCarous
|
||||
// 获取图片URL(处理TX完整URL和TMDB路径)
|
||||
const getImageUrl = (path: string | null) => {
|
||||
if (!path) return '';
|
||||
// 如果是完整URL(TX数据源),直接返回
|
||||
// 如果是完整URL(TX数据源或豆瓣),需要判断是否需要代理
|
||||
if (path.startsWith('http://') || path.startsWith('https://')) {
|
||||
// 豆瓣图片需要通过代理
|
||||
if (path.includes('doubanio.com')) {
|
||||
return processImageUrl(path);
|
||||
}
|
||||
// TX等其他完整URL直接返回
|
||||
return path;
|
||||
}
|
||||
// 否则使用TMDB的URL拼接
|
||||
return getTMDBImageUrl(path, 'original');
|
||||
};
|
||||
|
||||
// 获取视频URL(处理豆瓣视频代理)
|
||||
const getVideoUrl = (url: string | null) => {
|
||||
if (!url) return null;
|
||||
// 豆瓣视频需要通过域名替换代理
|
||||
if (url.includes('doubanio.com')) {
|
||||
return processVideoUrl(url);
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
// 读取本地设置
|
||||
useEffect(() => {
|
||||
const setting = localStorage.getItem('enableTrailers');
|
||||
@@ -61,10 +80,10 @@ export default function BannerCarousel({ autoPlayInterval = 5000 }: BannerCarous
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 检测YouTube连通性 - 仅在启用预告片时检测
|
||||
// 检测YouTube连通性 - 仅在启用预告片且数据源为TMDB时检测
|
||||
useEffect(() => {
|
||||
// 如果未启用预告片,不进行检测
|
||||
if (!enableTrailers) {
|
||||
// 如果未启用预告片或数据源不是TMDB,不进行检测
|
||||
if (!enableTrailers || dataSource !== 'TMDB') {
|
||||
setIsYouTubeAccessible(false);
|
||||
return;
|
||||
}
|
||||
@@ -91,14 +110,14 @@ export default function BannerCarousel({ autoPlayInterval = 5000 }: BannerCarous
|
||||
};
|
||||
|
||||
checkYouTubeAccess();
|
||||
}, [enableTrailers]);
|
||||
}, [enableTrailers, dataSource]);
|
||||
|
||||
// 获取热门内容
|
||||
useEffect(() => {
|
||||
const fetchTrending = async () => {
|
||||
try {
|
||||
// 先尝试从所有可能的数据源缓存中读取
|
||||
const sources = ['TMDB', 'TX'];
|
||||
const sources = ['TMDB', 'TX', 'Douban'];
|
||||
let cachedData = null;
|
||||
let validSource = null;
|
||||
|
||||
@@ -126,6 +145,7 @@ export default function BannerCarousel({ autoPlayInterval = 5000 }: BannerCarous
|
||||
// 如果有有效的缓存,直接使用,不请求API
|
||||
if (cachedData) {
|
||||
setItems(cachedData);
|
||||
setDataSource(validSource || ''); // 设置数据源
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
@@ -139,6 +159,7 @@ export default function BannerCarousel({ autoPlayInterval = 5000 }: BannerCarous
|
||||
const cacheKey = getLocalStorageKey(dataSource);
|
||||
|
||||
setItems(result.list);
|
||||
setDataSource(dataSource); // 设置数据源
|
||||
|
||||
// 保存到 localStorage(使用数据源特定的key)
|
||||
try {
|
||||
@@ -285,7 +306,20 @@ export default function BannerCarousel({ autoPlayInterval = 5000 }: BannerCarous
|
||||
index === currentIndex ? 'opacity-100' : 'opacity-0'
|
||||
}`}
|
||||
>
|
||||
{item.video_key && isYouTubeAccessible && enableTrailers ? (
|
||||
{item.trailer_url && enableTrailers ? (
|
||||
/* 显示豆瓣直链视频 */
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<video
|
||||
src={getVideoUrl(item.trailer_url) || undefined}
|
||||
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 min-w-full min-h-full w-auto h-auto object-cover"
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
preload="metadata"
|
||||
/>
|
||||
</div>
|
||||
) : item.video_key && isYouTubeAccessible && enableTrailers ? (
|
||||
/* 显示YouTube视频 */
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<iframe
|
||||
@@ -333,13 +367,20 @@ export default function BannerCarousel({ autoPlayInterval = 5000 }: BannerCarous
|
||||
{currentItem.vote_average.toFixed(1)}
|
||||
</span>
|
||||
)}
|
||||
{/* 显示TX数据源的标签 */}
|
||||
{/* 显示标签:优先TX的tags,其次豆瓣的genres,最后TMDB的genre_ids */}
|
||||
{currentItem.tags && currentItem.tags.length > 0 ? (
|
||||
currentItem.tags.slice(0, 3).map((tag, index) => (
|
||||
<span key={index} className="px-2 py-1 bg-white/20 backdrop-blur-sm rounded text-sm">
|
||||
{tag}
|
||||
</span>
|
||||
))
|
||||
) : currentItem.genres && Array.isArray(currentItem.genres) && currentItem.genres.length > 0 ? (
|
||||
/* 显示豆瓣数据源的标签 */
|
||||
currentItem.genres.slice(0, 3).map((genre, index) => (
|
||||
<span key={index} className="px-2 py-1 bg-white/20 backdrop-blur-sm rounded text-sm">
|
||||
{genre}
|
||||
</span>
|
||||
))
|
||||
) : (
|
||||
/* 显示TMDB数据源的类型标签 */
|
||||
getGenreNames(currentItem.genre_ids, 3).map(genre => (
|
||||
|
||||
Reference in New Issue
Block a user