增加动漫数据源配置

This commit is contained in:
mtvpls
2026-05-28 16:00:07 +08:00
parent dc31a788fc
commit cc98b21d66
16 changed files with 4448 additions and 2153 deletions
+87 -8
View File
@@ -1,25 +1,103 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { HttpsProxyAgent } from 'https-proxy-agent';
import nodeFetch from 'node-fetch';
import { NextResponse } from 'next/server';
import { getConfig } from '@/lib/config';
export const runtime = 'nodejs';
function isCloudflareEnvironment(): boolean {
return (
process.env.CF_PAGES === '1' || process.env.BUILD_TARGET === 'cloudflare'
);
}
function normalizeBaseUrl(baseUrl: string): string {
return baseUrl.trim().replace(/\/+$/, '');
}
function applyBangumiImageBaseUrl(
imageUrl: string,
imageBaseUrl?: string
): string {
const normalizedBaseUrl = normalizeBaseUrl(imageBaseUrl || '');
if (!normalizedBaseUrl) {
return imageUrl;
}
if (imageUrl.startsWith(`${normalizedBaseUrl}/`)) {
return imageUrl;
}
return `${normalizedBaseUrl}/${imageUrl}`;
}
function isBangumiImageUrl(url: string): boolean {
try {
const hostname = new URL(url).hostname.toLowerCase();
return (
hostname === 'lain.bgm.tv' ||
hostname === 'r.bgm.tv' ||
hostname.endsWith('.bgm.tv') ||
hostname.endsWith('.bangumi.tv')
);
} catch {
return false;
}
}
async function fetchImage(
imageUrl: string,
options?: { source?: string }
): Promise<Response> {
const isBangumiImage =
options?.source === 'bangumi' || isBangumiImageUrl(imageUrl);
const headers = {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
Accept: 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
Referer: isBangumiImage ? 'https://bgm.tv/' : 'https://movie.douban.com/',
};
const config = isBangumiImage ? await getConfig() : null;
const targetUrl = isBangumiImage
? applyBangumiImageBaseUrl(imageUrl, config?.SiteConfig.BangumiImageBaseUrl)
: imageUrl;
if (!isBangumiImage || isCloudflareEnvironment()) {
return fetch(targetUrl, { headers, signal: AbortSignal.timeout(15000) });
}
const proxy = config?.SiteConfig.BangumiProxy?.trim();
const fetchOptions: any = {
headers,
signal: AbortSignal.timeout(proxy ? 30000 : 15000),
};
if (proxy) {
fetchOptions.agent = new HttpsProxyAgent(proxy, {
timeout: 30000,
keepAlive: false,
});
}
return nodeFetch(targetUrl, fetchOptions) as unknown as Promise<Response>;
}
// OrionTV 兼容接口
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const imageUrl = searchParams.get('url');
const source = searchParams.get('source') || undefined;
if (!imageUrl) {
return NextResponse.json({ error: 'Missing image URL' }, { status: 400 });
}
try {
const imageResponse = await fetch(imageUrl, {
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
Accept: 'image/jpeg,image/png,image/gif,*/*;q=0.8',
Referer: 'https://movie.douban.com/',
},
});
const imageResponse = await fetchImage(imageUrl, { source });
if (!imageResponse.ok) {
return NextResponse.json(
@@ -55,6 +133,7 @@ export async function GET(request: Request) {
headers,
});
} catch (error) {
console.error('图片代理请求失败:', error);
return NextResponse.json(
{ error: 'Error fetching image' },
{ status: 500 }