mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-02-20 08:24:40 +08:00
feat: add play page douban link
This commit is contained in:
@@ -1 +1 @@
|
||||
20250806191001
|
||||
20250806193618
|
||||
@@ -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 不控
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
|
||||
@@ -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'>
|
||||
封面图片
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
'use client';
|
||||
|
||||
const CURRENT_VERSION = '20250806191001';
|
||||
const CURRENT_VERSION = '20250806193618';
|
||||
|
||||
// 版本检查结果枚举
|
||||
export enum UpdateStatus {
|
||||
|
||||
Reference in New Issue
Block a user