feat: add play page douban link

This commit is contained in:
shinya
2025-08-06 19:36:18 +08:00
parent 06ed12bb3a
commit 87463f343c
7 changed files with 52 additions and 25 deletions

View File

@@ -1 +1 @@
20250806191001 20250806193618

View File

@@ -427,7 +427,7 @@ function DoubanPageClient() {
from='douban' from='douban'
title={item.title} title={item.title}
poster={item.poster} poster={item.poster}
douban_id={item.id} douban_id={Number(item.id)}
rate={item.rate} rate={item.rate}
year={item.year} year={item.year}
type={type === 'movie' ? 'movie' : ''} // 电影类型严格控制tv 不控 type={type === 'movie' ? 'movie' : ''} // 电影类型严格控制tv 不控

View File

@@ -251,7 +251,7 @@ function HomeClient() {
from='douban' from='douban'
title={movie.title} title={movie.title}
poster={movie.poster} poster={movie.poster}
douban_id={movie.id} douban_id={Number(movie.id)}
rate={movie.rate} rate={movie.rate}
year={movie.year} year={movie.year}
type='movie' type='movie'
@@ -299,7 +299,7 @@ function HomeClient() {
from='douban' from='douban'
title={show.title} title={show.title}
poster={show.poster} poster={show.poster}
douban_id={show.id} douban_id={Number(show.id)}
rate={show.rate} rate={show.rate}
year={show.year} year={show.year}
/> />
@@ -346,7 +346,7 @@ function HomeClient() {
from='douban' from='douban'
title={show.title} title={show.title}
poster={show.poster} poster={show.poster}
douban_id={show.id} douban_id={Number(show.id)}
rate={show.rate} rate={show.rate}
year={show.year} year={show.year}
/> />

View File

@@ -92,6 +92,7 @@ function PlayPageClient() {
const [videoTitle, setVideoTitle] = useState(searchParams.get('title') || ''); const [videoTitle, setVideoTitle] = useState(searchParams.get('title') || '');
const [videoYear, setVideoYear] = useState(searchParams.get('year') || ''); const [videoYear, setVideoYear] = useState(searchParams.get('year') || '');
const [videoCover, setVideoCover] = useState(''); const [videoCover, setVideoCover] = useState('');
const [videoDoubanId, setVideoDoubanId] = useState(0);
// 当前源和ID // 当前源和ID
const [currentSource, setCurrentSource] = useState( const [currentSource, setCurrentSource] = useState(
searchParams.get('source') || '' searchParams.get('source') || ''
@@ -715,6 +716,7 @@ function PlayPageClient() {
setVideoYear(detailData.year); setVideoYear(detailData.year);
setVideoTitle(detailData.title || videoTitleRef.current); setVideoTitle(detailData.title || videoTitleRef.current);
setVideoCover(detailData.poster); setVideoCover(detailData.poster);
setVideoDoubanId(detailData.douban_id || 0);
setDetail(detailData); setDetail(detailData);
if (currentEpisodeIndex >= detailData.episodes.length) { if (currentEpisodeIndex >= detailData.episodes.length) {
setCurrentEpisodeIndex(0); setCurrentEpisodeIndex(0);
@@ -868,6 +870,7 @@ function PlayPageClient() {
setVideoTitle(newDetail.title || newTitle); setVideoTitle(newDetail.title || newTitle);
setVideoYear(newDetail.year); setVideoYear(newDetail.year);
setVideoCover(newDetail.poster); setVideoCover(newDetail.poster);
setVideoDoubanId(newDetail.douban_id || 0);
setCurrentSource(newSource); setCurrentSource(newSource);
setCurrentId(newId); setCurrentId(newId);
setDetail(newDetail); setDetail(newDetail);
@@ -1932,13 +1935,41 @@ function PlayPageClient() {
{/* 封面展示 */} {/* 封面展示 */}
<div className='hidden md:block md:col-span-1 md:order-first'> <div className='hidden md:block md:col-span-1 md:order-first'>
<div className='pl-0 py-4 pr-6'> <div className='pl-0 py-4 pr-6'>
<div className='bg-gray-300 dark:bg-gray-700 aspect-[2/3] flex items-center justify-center rounded-xl overflow-hidden'> <div className='relative bg-gray-300 dark:bg-gray-700 aspect-[2/3] flex items-center justify-center rounded-xl overflow-hidden'>
{videoCover ? ( {videoCover ? (
<img <>
src={processImageUrl(videoCover)} <img
alt={videoTitle} src={processImageUrl(videoCover)}
className='w-full h-full object-cover' alt={videoTitle}
/> className='w-full h-full object-cover'
/>
{/* 豆瓣链接按钮 */}
{videoDoubanId !== 0 && (
<a
href={`https://movie.douban.com/subject/${videoDoubanId.toString()}`}
target='_blank'
rel='noopener noreferrer'
className='absolute top-3 left-3'
>
<div className='bg-green-500 text-white text-xs font-bold w-8 h-8 rounded-full flex items-center justify-center shadow-md hover:bg-green-600 hover:scale-[1.1] transition-all duration-300 ease-out'>
<svg
width='16'
height='16'
viewBox='0 0 24 24'
fill='none'
stroke='currentColor'
strokeWidth='2'
strokeLinecap='round'
strokeLinejoin='round'
>
<path d='M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71'></path>
<path d='M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71'></path>
</svg>
</div>
</a>
)}
</>
) : ( ) : (
<span className='text-gray-600 dark:text-gray-400'> <span className='text-gray-600 dark:text-gray-400'>

View File

@@ -322,12 +322,12 @@ function SearchPageClient() {
> >
<VideoCard <VideoCard
id={item.id} id={item.id}
title={item.title + ' ' + item.type_name} title={item.title}
poster={item.poster} poster={item.poster}
episodes={item.episodes.length} episodes={item.episodes.length}
source={item.source} source={item.source}
source_name={item.source_name} source_name={item.source_name}
douban_id={item.douban_id?.toString()} douban_id={item.douban_id}
query={ query={
searchQuery.trim() !== item.title searchQuery.trim() !== item.title
? searchQuery.trim() ? searchQuery.trim()

View File

@@ -30,7 +30,7 @@ interface VideoCardProps {
year?: string; year?: string;
from: 'playrecord' | 'favorite' | 'search' | 'douban'; from: 'playrecord' | 'favorite' | 'search' | 'douban';
currentEpisode?: number; currentEpisode?: number;
douban_id?: string; douban_id?: number;
onDelete?: () => void; onDelete?: () => void;
rate?: string; rate?: string;
items?: SearchResult[]; items?: SearchResult[];
@@ -63,7 +63,7 @@ export default function VideoCard({
const aggregateData = useMemo(() => { const aggregateData = useMemo(() => {
if (!isAggregate || !items) return null; if (!isAggregate || !items) return null;
const countMap = new Map<string | number, number>(); const countMap = new Map<number, number>();
const episodeCountMap = new Map<number, number>(); const episodeCountMap = new Map<number, number>();
items.forEach((item) => { items.forEach((item) => {
if (item.douban_id && item.douban_id !== 0) { if (item.douban_id && item.douban_id !== 0) {
@@ -75,11 +75,9 @@ export default function VideoCard({
} }
}); });
const getMostFrequent = <T extends string | number>( const getMostFrequent = (map: Map<number, number>) => {
map: Map<T, number>
) => {
let maxCount = 0; let maxCount = 0;
let result: T | undefined; let result: number | undefined;
map.forEach((cnt, key) => { map.forEach((cnt, key) => {
if (cnt > maxCount) { if (cnt > maxCount) {
maxCount = cnt; maxCount = cnt;
@@ -100,9 +98,7 @@ export default function VideoCard({
const actualPoster = aggregateData?.first.poster ?? poster; const actualPoster = aggregateData?.first.poster ?? poster;
const actualSource = aggregateData?.first.source ?? source; const actualSource = aggregateData?.first.source ?? source;
const actualId = aggregateData?.first.id ?? id; const actualId = aggregateData?.first.id ?? id;
const actualDoubanId = String( const actualDoubanId = aggregateData?.mostFrequentDoubanId ?? douban_id;
aggregateData?.mostFrequentDoubanId ?? douban_id
);
const actualEpisodes = aggregateData?.mostFrequentEpisodes ?? episodes; const actualEpisodes = aggregateData?.mostFrequentEpisodes ?? episodes;
const actualYear = aggregateData?.first.year ?? year; const actualYear = aggregateData?.first.year ?? year;
const actualQuery = query || ''; const actualQuery = query || '';
@@ -340,9 +336,9 @@ export default function VideoCard({
)} )}
{/* 豆瓣链接 */} {/* 豆瓣链接 */}
{config.showDoubanLink && actualDoubanId && ( {config.showDoubanLink && actualDoubanId && actualDoubanId !== 0 && (
<a <a
href={`https://movie.douban.com/subject/${actualDoubanId}`} href={`https://movie.douban.com/subject/${actualDoubanId.toString()}`}
target='_blank' target='_blank'
rel='noopener noreferrer' rel='noopener noreferrer'
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}

View File

@@ -2,7 +2,7 @@
'use client'; 'use client';
const CURRENT_VERSION = '20250806191001'; const CURRENT_VERSION = '20250806193618';
// 版本检查结果枚举 // 版本检查结果枚举
export enum UpdateStatus { export enum UpdateStatus {