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'
title={item.title}
poster={item.poster}
douban_id={item.id}
douban_id={Number(item.id)}
rate={item.rate}
year={item.year}
type={type === 'movie' ? 'movie' : ''} // 电影类型严格控制tv 不控

View File

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

View File

@@ -92,6 +92,7 @@ function PlayPageClient() {
const [videoTitle, setVideoTitle] = useState(searchParams.get('title') || '');
const [videoYear, setVideoYear] = useState(searchParams.get('year') || '');
const [videoCover, setVideoCover] = useState('');
const [videoDoubanId, setVideoDoubanId] = useState(0);
// 当前源和ID
const [currentSource, setCurrentSource] = useState(
searchParams.get('source') || ''
@@ -715,6 +716,7 @@ function PlayPageClient() {
setVideoYear(detailData.year);
setVideoTitle(detailData.title || videoTitleRef.current);
setVideoCover(detailData.poster);
setVideoDoubanId(detailData.douban_id || 0);
setDetail(detailData);
if (currentEpisodeIndex >= detailData.episodes.length) {
setCurrentEpisodeIndex(0);
@@ -868,6 +870,7 @@ function PlayPageClient() {
setVideoTitle(newDetail.title || newTitle);
setVideoYear(newDetail.year);
setVideoCover(newDetail.poster);
setVideoDoubanId(newDetail.douban_id || 0);
setCurrentSource(newSource);
setCurrentId(newId);
setDetail(newDetail);
@@ -1932,13 +1935,41 @@ function PlayPageClient() {
{/* 封面展示 */}
<div className='hidden md:block md:col-span-1 md:order-first'>
<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 ? (
<img
src={processImageUrl(videoCover)}
alt={videoTitle}
className='w-full h-full object-cover'
/>
<>
<img
src={processImageUrl(videoCover)}
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'>

View File

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

View File

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

View File

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