增加tvbox订阅功能,自带去广告
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
import { getAuthInfoFromCookie } from '@/lib/auth';
|
||||
|
||||
export const runtime = 'nodejs';
|
||||
|
||||
/**
|
||||
* 获取TVBOX订阅配置
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
// 验证用户登录
|
||||
const authInfo = getAuthInfoFromCookie(request);
|
||||
if (!authInfo || !authInfo.username) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Unauthorized' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
// 检查是否开启订阅功能
|
||||
const enableSubscribe = process.env.ENABLE_TVBOX_SUBSCRIBE === 'true';
|
||||
const subscribeToken = process.env.TVBOX_SUBSCRIBE_TOKEN;
|
||||
|
||||
if (!enableSubscribe || !subscribeToken) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
enabled: false,
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Cache-Control': 'no-store',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// 构建订阅链接
|
||||
// 优先使用 SITE_BASE 环境变量,如果没有则使用前端传来的 origin
|
||||
const siteBase = process.env.SITE_BASE;
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const clientOrigin = searchParams.get('origin');
|
||||
const adFilter = searchParams.get('adFilter') === 'true'; // 获取去广告参数
|
||||
|
||||
const baseUrl = siteBase || clientOrigin || request.nextUrl.origin;
|
||||
|
||||
// 构建订阅链接,包含 adFilter 参数
|
||||
const subscribeUrl = `${baseUrl}/api/tvbox/subscribe?token=${encodeURIComponent(subscribeToken)}&adFilter=${adFilter}`;
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
enabled: true,
|
||||
url: subscribeUrl,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Cache-Control': 'no-store',
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
import { getAuthInfoFromCookie } from '@/lib/auth';
|
||||
import { getAvailableApiSites, getConfig } from '@/lib/config';
|
||||
import { getCachedLiveChannels } from '@/lib/live';
|
||||
|
||||
export const runtime = 'nodejs';
|
||||
|
||||
/**
|
||||
* TVBOX订阅API
|
||||
* 根据视频源和直播源生成TVBOX订阅
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
// 检查是否开启订阅功能
|
||||
const enableSubscribe = process.env.ENABLE_TVBOX_SUBSCRIBE === 'true';
|
||||
if (!enableSubscribe) {
|
||||
return NextResponse.json(
|
||||
{ error: '订阅功能未开启' },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
// 验证token
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const token = searchParams.get('token');
|
||||
const subscribeToken = process.env.TVBOX_SUBSCRIBE_TOKEN;
|
||||
const adFilter = searchParams.get('adFilter') === 'true'; // 获取去广告参数
|
||||
|
||||
if (!subscribeToken || token !== subscribeToken) {
|
||||
return NextResponse.json(
|
||||
{ error: '无效的订阅token' },
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取用户信息
|
||||
const authInfo = getAuthInfoFromCookie(request);
|
||||
const username = authInfo?.username;
|
||||
|
||||
// 获取配置
|
||||
const config = await getConfig();
|
||||
|
||||
// 获取视频源
|
||||
const apiSites = await getAvailableApiSites(username);
|
||||
|
||||
// 获取直播源
|
||||
const liveConfig = config.LiveConfig?.filter(live => !live.disabled) || [];
|
||||
|
||||
// 获取当前请求的 origin,用于构建代理链接
|
||||
// 优先级:SITE_BASE 环境变量 > origin 参数 > 从请求头构建
|
||||
let baseUrl = process.env.SITE_BASE || searchParams.get('origin');
|
||||
|
||||
if (!baseUrl) {
|
||||
// 从请求头中获取 Host 和协议
|
||||
const host = request.headers.get('host') || request.headers.get('x-forwarded-host');
|
||||
const proto = request.headers.get('x-forwarded-proto') ||
|
||||
(host?.includes('localhost') || host?.includes('127.0.0.1') ? 'http' : 'https');
|
||||
baseUrl = `${proto}://${host}`;
|
||||
}
|
||||
|
||||
console.log('TVBOX 订阅 baseUrl:', baseUrl, 'adFilter:', adFilter);
|
||||
|
||||
// 构建TVBOX订阅数据
|
||||
const tvboxSubscription = {
|
||||
// 站点配置
|
||||
spider: '',
|
||||
wallpaper: '',
|
||||
|
||||
// 视频源站点 - 根据 adFilter 参数决定是否使用代理
|
||||
sites: apiSites.map(site => ({
|
||||
key: site.key,
|
||||
name: site.name,
|
||||
type: 1,
|
||||
// 如果开启去广告,使用 CMS 代理;否则使用原始 API
|
||||
api: adFilter
|
||||
? `${baseUrl}/api/cms-proxy?api=${encodeURIComponent(site.api)}`
|
||||
: site.api,
|
||||
searchable: 1,
|
||||
quickSearch: 1,
|
||||
filterable: 1,
|
||||
ext: site.detail || '',
|
||||
})),
|
||||
|
||||
// 直播源
|
||||
lives: await Promise.all(
|
||||
liveConfig.map(async (live) => {
|
||||
try {
|
||||
const liveChannels = await getCachedLiveChannels(live.key);
|
||||
return {
|
||||
name: live.name,
|
||||
type: 0,
|
||||
url: live.url,
|
||||
epg: live.epg || (liveChannels?.epgUrl || ''),
|
||||
logo: '',
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
name: live.name,
|
||||
type: 0,
|
||||
url: live.url,
|
||||
epg: live.epg || '',
|
||||
logo: '',
|
||||
};
|
||||
}
|
||||
})
|
||||
),
|
||||
|
||||
// 解析器
|
||||
parses: [],
|
||||
|
||||
// 规则
|
||||
rules: [],
|
||||
|
||||
// 广告配置
|
||||
ads: [],
|
||||
};
|
||||
|
||||
return NextResponse.json(tvboxSubscription, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('生成TVBOX订阅失败:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: '生成订阅失败',
|
||||
details: (error as Error).message,
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user