mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-05-21 05:27:29 +08:00
feat: fallback douban proxy
This commit is contained in:
@@ -1 +1 @@
|
|||||||
20250807215120
|
20250807220314
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
|
|
||||||
import { getCacheTime } from '@/lib/config';
|
import { getCacheTime } from '@/lib/config';
|
||||||
|
import { fetchDoubanData } from '@/lib/douban';
|
||||||
import { DoubanItem, DoubanResult } from '@/lib/types';
|
import { DoubanItem, DoubanResult } from '@/lib/types';
|
||||||
|
|
||||||
interface DoubanCategoryApiResponse {
|
interface DoubanCategoryApiResponse {
|
||||||
@@ -19,41 +20,6 @@ interface DoubanCategoryApiResponse {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchDoubanData(
|
|
||||||
url: string
|
|
||||||
): Promise<DoubanCategoryApiResponse> {
|
|
||||||
// 添加超时控制
|
|
||||||
const controller = new AbortController();
|
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
|
|
||||||
|
|
||||||
// 设置请求选项,包括信号和头部
|
|
||||||
const fetchOptions = {
|
|
||||||
signal: controller.signal,
|
|
||||||
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',
|
|
||||||
Referer: 'https://movie.douban.com/',
|
|
||||||
Accept: 'application/json, text/plain, */*',
|
|
||||||
Origin: 'https://movie.douban.com',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 尝试直接访问豆瓣API
|
|
||||||
const response = await fetch(url, fetchOptions);
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const runtime = 'edge';
|
export const runtime = 'edge';
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
@@ -99,7 +65,7 @@ export async function GET(request: Request) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 调用豆瓣 API
|
// 调用豆瓣 API
|
||||||
const doubanData = await fetchDoubanData(target);
|
const doubanData = await fetchDoubanData<DoubanCategoryApiResponse>(target);
|
||||||
|
|
||||||
// 转换数据格式
|
// 转换数据格式
|
||||||
const list: DoubanItem[] = doubanData.items.map((item) => ({
|
const list: DoubanItem[] = doubanData.items.map((item) => ({
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
|
|
||||||
import { getCacheTime } from '@/lib/config';
|
import { getCacheTime } from '@/lib/config';
|
||||||
|
import { fetchDoubanData } from '@/lib/douban';
|
||||||
import { DoubanItem, DoubanResult } from '@/lib/types';
|
import { DoubanItem, DoubanResult } from '@/lib/types';
|
||||||
|
|
||||||
interface DoubanApiResponse {
|
interface DoubanApiResponse {
|
||||||
@@ -12,38 +13,6 @@ interface DoubanApiResponse {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchDoubanData(url: string): Promise<DoubanApiResponse> {
|
|
||||||
// 添加超时控制
|
|
||||||
const controller = new AbortController();
|
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
|
|
||||||
|
|
||||||
// 设置请求选项,包括信号和头部
|
|
||||||
const fetchOptions = {
|
|
||||||
signal: controller.signal,
|
|
||||||
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',
|
|
||||||
Referer: 'https://movie.douban.com/',
|
|
||||||
Accept: 'application/json, text/plain, */*',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 尝试直接访问豆瓣API
|
|
||||||
const response = await fetch(url, fetchOptions);
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await response.json();
|
|
||||||
} catch (error) {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const runtime = 'edge';
|
export const runtime = 'edge';
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
export async function GET(request: Request) {
|
||||||
@@ -92,7 +61,7 @@ export async function GET(request: Request) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// 调用豆瓣 API
|
// 调用豆瓣 API
|
||||||
const doubanData = await fetchDoubanData(target);
|
const doubanData = await fetchDoubanData<DoubanApiResponse>(target);
|
||||||
|
|
||||||
// 转换数据格式
|
// 转换数据格式
|
||||||
const list: DoubanItem[] = doubanData.subjects.map((item) => ({
|
const list: DoubanItem[] = doubanData.subjects.map((item) => ({
|
||||||
|
|||||||
52
src/lib/douban.ts
Normal file
52
src/lib/douban.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* 通用的豆瓣数据获取函数
|
||||||
|
* @param url 请求的URL
|
||||||
|
* @returns Promise<T> 返回指定类型的数据
|
||||||
|
*/
|
||||||
|
export async function fetchDoubanData<T>(url: string): Promise<T> {
|
||||||
|
// 添加超时控制
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10秒超时
|
||||||
|
|
||||||
|
// 设置请求选项,包括信号和头部
|
||||||
|
const fetchOptions = {
|
||||||
|
signal: controller.signal,
|
||||||
|
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',
|
||||||
|
Referer: 'https://movie.douban.com/',
|
||||||
|
Accept: 'application/json, text/plain, */*',
|
||||||
|
Origin: 'https://movie.douban.com',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 尝试直接访问豆瓣API
|
||||||
|
const response = await fetch(url, fetchOptions);
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
const fallbackUrl = `https://api.allorigins.win/get?url=${encodeURIComponent(
|
||||||
|
url
|
||||||
|
)}`;
|
||||||
|
try {
|
||||||
|
const fallbackResponse = await fetch(fallbackUrl, fetchOptions);
|
||||||
|
if (!fallbackResponse.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${fallbackResponse.status}`);
|
||||||
|
}
|
||||||
|
const fallbackData = await fallbackResponse.json();
|
||||||
|
if (fallbackData && fallbackData.contents) {
|
||||||
|
return JSON.parse(fallbackData.contents);
|
||||||
|
}
|
||||||
|
throw new Error('Invalid fallback response');
|
||||||
|
} catch (fallbackError) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
throw fallbackError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
const CURRENT_VERSION = '20250807215120';
|
const CURRENT_VERSION = '20250807220314';
|
||||||
|
|
||||||
// 版本检查结果枚举
|
// 版本检查结果枚举
|
||||||
export enum UpdateStatus {
|
export enum UpdateStatus {
|
||||||
|
|||||||
Reference in New Issue
Block a user