完善tmdb反代
This commit is contained in:
@@ -249,7 +249,8 @@ async function fetchTMDBData(
|
||||
type?: 'movie' | 'tv';
|
||||
},
|
||||
tmdbApiKey?: string,
|
||||
tmdbProxy?: string
|
||||
tmdbProxy?: string,
|
||||
tmdbReverseProxy?: string
|
||||
): Promise<any> {
|
||||
try {
|
||||
const actualKey = getNextApiKey(tmdbApiKey || '');
|
||||
@@ -263,9 +264,11 @@ async function fetchTMDBData(
|
||||
return null;
|
||||
}
|
||||
|
||||
// 使用反代代理或默认 Base URL
|
||||
const baseUrl = tmdbReverseProxy || 'https://api.themoviedb.org';
|
||||
// 使用 TMDB API 获取详情
|
||||
// TMDB API: https://api.themoviedb.org/3/{type}/{id}
|
||||
const url = `https://api.themoviedb.org/3/${params.type}/${params.id}?api_key=${actualKey}&language=zh-CN&append_to_response=keywords,similar`;
|
||||
const url = `${baseUrl}/3/${params.type}/${params.id}?api_key=${actualKey}&language=zh-CN&append_to_response=keywords,similar`;
|
||||
|
||||
console.log('📡 获取TMDB详情:', params.type, params.id);
|
||||
|
||||
@@ -517,6 +520,7 @@ export async function orchestrateDataSources(
|
||||
// TMDB 配置
|
||||
tmdbApiKey?: string;
|
||||
tmdbProxy?: string;
|
||||
tmdbReverseProxy?: string;
|
||||
// 决策模型配置
|
||||
enableDecisionModel?: boolean;
|
||||
decisionProvider?: 'openai' | 'claude' | 'custom';
|
||||
@@ -653,7 +657,8 @@ export async function orchestrateDataSources(
|
||||
type: context.type,
|
||||
},
|
||||
config?.tmdbApiKey,
|
||||
config?.tmdbProxy
|
||||
config?.tmdbProxy,
|
||||
config?.tmdbReverseProxy
|
||||
);
|
||||
dataPromises.push(tmdbPromise);
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ export async function startOpenListRefresh(clearMetaInfo: boolean = false): Prom
|
||||
|
||||
const tmdbApiKey = config.SiteConfig.TMDBApiKey;
|
||||
const tmdbProxy = config.SiteConfig.TMDBProxy;
|
||||
const tmdbReverseProxy = config.SiteConfig.TMDBReverseProxy;
|
||||
|
||||
if (!tmdbApiKey) {
|
||||
throw new Error('TMDB API Key 未配置');
|
||||
@@ -124,6 +125,7 @@ export async function startOpenListRefresh(clearMetaInfo: boolean = false): Prom
|
||||
rootPaths,
|
||||
tmdbApiKey,
|
||||
tmdbProxy,
|
||||
tmdbReverseProxy,
|
||||
openListConfig.Username,
|
||||
openListConfig.Password,
|
||||
clearMetaInfo,
|
||||
@@ -145,6 +147,7 @@ async function performMultiRootScan(
|
||||
rootPaths: string[],
|
||||
tmdbApiKey: string,
|
||||
tmdbProxy: string | undefined,
|
||||
tmdbReverseProxy: string | undefined,
|
||||
username: string,
|
||||
password: string,
|
||||
clearMetaInfo: boolean,
|
||||
@@ -161,6 +164,7 @@ async function performMultiRootScan(
|
||||
rootPath,
|
||||
tmdbApiKey,
|
||||
tmdbProxy,
|
||||
tmdbReverseProxy,
|
||||
username,
|
||||
password,
|
||||
clearMetaInfo && i === 0, // 只在第一个根目录时清除
|
||||
@@ -182,6 +186,7 @@ async function performScan(
|
||||
rootPath: string,
|
||||
tmdbApiKey: string,
|
||||
tmdbProxy?: string,
|
||||
tmdbReverseProxy?: string,
|
||||
username?: string,
|
||||
password?: string,
|
||||
clearMetaInfo?: boolean,
|
||||
@@ -288,7 +293,7 @@ async function performScan(
|
||||
console.log(`[OpenList Refresh] 种子库模式 - 文件夹: ${folder.name}`);
|
||||
console.log(`[OpenList Refresh] 解析结果 - 标题: ${searchQuery}, 季度: ${seasonNumber}, 年份: ${year}`);
|
||||
|
||||
searchResult = await searchTMDB(tmdbApiKey, searchQuery, tmdbProxy, year || undefined);
|
||||
searchResult = await searchTMDB(tmdbApiKey, searchQuery, tmdbProxy, year || undefined, tmdbReverseProxy);
|
||||
}
|
||||
|
||||
if (scanMode === 'name' || (scanMode === 'hybrid' && (!searchResult || searchResult.code !== 200 || !searchResult.result))) {
|
||||
@@ -300,7 +305,7 @@ async function performScan(
|
||||
console.log(`[OpenList Refresh] 名字匹配模式 - 文件夹: ${folder.name}`);
|
||||
console.log(`[OpenList Refresh] 清理后标题: ${searchQuery}, 季度: ${seasonNumber}, 年份: ${year}`);
|
||||
|
||||
searchResult = await searchTMDB(tmdbApiKey, searchQuery, tmdbProxy, year || undefined);
|
||||
searchResult = await searchTMDB(tmdbApiKey, searchQuery, tmdbProxy, year || undefined, tmdbReverseProxy);
|
||||
}
|
||||
|
||||
if (searchResult.code === 200 && searchResult.result) {
|
||||
@@ -325,7 +330,8 @@ async function performScan(
|
||||
tmdbApiKey,
|
||||
result.id,
|
||||
seasonNumber,
|
||||
tmdbProxy
|
||||
tmdbProxy,
|
||||
tmdbReverseProxy
|
||||
);
|
||||
|
||||
if (seasonDetails.code === 200 && seasonDetails.season) {
|
||||
|
||||
@@ -354,7 +354,8 @@ export async function getXiaoyaDetail(id: string): Promise<SearchResult> {
|
||||
client,
|
||||
decodedDirPath,
|
||||
config.SiteConfig.TMDBApiKey,
|
||||
config.SiteConfig.TMDBProxy
|
||||
config.SiteConfig.TMDBProxy,
|
||||
config.SiteConfig.TMDBReverseProxy
|
||||
);
|
||||
|
||||
// 获取集数列表
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import nodeFetch from 'node-fetch';
|
||||
|
||||
// TMDB API 默认 Base URL
|
||||
const DEFAULT_TMDB_BASE_URL = 'https://api.themoviedb.org/3';
|
||||
// TMDB API 默认 Base URL(不包含 /3/,由程序拼接)
|
||||
const DEFAULT_TMDB_BASE_URL = 'https://api.themoviedb.org';
|
||||
|
||||
// TMDB API Key 轮询管理
|
||||
let currentKeyIndex = 0;
|
||||
@@ -97,7 +97,7 @@ export async function getTMDBUpcomingMovies(
|
||||
}
|
||||
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/movie/upcoming?api_key=${actualKey}&language=zh-CN&page=${page}®ion=${region}`;
|
||||
const url = `${baseUrl}/3/movie/upcoming?api_key=${actualKey}&language=zh-CN&page=${page}®ion=${region}`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -152,7 +152,7 @@ export async function getTMDBUpcomingTVShows(
|
||||
|
||||
// 使用 on_the_air 接口获取正在播出的电视剧
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/tv/on_the_air?api_key=${actualKey}&language=zh-CN&page=${page}`;
|
||||
const url = `${baseUrl}/3/tv/on_the_air?api_key=${actualKey}&language=zh-CN&page=${page}`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -290,7 +290,7 @@ export async function getTMDBVideos(
|
||||
}
|
||||
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/${mediaType}/${mediaId}/videos?api_key=${actualKey}`;
|
||||
const url = `${baseUrl}/3/${mediaType}/${mediaId}/videos?api_key=${actualKey}`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -344,7 +344,7 @@ export async function getTMDBTrendingContent(
|
||||
|
||||
// 获取本周热门内容(电影+电视剧)
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/trending/all/week?api_key=${actualKey}&language=zh-CN`;
|
||||
const url = `${baseUrl}/3/trending/all/week?api_key=${actualKey}&language=zh-CN`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -478,7 +478,7 @@ export async function searchTMDBMulti(
|
||||
}
|
||||
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/search/multi?api_key=${actualKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
const url = `${baseUrl}/3/search/multi?api_key=${actualKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -531,7 +531,7 @@ export async function getTMDBMovieRecommendations(
|
||||
}
|
||||
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/movie/${movieId}/recommendations?api_key=${actualKey}&language=zh-CN&page=1`;
|
||||
const url = `${baseUrl}/3/movie/${movieId}/recommendations?api_key=${actualKey}&language=zh-CN&page=1`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -584,7 +584,7 @@ export async function getTMDBTVRecommendations(
|
||||
}
|
||||
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/tv/${tvId}/recommendations?api_key=${actualKey}&language=zh-CN&page=1`;
|
||||
const url = `${baseUrl}/3/tv/${tvId}/recommendations?api_key=${actualKey}&language=zh-CN&page=1`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -637,7 +637,7 @@ export async function getTMDBMovieDetails(
|
||||
}
|
||||
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/movie/${movieId}?api_key=${actualKey}&language=zh-CN`;
|
||||
const url = `${baseUrl}/3/movie/${movieId}?api_key=${actualKey}&language=zh-CN`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
@@ -690,7 +690,7 @@ export async function getTMDBTVDetails(
|
||||
}
|
||||
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/tv/${tvId}?api_key=${actualKey}&language=zh-CN`;
|
||||
const url = `${baseUrl}/3/tv/${tvId}?api_key=${actualKey}&language=zh-CN`;
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
agent: new HttpsProxyAgent(proxy, {
|
||||
|
||||
@@ -4,6 +4,9 @@ import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import nodeFetch from 'node-fetch';
|
||||
import { getNextApiKey } from './tmdb.client';
|
||||
|
||||
// TMDB API 默认 Base URL(不包含 /3/,由程序拼接)
|
||||
const DEFAULT_TMDB_BASE_URL = 'https://api.themoviedb.org';
|
||||
|
||||
export interface TMDBSearchResult {
|
||||
id: number;
|
||||
title?: string; // 电影
|
||||
@@ -30,7 +33,8 @@ export async function searchTMDB(
|
||||
apiKey: string,
|
||||
query: string,
|
||||
proxy?: string,
|
||||
year?: number
|
||||
year?: number,
|
||||
reverseProxyBaseUrl?: string
|
||||
): Promise<{ code: number; result: TMDBSearchResult | null }> {
|
||||
try {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
@@ -38,8 +42,9 @@ export async function searchTMDB(
|
||||
return { code: 400, result: null };
|
||||
}
|
||||
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
// 使用 multi search 同时搜索电影和电视剧
|
||||
let url = `https://api.themoviedb.org/3/search/multi?api_key=${actualKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
let url = `${baseUrl}/3/search/multi?api_key=${actualKey}&language=zh-CN&query=${encodeURIComponent(query)}&page=1`;
|
||||
|
||||
// 如果提供了年份,添加到搜索参数中
|
||||
if (year) {
|
||||
@@ -120,7 +125,8 @@ interface TMDBTVDetails {
|
||||
export async function getTVSeasons(
|
||||
apiKey: string,
|
||||
tvId: number,
|
||||
proxy?: string
|
||||
proxy?: string,
|
||||
reverseProxyBaseUrl?: string
|
||||
): Promise<{ code: number; seasons: TMDBSeasonInfo[] | null }> {
|
||||
try {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
@@ -128,7 +134,8 @@ export async function getTVSeasons(
|
||||
return { code: 400, seasons: null };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}?api_key=${actualKey}&language=zh-CN`;
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/3/tv/${tvId}?api_key=${actualKey}&language=zh-CN`;
|
||||
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
@@ -171,7 +178,8 @@ export async function getTVSeasonDetails(
|
||||
apiKey: string,
|
||||
tvId: number,
|
||||
seasonNumber: number,
|
||||
proxy?: string
|
||||
proxy?: string,
|
||||
reverseProxyBaseUrl?: string
|
||||
): Promise<{ code: number; season: TMDBSeasonInfo | null }> {
|
||||
try {
|
||||
const actualKey = getNextApiKey(apiKey);
|
||||
@@ -179,7 +187,8 @@ export async function getTVSeasonDetails(
|
||||
return { code: 400, season: null };
|
||||
}
|
||||
|
||||
const url = `https://api.themoviedb.org/3/tv/${tvId}/season/${seasonNumber}?api_key=${actualKey}&language=zh-CN`;
|
||||
const baseUrl = reverseProxyBaseUrl || DEFAULT_TMDB_BASE_URL;
|
||||
const url = `${baseUrl}/3/tv/${tvId}/season/${seasonNumber}?api_key=${actualKey}&language=zh-CN`;
|
||||
|
||||
const fetchOptions: any = proxy
|
||||
? {
|
||||
|
||||
@@ -46,7 +46,19 @@ export function processImageUrl(originalUrl: string): string {
|
||||
return originalUrl;
|
||||
}
|
||||
|
||||
// 仅处理豆瓣图片代理
|
||||
// 处理 TMDB 图片 URL 替换
|
||||
if (originalUrl.includes('image.tmdb.org')) {
|
||||
if (typeof window !== 'undefined') {
|
||||
const tmdbImageBaseUrl = localStorage.getItem('tmdbImageBaseUrl') || 'https://image.tmdb.org';
|
||||
// 只有当用户设置了不同的 baseUrl 时才进行替换
|
||||
if (tmdbImageBaseUrl !== 'https://image.tmdb.org') {
|
||||
return originalUrl.replace('https://image.tmdb.org', tmdbImageBaseUrl);
|
||||
}
|
||||
}
|
||||
return originalUrl;
|
||||
}
|
||||
|
||||
// 处理豆瓣图片代理
|
||||
if (!originalUrl.includes('doubanio.com')) {
|
||||
return originalUrl;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,8 @@ export async function getXiaoyaMetadata(
|
||||
xiaoyaClient: XiaoyaClient,
|
||||
videoPath: string,
|
||||
tmdbApiKey?: string,
|
||||
tmdbProxy?: string
|
||||
tmdbProxy?: string,
|
||||
tmdbReverseProxy?: string
|
||||
): Promise<XiaoyaMetadata> {
|
||||
const pathParts = videoPath.split('/').filter(Boolean);
|
||||
|
||||
@@ -216,7 +217,7 @@ export async function getXiaoyaMetadata(
|
||||
|
||||
if (!isPureNumber && !isSeasonEpisode) {
|
||||
const { searchTMDB, getTMDBImageUrl } = await import('./tmdb.search');
|
||||
const tmdbResult = await searchTMDB(tmdbApiKey, searchQuery, tmdbProxy);
|
||||
const tmdbResult = await searchTMDB(tmdbApiKey, searchQuery, tmdbProxy, undefined, tmdbReverseProxy);
|
||||
|
||||
if (tmdbResult.code === 200 && tmdbResult.result) {
|
||||
return {
|
||||
@@ -244,7 +245,7 @@ export async function getXiaoyaMetadata(
|
||||
.trim();
|
||||
|
||||
const { searchTMDB, getTMDBImageUrl } = await import('./tmdb.search');
|
||||
const tmdbResult = await searchTMDB(tmdbApiKey, searchQuery, tmdbProxy);
|
||||
const tmdbResult = await searchTMDB(tmdbApiKey, searchQuery, tmdbProxy, undefined, tmdbReverseProxy);
|
||||
|
||||
if (tmdbResult.code === 200 && tmdbResult.result) {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user