支持自定义tmdb图片baseurl
This commit is contained in:
@@ -6,6 +6,7 @@ import { createPortal } from 'react-dom';
|
|||||||
import { CheckCircle, AlertCircle, Plus } from 'lucide-react';
|
import { CheckCircle, AlertCircle, Plus } from 'lucide-react';
|
||||||
|
|
||||||
import PageLayout from '@/components/PageLayout';
|
import PageLayout from '@/components/PageLayout';
|
||||||
|
import { getTMDBImageUrl } from '@/lib/tmdb.client';
|
||||||
|
|
||||||
interface TMDBResult {
|
interface TMDBResult {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -116,7 +117,7 @@ export default function MovieRequestPage() {
|
|||||||
const submitRequest = async (item: TMDBResult, season?: number) => {
|
const submitRequest = async (item: TMDBResult, season?: number) => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
try {
|
try {
|
||||||
let poster = item.poster_path ? `https://image.tmdb.org/t/p/w500${item.poster_path}` : undefined;
|
let poster = item.poster_path ? getTMDBImageUrl(item.poster_path, 'w500') : undefined;
|
||||||
let title = item.title || item.name || '';
|
let title = item.title || item.name || '';
|
||||||
|
|
||||||
if (season && seasons.length > 0) {
|
if (season && seasons.length > 0) {
|
||||||
@@ -124,7 +125,7 @@ export default function MovieRequestPage() {
|
|||||||
if (seasonData) {
|
if (seasonData) {
|
||||||
title = `${title} ${seasonData.name}`;
|
title = `${title} ${seasonData.name}`;
|
||||||
if (seasonData.poster_path) {
|
if (seasonData.poster_path) {
|
||||||
poster = `https://image.tmdb.org/t/p/w500${seasonData.poster_path}`;
|
poster = getTMDBImageUrl(seasonData.poster_path, 'w500');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,7 +311,7 @@ export default function MovieRequestPage() {
|
|||||||
>
|
>
|
||||||
{item.poster_path ? (
|
{item.poster_path ? (
|
||||||
<img
|
<img
|
||||||
src={`https://image.tmdb.org/t/p/w500${item.poster_path}`}
|
src={getTMDBImageUrl(item.poster_path, 'w500')}
|
||||||
alt={item.title || item.name}
|
alt={item.title || item.name}
|
||||||
className='w-full aspect-[2/3] object-cover'
|
className='w-full aspect-[2/3] object-cover'
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { X, Calendar, Star, Clock, Tag, Users, Globe, Film } from 'lucide-react'
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
import { getTMDBImageUrl } from '@/lib/tmdb.client';
|
||||||
|
|
||||||
interface DetailPanelProps {
|
interface DetailPanelProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -372,7 +373,7 @@ const DetailPanel: React.FC<DetailPanelProps> = ({
|
|||||||
? detailResult.release_date?.substring(0, 4)
|
? detailResult.release_date?.substring(0, 4)
|
||||||
: detailResult.first_air_date?.substring(0, 4),
|
: detailResult.first_air_date?.substring(0, 4),
|
||||||
poster: detailResult.poster_path
|
poster: detailResult.poster_path
|
||||||
? `https://image.tmdb.org/t/p/w500${detailResult.poster_path}`
|
? getTMDBImageUrl(detailResult.poster_path, 'w500')
|
||||||
: poster,
|
: poster,
|
||||||
rating: detailResult.vote_average
|
rating: detailResult.vote_average
|
||||||
? {
|
? {
|
||||||
@@ -480,7 +481,7 @@ const DetailPanel: React.FC<DetailPanelProps> = ({
|
|||||||
...prev,
|
...prev,
|
||||||
title: episodesData.name || season?.name || prev.title,
|
title: episodesData.name || season?.name || prev.title,
|
||||||
intro: episodesData.overview || season?.overview || prev.overview,
|
intro: episodesData.overview || season?.overview || prev.overview,
|
||||||
poster: season?.poster_path ? `https://image.tmdb.org/t/p/w500${season.poster_path}` : prev.poster,
|
poster: season?.poster_path ? getTMDBImageUrl(season.poster_path, 'w500') : prev.poster,
|
||||||
releaseDate: episodesData.air_date || season?.air_date || prev.releaseDate,
|
releaseDate: episodesData.air_date || season?.air_date || prev.releaseDate,
|
||||||
year: episodesData.air_date?.substring(0, 4) || season?.air_date?.substring(0, 4) || prev.year,
|
year: episodesData.air_date?.substring(0, 4) || season?.air_date?.substring(0, 4) || prev.year,
|
||||||
episodesCount: episodesData.episodes?.length || season?.episode_count || prev.episodesCount,
|
episodesCount: episodesData.episodes?.length || season?.episode_count || prev.episodesCount,
|
||||||
@@ -732,7 +733,7 @@ const DetailPanel: React.FC<DetailPanelProps> = ({
|
|||||||
{season.poster_path && (
|
{season.poster_path && (
|
||||||
<div className="relative w-12 h-16 rounded overflow-hidden bg-gray-200 dark:bg-gray-700 flex-shrink-0">
|
<div className="relative w-12 h-16 rounded overflow-hidden bg-gray-200 dark:bg-gray-700 flex-shrink-0">
|
||||||
<Image
|
<Image
|
||||||
src={`https://image.tmdb.org/t/p/w92${season.poster_path}`}
|
src={getTMDBImageUrl(season.poster_path, 'w92')}
|
||||||
alt={season.name}
|
alt={season.name}
|
||||||
fill
|
fill
|
||||||
className="object-cover"
|
className="object-cover"
|
||||||
@@ -771,7 +772,7 @@ const DetailPanel: React.FC<DetailPanelProps> = ({
|
|||||||
{episode.still_path && (
|
{episode.still_path && (
|
||||||
<div className="relative w-full h-36 rounded overflow-hidden bg-gray-200 dark:bg-gray-700 mb-2">
|
<div className="relative w-full h-36 rounded overflow-hidden bg-gray-200 dark:bg-gray-700 mb-2">
|
||||||
<Image
|
<Image
|
||||||
src={`https://image.tmdb.org/t/p/w300${episode.still_path}`}
|
src={getTMDBImageUrl(episode.still_path, 'w300')}
|
||||||
alt={episode.name}
|
alt={episode.name}
|
||||||
fill
|
fill
|
||||||
className="object-cover"
|
className="object-cover"
|
||||||
|
|||||||
@@ -119,6 +119,9 @@ export const UserMenu: React.FC = () => {
|
|||||||
|
|
||||||
// 折叠面板状态
|
// 折叠面板状态
|
||||||
const [isDoubanSectionOpen, setIsDoubanSectionOpen] = useState(true);
|
const [isDoubanSectionOpen, setIsDoubanSectionOpen] = useState(true);
|
||||||
|
|
||||||
|
// TMDB 图片设置
|
||||||
|
const [tmdbImageBaseUrl, setTmdbImageBaseUrl] = useState('https://image.tmdb.org');
|
||||||
const [isUsageSectionOpen, setIsUsageSectionOpen] = useState(false);
|
const [isUsageSectionOpen, setIsUsageSectionOpen] = useState(false);
|
||||||
const [isBufferSectionOpen, setIsBufferSectionOpen] = useState(false);
|
const [isBufferSectionOpen, setIsBufferSectionOpen] = useState(false);
|
||||||
const [isDanmakuSectionOpen, setIsDanmakuSectionOpen] = useState(false);
|
const [isDanmakuSectionOpen, setIsDanmakuSectionOpen] = useState(false);
|
||||||
@@ -339,6 +342,11 @@ export const UserMenu: React.FC = () => {
|
|||||||
setDoubanImageProxyUrl(defaultDoubanImageProxyUrl);
|
setDoubanImageProxyUrl(defaultDoubanImageProxyUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const savedTmdbImageBaseUrl = localStorage.getItem('tmdbImageBaseUrl');
|
||||||
|
if (savedTmdbImageBaseUrl !== null) {
|
||||||
|
setTmdbImageBaseUrl(savedTmdbImageBaseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
const savedEnableOptimization =
|
const savedEnableOptimization =
|
||||||
localStorage.getItem('enableOptimization');
|
localStorage.getItem('enableOptimization');
|
||||||
if (savedEnableOptimization !== null) {
|
if (savedEnableOptimization !== null) {
|
||||||
@@ -704,6 +712,13 @@ export const UserMenu: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleTmdbImageBaseUrlChange = (value: string) => {
|
||||||
|
setTmdbImageBaseUrl(value);
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
localStorage.setItem('tmdbImageBaseUrl', value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleBufferStrategyChange = (value: string) => {
|
const handleBufferStrategyChange = (value: string) => {
|
||||||
setBufferStrategy(value);
|
setBufferStrategy(value);
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
@@ -833,6 +848,7 @@ export const UserMenu: React.FC = () => {
|
|||||||
setDoubanDataSource(defaultDoubanProxyType);
|
setDoubanDataSource(defaultDoubanProxyType);
|
||||||
setDoubanImageProxyType(defaultDoubanImageProxyType);
|
setDoubanImageProxyType(defaultDoubanImageProxyType);
|
||||||
setDoubanImageProxyUrl(defaultDoubanImageProxyUrl);
|
setDoubanImageProxyUrl(defaultDoubanImageProxyUrl);
|
||||||
|
setTmdbImageBaseUrl('https://image.tmdb.org');
|
||||||
setBufferStrategy('medium');
|
setBufferStrategy('medium');
|
||||||
setNextEpisodePreCache(true);
|
setNextEpisodePreCache(true);
|
||||||
setNextEpisodeDanmakuPreload(true);
|
setNextEpisodeDanmakuPreload(true);
|
||||||
@@ -850,6 +866,7 @@ export const UserMenu: React.FC = () => {
|
|||||||
localStorage.setItem('doubanDataSource', defaultDoubanProxyType);
|
localStorage.setItem('doubanDataSource', defaultDoubanProxyType);
|
||||||
localStorage.setItem('doubanImageProxyType', defaultDoubanImageProxyType);
|
localStorage.setItem('doubanImageProxyType', defaultDoubanImageProxyType);
|
||||||
localStorage.setItem('doubanImageProxyUrl', defaultDoubanImageProxyUrl);
|
localStorage.setItem('doubanImageProxyUrl', defaultDoubanImageProxyUrl);
|
||||||
|
localStorage.setItem('tmdbImageBaseUrl', 'https://image.tmdb.org');
|
||||||
localStorage.setItem('bufferStrategy', 'medium');
|
localStorage.setItem('bufferStrategy', 'medium');
|
||||||
localStorage.setItem('nextEpisodePreCache', 'true');
|
localStorage.setItem('nextEpisodePreCache', 'true');
|
||||||
localStorage.setItem('nextEpisodeDanmakuPreload', 'true');
|
localStorage.setItem('nextEpisodeDanmakuPreload', 'true');
|
||||||
@@ -1167,7 +1184,7 @@ export const UserMenu: React.FC = () => {
|
|||||||
className='w-full px-3 py-2.5 md:px-4 md:py-3 bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-750 transition-colors flex items-center justify-between'
|
className='w-full px-3 py-2.5 md:px-4 md:py-3 bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-750 transition-colors flex items-center justify-between'
|
||||||
>
|
>
|
||||||
<h3 className='text-base font-semibold text-gray-800 dark:text-gray-200'>
|
<h3 className='text-base font-semibold text-gray-800 dark:text-gray-200'>
|
||||||
豆瓣设置
|
网络设置
|
||||||
</h3>
|
</h3>
|
||||||
{isDoubanSectionOpen ? (
|
{isDoubanSectionOpen ? (
|
||||||
<ChevronUp className='w-5 h-5 text-gray-600 dark:text-gray-400' />
|
<ChevronUp className='w-5 h-5 text-gray-600 dark:text-gray-400' />
|
||||||
@@ -1384,6 +1401,30 @@ export const UserMenu: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 分割线 */}
|
||||||
|
<div className='border-t border-gray-200 dark:border-gray-700'></div>
|
||||||
|
|
||||||
|
{/* TMDB 图片网络请求地址设置 */}
|
||||||
|
<div className='space-y-3'>
|
||||||
|
<div>
|
||||||
|
<h4 className='text-sm font-medium text-gray-700 dark:text-gray-300'>
|
||||||
|
TMDB 图片网络请求地址
|
||||||
|
</h4>
|
||||||
|
<p className='text-xs text-gray-500 dark:text-gray-400 mt-1'>
|
||||||
|
TMDB 图片的 Base URL(默认: https://image.tmdb.org)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='w-full px-3 py-2.5 border border-gray-300 dark:border-gray-600 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-green-500 transition-all duration-200 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 shadow-sm hover:border-gray-400 dark:hover:border-gray-500'
|
||||||
|
placeholder='例如: https://image.tmdb.org'
|
||||||
|
value={tmdbImageBaseUrl}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleTmdbImageBaseUrlChange(e.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -403,7 +403,10 @@ export function getTMDBImageUrl(
|
|||||||
size: string = 'w500'
|
size: string = 'w500'
|
||||||
): string {
|
): string {
|
||||||
if (!path) return '';
|
if (!path) return '';
|
||||||
return `https://image.tmdb.org/t/p/${size}${path}`;
|
const baseUrl = typeof window !== 'undefined'
|
||||||
|
? localStorage.getItem('tmdbImageBaseUrl') || 'https://image.tmdb.org'
|
||||||
|
: 'https://image.tmdb.org';
|
||||||
|
return `${baseUrl}/t/p/${size}${path}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -226,5 +226,8 @@ export function getTMDBImageUrl(
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `https://image.tmdb.org/t/p/${size}${path}`;
|
const baseUrl = typeof window !== 'undefined'
|
||||||
|
? localStorage.getItem('tmdbImageBaseUrl') || 'https://image.tmdb.org'
|
||||||
|
: 'https://image.tmdb.org';
|
||||||
|
return `${baseUrl}/t/p/${size}${path}`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user