fix(player):修复直链播放m3u8时跨域错误及分片加载失败的问题

This commit is contained in:
Troray
2026-03-10 17:28:48 +08:00
parent cdeddd48c1
commit 3563d80510
3 changed files with 1818 additions and 1790 deletions

View File

@@ -1,4 +1,4 @@
import { NextResponse } from 'next/server';
import { NextRequest, NextResponse } from 'next/server';
import { getConfig } from '@/lib/config';
@@ -9,7 +9,7 @@ export const runtime = 'nodejs';
* 用于外部播放器访问,会执行去广告逻辑并处理相对链接
* GET /api/proxy-m3u8?url=<原始m3u8地址>&source=<播放源>&token=<鉴权token>
*/
export async function GET(request: Request) {
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const m3u8Url = searchParams.get('url');
@@ -38,8 +38,11 @@ export async function GET(request: Request) {
// 优先级SITE_BASE 环境变量 > 从请求头构建
let origin = process.env.SITE_BASE;
if (!origin) {
const requestUrl = new URL(request.url);
origin = `${requestUrl.protocol}//${requestUrl.host}`;
// 从请求头中获取 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');
origin = `${proto}://${host}`;
}
// 获取原始 m3u8 内容
@@ -196,10 +199,15 @@ function resolveM3u8Links(m3u8Content: string, baseUrl: string, source: string,
} else {
keyUri = new URL(keyUri, baseDir).href;
}
// 替换原来的 URI
line = line.replace(/URI="[^"]+"/, `URI="${keyUri}"`);
}
// 直链播放模式:通过代理访问密钥,避免 CORS 问题
if (source === 'directplay') {
keyUri = `${proxyOrigin}/api/proxy/vod/segment?url=${encodeURIComponent(keyUri)}&source=directplay`;
}
// 替换原来的 URI
line = line.replace(/URI="[^"]+"/, `URI="${keyUri}"`);
}
resolvedLines.push(line);
continue;
@@ -240,6 +248,9 @@ function resolveM3u8Links(m3u8Content: string, baseUrl: string, source: string,
if (isM3u8) {
const tokenParam = token ? `&token=${encodeURIComponent(token)}` : '';
url = `${proxyOrigin}/api/proxy-m3u8?url=${encodeURIComponent(url)}${source ? `&source=${encodeURIComponent(source)}` : ''}${tokenParam}`;
} else if (source === 'directplay') {
// 直链播放模式通过代理访问媒体分片ts/jpeg/png 等),避免 CORS 问题
url = `${proxyOrigin}/api/proxy/vod/segment?url=${encodeURIComponent(url)}&source=directplay`;
}
resolvedLines.push(url);

View File

@@ -19,16 +19,19 @@ export async function GET(request: Request) {
return NextResponse.json({ error: 'Missing source' }, { status: 400 });
}
// 检查该视频源是否启用了代理模式
const config = await getConfig();
const videoSource = config.SourceConfig?.find((s: any) => s.key === source);
// 直链播放模式:跳过源站配置检查,直接代理
if (source !== 'directplay') {
// 检查该视频源是否启用了代理模式
const config = await getConfig();
const videoSource = config.SourceConfig?.find((s: any) => s.key === source);
if (!videoSource) {
return NextResponse.json({ error: 'Source not found' }, { status: 404 });
}
if (!videoSource) {
return NextResponse.json({ error: 'Source not found' }, { status: 404 });
}
if (!videoSource.proxyMode) {
return NextResponse.json({ error: 'Proxy mode not enabled for this source' }, { status: 403 });
if (!videoSource.proxyMode) {
return NextResponse.json({ error: 'Proxy mode not enabled for this source' }, { status: 403 });
}
}
let response: Response | null = null;

File diff suppressed because it is too large Load Diff