tmdb增加轮询
This commit is contained in:
@@ -6382,7 +6382,7 @@ const SiteConfigComponent = ({
|
||||
</label>
|
||||
<input
|
||||
type='text'
|
||||
placeholder='请输入 TMDB API Key'
|
||||
placeholder='请输入 TMDB API Key(多个key用英文逗号分隔)'
|
||||
value={siteSettings.TMDBApiKey}
|
||||
onChange={(e) =>
|
||||
setSiteSettings((prev) => ({
|
||||
@@ -6393,7 +6393,7 @@ const SiteConfigComponent = ({
|
||||
className='w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-green-500 focus:border-transparent'
|
||||
/>
|
||||
<p className='mt-1 text-xs text-gray-500 dark:text-gray-400'>
|
||||
配置后首页将显示 TMDB 即将上映电影。获取 API Key 请访问{' '}
|
||||
配置后首页将显示 TMDB 即将上映电影。支持配置多个 API Key(用英文逗号分隔)以实现轮询,避免单个 Key 请求限制。获取 API Key 请访问{' '}
|
||||
<a
|
||||
href='https://www.themoviedb.org/settings/api'
|
||||
target='_blank'
|
||||
@@ -8928,6 +8928,24 @@ function AdminPageClient() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* TMDB 未配置提示 */}
|
||||
{config && !config.SiteConfig.TMDBApiKey && (
|
||||
<div className='bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4 mb-4'>
|
||||
<div className='flex items-start gap-3'>
|
||||
<div className='flex-shrink-0 mt-0.5'>
|
||||
<svg className='w-5 h-5 text-blue-600 dark:text-blue-400' fill='currentColor' viewBox='0 0 20 20'>
|
||||
<path fillRule='evenodd' d='M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z' clipRule='evenodd' />
|
||||
</svg>
|
||||
</div>
|
||||
<div className='flex-1'>
|
||||
<p className='text-sm font-medium text-blue-800 dark:text-blue-300'>
|
||||
未配置 TMDB API Key,配置后可获得更丰富的影视信息和推荐内容
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 配置文件标签 - 仅站长可见 */}
|
||||
{role === 'owner' && (
|
||||
<CollapsibleTab
|
||||
|
||||
@@ -4,6 +4,7 @@ import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
import { getAuthInfoFromCookie } from '@/lib/auth';
|
||||
import { getConfig } from '@/lib/config';
|
||||
import { getNextApiKey } from '@/lib/tmdb.client';
|
||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import nodeFetch from 'node-fetch';
|
||||
|
||||
@@ -31,7 +32,8 @@ export async function GET(request: NextRequest) {
|
||||
const tmdbApiKey = config.SiteConfig.TMDBApiKey;
|
||||
const tmdbProxy = config.SiteConfig.TMDBProxy;
|
||||
|
||||
if (!tmdbApiKey) {
|
||||
const actualKey = getNextApiKey(tmdbApiKey || '');
|
||||
if (!actualKey) {
|
||||
return NextResponse.json(
|
||||
{ error: 'TMDB API Key 未配置' },
|
||||
{ status: 400 }
|
||||
@@ -39,7 +41,7 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
|
||||
// 使用 multi search 同时搜索电影和电视剧
|
||||
const url = `https://api.themoviedb.org/3/search/multi?api_key=${tmdbApiKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
const url = `https://api.themoviedb.org/3/search/multi?api_key=${actualKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
|
||||
const fetchOptions: any = tmdbProxy
|
||||
? {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import { fetchDoubanData as fetchDoubanAPI } from '@/lib/douban';
|
||||
import { searchTMDB, getTVSeasons } from '@/lib/tmdb.search';
|
||||
import { getNextApiKey } from '@/lib/tmdb.client';
|
||||
|
||||
export interface VideoContext {
|
||||
title?: string;
|
||||
@@ -251,7 +252,8 @@ async function fetchTMDBData(
|
||||
tmdbProxy?: string
|
||||
): Promise<any> {
|
||||
try {
|
||||
if (!tmdbApiKey) {
|
||||
const actualKey = getNextApiKey(tmdbApiKey || '');
|
||||
if (!actualKey) {
|
||||
console.log('⚠️ TMDB API Key 未配置,跳过TMDB数据获取');
|
||||
return null;
|
||||
}
|
||||
@@ -263,7 +265,7 @@ async function fetchTMDBData(
|
||||
|
||||
// 使用 TMDB API 获取详情
|
||||
// TMDB API: https://api.themoviedb.org/3/{type}/{id}
|
||||
const url = `https://api.themoviedb.org/3/${params.type}/${params.id}?api_key=${tmdbApiKey}&language=zh-CN&append_to_response=keywords,similar`;
|
||||
const url = `https://api.themoviedb.org/3/${params.type}/${params.id}?api_key=${actualKey}&language=zh-CN&append_to_response=keywords,similar`;
|
||||
|
||||
console.log('📡 获取TMDB详情:', params.type, params.id);
|
||||
|
||||
|
||||
@@ -183,6 +183,7 @@ export class DbManager {
|
||||
enabledApis?: string[];
|
||||
created_at: number;
|
||||
playrecord_migrated?: boolean;
|
||||
favorite_migrated?: boolean;
|
||||
} | null> {
|
||||
if (typeof (this.storage as any).getUserInfoV2 === 'function') {
|
||||
return (this.storage as any).getUserInfoV2(userName);
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import nodeFetch from 'node-fetch';
|
||||
|
||||
// TMDB API Key 轮询管理
|
||||
let currentKeyIndex = 0;
|
||||
|
||||
/**
|
||||
* 解析并获取下一个可用的 TMDB API Key
|
||||
* @param apiKeys - API Key 字符串(支持逗号分隔的多个key)
|
||||
* @returns 当前应使用的 API Key
|
||||
*/
|
||||
export function getNextApiKey(apiKeys: string): string {
|
||||
if (!apiKeys) return '';
|
||||
|
||||
const keys = apiKeys.split(',').map(k => k.trim()).filter(k => k);
|
||||
if (keys.length === 0) return '';
|
||||
if (keys.length === 1) return keys[0];
|
||||
|
||||
// 轮询获取下一个key
|
||||
const key = keys[currentKeyIndex % keys.length];
|
||||
currentKeyIndex = (currentKeyIndex + 1) % keys.length;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
export interface TMDBMovie {
|
||||
id: number;
|
||||
title: string;
|
||||
@@ -63,11 +85,12 @@ export async function getTMDBUpcomingMovies(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; list: TMDBMovie[] }> {
|
||||
try {
|
||||
if (!apiKey) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey) {
|
||||
return { code: 400, list: [] };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/movie/upcoming?api_key=${apiKey}&language=zh-CN&page=${page}®ion=${region}`;
|
||||
const url = `https://api.themoviedb.org/3/movie/upcoming?api_key=${actualKey}&language=zh-CN&page=${page}®ion=${region}`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -113,12 +136,13 @@ export async function getTMDBUpcomingTVShows(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; list: TMDBTVShow[] }> {
|
||||
try {
|
||||
if (!apiKey) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey) {
|
||||
return { code: 400, list: [] };
|
||||
}
|
||||
|
||||
// 使用 on_the_air 接口获取正在播出的电视剧
|
||||
const url = `https://api.themoviedb.org/3/tv/on_the_air?api_key=${apiKey}&language=zh-CN&page=${page}`;
|
||||
const url = `https://api.themoviedb.org/3/tv/on_the_air?api_key=${actualKey}&language=zh-CN&page=${page}`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -242,12 +266,13 @@ export async function getTMDBTrendingContent(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; list: TMDBItem[] }> {
|
||||
try {
|
||||
if (!apiKey) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey) {
|
||||
return { code: 400, list: [] };
|
||||
}
|
||||
|
||||
// 获取本周热门内容(电影+电视剧)
|
||||
const url = `https://api.themoviedb.org/3/trending/all/week?api_key=${apiKey}&language=zh-CN`;
|
||||
const url = `https://api.themoviedb.org/3/trending/all/week?api_key=${actualKey}&language=zh-CN`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -370,11 +395,12 @@ export async function searchTMDBMulti(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; results: any[] }> {
|
||||
try {
|
||||
if (!apiKey || !query) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey || !query) {
|
||||
return { code: 400, results: [] };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/search/multi?api_key=${apiKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
const url = `https://api.themoviedb.org/3/search/multi?api_key=${actualKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -419,11 +445,12 @@ export async function getTMDBMovieRecommendations(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; results: TMDBMovie[] }> {
|
||||
try {
|
||||
if (!apiKey || !movieId) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey || !movieId) {
|
||||
return { code: 400, results: [] };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/movie/${movieId}/recommendations?api_key=${apiKey}&language=zh-CN&page=1`;
|
||||
const url = `https://api.themoviedb.org/3/movie/${movieId}/recommendations?api_key=${actualKey}&language=zh-CN&page=1`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -468,11 +495,12 @@ export async function getTMDBTVRecommendations(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; results: TMDBTVShow[] }> {
|
||||
try {
|
||||
if (!apiKey || !tvId) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey || !tvId) {
|
||||
return { code: 400, results: [] };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}/recommendations?api_key=${apiKey}&language=zh-CN&page=1`;
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}/recommendations?api_key=${actualKey}&language=zh-CN&page=1`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -517,11 +545,12 @@ export async function getTMDBMovieDetails(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; details: any }> {
|
||||
try {
|
||||
if (!apiKey) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey) {
|
||||
return { code: 400, details: null };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/movie/${movieId}?api_key=${apiKey}&language=zh-CN`;
|
||||
const url = `https://api.themoviedb.org/3/movie/${movieId}?api_key=${actualKey}&language=zh-CN`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -566,11 +595,12 @@ export async function getTMDBTVDetails(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; details: any }> {
|
||||
try {
|
||||
if (!apiKey) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey) {
|
||||
return { code: 400, details: null };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}?api_key=${apiKey}&language=zh-CN`;
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}?api_key=${actualKey}&language=zh-CN`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import nodeFetch from 'node-fetch';
|
||||
import { getNextApiKey } from './tmdb.client';
|
||||
|
||||
export interface TMDBSearchResult {
|
||||
id: number;
|
||||
@@ -32,12 +33,13 @@ export async function searchTMDB(
|
||||
year?: number
|
||||
): Promise<{ code: number; result: TMDBSearchResult | null }> {
|
||||
try {
|
||||
if (!apiKey) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey) {
|
||||
return { code: 400, result: null };
|
||||
}
|
||||
|
||||
// 使用 multi search 同时搜索电影和电视剧
|
||||
let url = `https://api.themoviedb.org/3/search/multi?api_key=${apiKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
let url = `https://api.themoviedb.org/3/search/multi?api_key=${actualKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
|
||||
// 如果提供了年份,添加到搜索参数中
|
||||
if (year) {
|
||||
@@ -121,11 +123,12 @@ export async function getTVSeasons(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; seasons: TMDBSeasonInfo[] | null }> {
|
||||
try {
|
||||
if (!apiKey) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey) {
|
||||
return { code: 400, seasons: null };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}?api_key=${apiKey}&language=zh-CN`;
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}?api_key=${actualKey}&language=zh-CN`;
|
||||
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
@@ -171,11 +174,12 @@ export async function getTVSeasonDetails(
|
||||
proxy?: string
|
||||
): Promise<{ code: number; season: TMDBSeasonInfo | null }> {
|
||||
try {
|
||||
if (!apiKey) {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
if (!actualKey) {
|
||||
return { code: 400, season: null };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}/season/${seasonNumber}?api_key=${apiKey}&language=zh-CN`;
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}/season/${seasonNumber}?api_key=${actualKey}&language=zh-CN`;
|
||||
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
|
||||
Reference in New Issue
Block a user