增加轮播图数据源

This commit is contained in:
mtvpls
2025-12-27 22:08:23 +08:00
parent cd761d530c
commit 6a9777a7ca
5 changed files with 254 additions and 31 deletions

View File

@@ -43,6 +43,7 @@ export async function POST(request: NextRequest) {
DanmakuApiToken,
TMDBApiKey,
TMDBProxy,
BannerDataSource,
PansouApiUrl,
PansouUsername,
PansouPassword,
@@ -80,6 +81,7 @@ export async function POST(request: NextRequest) {
DanmakuApiToken: string;
TMDBApiKey?: string;
TMDBProxy?: string;
BannerDataSource?: string;
PansouApiUrl?: string;
PansouUsername?: string;
PansouPassword?: string;
@@ -120,6 +122,7 @@ export async function POST(request: NextRequest) {
typeof DanmakuApiToken !== 'string' ||
(TMDBApiKey !== undefined && typeof TMDBApiKey !== 'string') ||
(TMDBProxy !== undefined && typeof TMDBProxy !== 'string') ||
(BannerDataSource !== undefined && typeof BannerDataSource !== 'string') ||
typeof EnableComments !== 'boolean' ||
(CustomAdFilterCode !== undefined && typeof CustomAdFilterCode !== 'string') ||
(CustomAdFilterVersion !== undefined && typeof CustomAdFilterVersion !== 'number') ||
@@ -172,6 +175,7 @@ export async function POST(request: NextRequest) {
DanmakuApiToken,
TMDBApiKey,
TMDBProxy,
BannerDataSource,
PansouApiUrl,
PansouUsername,
PansouPassword,

View File

@@ -1,47 +1,210 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { NextResponse } from 'next/server';
import { getTMDBTrendingContent } from '@/lib/tmdb.client';
import { getConfig } from '@/lib/config';
// 缓存配置 - 服务器内存缓存3小时
const CACHE_DURATION = 3 * 60 * 60 * 1000; // 3小时
let cachedData: { data: any; timestamp: number } | null = null;
// 为不同数据源分别维护缓存
let tmdbCache: { data: any; timestamp: number } | null = null;
let txCache: { data: any; timestamp: number } | null = null;
export const dynamic = 'force-dynamic';
export async function GET() {
try {
// 检查缓存
if (cachedData && Date.now() - cachedData.timestamp < CACHE_DURATION) {
return NextResponse.json(cachedData.data);
}
// 获取配置
const config = await getConfig();
const apiKey = config.SiteConfig?.TMDBApiKey;
const proxy = config.SiteConfig?.TMDBProxy;
const bannerDataSource = config.SiteConfig?.BannerDataSource || 'TMDB';
if (!apiKey) {
return NextResponse.json(
{ code: 400, message: 'TMDB API Key 未配置' },
{ status: 400 }
);
// 根据数据源选择对应的缓存
const cache = bannerDataSource === 'TX' ? txCache : tmdbCache;
// 检查缓存
if (cache && Date.now() - cache.timestamp < CACHE_DURATION) {
return NextResponse.json(cache.data);
}
// 获取热门内容
const result = await getTMDBTrendingContent(apiKey, proxy);
let result;
// 更新缓存
cachedData = {
data: result,
timestamp: Date.now(),
};
// 根据配置的数据源获取数据
if (bannerDataSource === 'TX') {
// 使用TX数据源
result = await getTXBannerContent();
// 更新TX缓存
txCache = {
data: result,
timestamp: Date.now(),
};
} else {
// 使用TMDB数据源默认
const apiKey = config.SiteConfig?.TMDBApiKey;
const proxy = config.SiteConfig?.TMDBProxy;
if (!apiKey) {
return NextResponse.json(
{ code: 400, message: 'TMDB API Key 未配置' },
{ status: 400 }
);
}
// 获取热门内容
result = await getTMDBTrendingContent(apiKey, proxy);
// 更新TMDB缓存
tmdbCache = {
data: result,
timestamp: Date.now(),
};
}
return NextResponse.json(result);
} catch (error) {
console.error('获取 TMDB 热门内容失败:', error);
console.error('获取热门内容失败:', error);
return NextResponse.json(
{ code: 500, message: '获取热门内容失败' },
{ status: 500 }
);
}
}
/**
* 获取TX轮播图内容
*/
async function getTXBannerContent(): Promise<{ code: number; list: any[] }> {
try {
// TX API 配置
const txApiUrl = 'https://pbaccess.video.qq.com/trpc.vector_layout.page_view.PageService/getPage?video_appid=3000010&vversion_platform=2&vdevice_guid=a458b2024f8d6f14';
const requestBody = {
page_params: {
page_type: 'channel',
page_id: '100101',
scene: 'channel',
new_mark_label_enabled: '1',
vl_to_mvl: '',
free_watch_trans_info: '{"ad_frequency_control_time_list":{}}',
ad_exp_ids: '',
ams_cookies: 'lv_play_index=33; o_minduid=PBUiqKSklDHZsTs2JqmXhTsczQfz5uzY; appuser=CC19AC2067F39B71',
ad_trans_data: '{"ad_request_id":"uglfjd6-26n6yw4-gs9tlvy-k19l366","game_sessions":[]}',
skip_privacy_types: '0',
support_click_scan: '1',
},
page_bypass_params: {
params: {
platform_id: '2',
caller_id: '3000010',
data_mode: 'default',
user_mode: 'default',
specified_strategy: '',
page_type: 'channel',
page_id: '100101',
scene: 'channel',
new_mark_label_enabled: '1',
},
scene: 'channel',
app_version: '',
abtest_bypass_id: 'a458b2024f8d6f14',
},
page_context: null,
};
// 发送请求到TX API
const response = await fetch(txApiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(requestBody),
signal: AbortSignal.timeout(15000),
});
if (!response.ok) {
console.error('TX API 请求失败:', response.status, response.statusText);
return { code: response.status, list: [] };
}
const data = await response.json();
// 解析响应数据
const bannerItems = parseTXBannerData(data);
return {
code: 200,
list: bannerItems,
};
} catch (error) {
console.error('获取 TX 轮播图数据失败:', error);
return { code: 500, list: [] };
}
}
/**
* 解析TX API响应数据提取轮播图信息
*/
function parseTXBannerData(data: any): any[] {
try {
const cardList = data?.data?.CardList;
if (!Array.isArray(cardList)) {
return [];
}
// 找到类型为 pc_shelves 的卡片
const pcShelvesCard = cardList.find((card: any) => card.type === 'pc_shelves');
if (!pcShelvesCard) {
return [];
}
// 获取轮播图卡片列表
const cards = pcShelvesCard?.children_list?.list?.cards;
if (!Array.isArray(cards)) {
return [];
}
// 转换为统一格式
const bannerItems = cards
.filter((card: any) => card.params) // 只保留有params的卡片
.map((card: any, index: number) => {
const params = card.params;
// 获取标题优先使用title
const title = params.title || '';
// 获取子标题优先使用priority_sub_title其次rec_normal_reason
const subtitle = params.priority_sub_title || params.rec_normal_reason || '';
// 获取标签(用"|"分割)
const topicLabel = params.topic_label || '';
const tags = topicLabel ? topicLabel.split('|').filter(Boolean) : [];
// 获取背景图
const backdropPath = params.priority_image_url || '';
return {
id: index + 1, // 使用索引作为ID
title,
subtitle,
tags,
backdrop_path: backdropPath,
poster_path: backdropPath, // 使用相同的图片
release_date: '',
overview: subtitle,
vote_average: 0,
media_type: 'tv',
genre_ids: [],
};
})
.filter((item: any) => {
// 只保留有标题和背景图的项目
if (!item.title || !item.backdrop_path) return false;
// 剔除标题包含"免费合集"的数据
if (item.title.includes('免费合集')) return false;
return true;
});
return bannerItems;
} catch (error) {
console.error('解析 TX 轮播图数据失败:', error);
return [];
}
}