调整视频源脚本播放流程
This commit is contained in:
@@ -6,7 +6,6 @@ import { getDetailFromApi } from '@/lib/downstream';
|
||||
import {
|
||||
executeSavedSourceScript,
|
||||
normalizeScriptDetailResult,
|
||||
resolveScriptDetailPlaybacks,
|
||||
normalizeScriptSources,
|
||||
parseScriptSourceValue,
|
||||
} from '@/lib/source-script';
|
||||
@@ -51,12 +50,6 @@ export async function GET(request: NextRequest) {
|
||||
},
|
||||
});
|
||||
|
||||
const resolvedDetailResult = await resolveScriptDetailPlaybacks({
|
||||
scriptKey: parsedScriptSource.scriptKey,
|
||||
sourceId: parsedScriptSource.sourceId,
|
||||
result: detailExecution.result,
|
||||
});
|
||||
|
||||
const normalized = normalizeScriptDetailResult({
|
||||
source: sourceCode,
|
||||
scriptKey: parsedScriptSource.scriptKey,
|
||||
@@ -64,7 +57,7 @@ export async function GET(request: NextRequest) {
|
||||
sourceId: parsedScriptSource.sourceId,
|
||||
sourceName: sourceInfo.name,
|
||||
detailId: id,
|
||||
result: resolvedDetailResult,
|
||||
result: detailExecution.result,
|
||||
});
|
||||
|
||||
return NextResponse.json(normalized);
|
||||
|
||||
@@ -9,7 +9,6 @@ import { getProxyToken } from '@/lib/emby-token';
|
||||
import {
|
||||
executeSavedSourceScript,
|
||||
normalizeScriptDetailResult,
|
||||
resolveScriptDetailPlaybacks,
|
||||
normalizeScriptSources,
|
||||
parseScriptSourceValue,
|
||||
} from '@/lib/source-script';
|
||||
@@ -59,12 +58,6 @@ export async function GET(request: NextRequest) {
|
||||
},
|
||||
});
|
||||
|
||||
const resolvedDetailResult = await resolveScriptDetailPlaybacks({
|
||||
scriptKey: parsedScriptSource.scriptKey,
|
||||
sourceId: parsedScriptSource.sourceId,
|
||||
result: detailExecution.result,
|
||||
});
|
||||
|
||||
const normalized = normalizeScriptDetailResult({
|
||||
source: sourceCode,
|
||||
scriptKey: parsedScriptSource.scriptKey,
|
||||
@@ -72,7 +65,7 @@ export async function GET(request: NextRequest) {
|
||||
sourceId: parsedScriptSource.sourceId,
|
||||
sourceName: sourceInfo.name,
|
||||
detailId: id,
|
||||
result: resolvedDetailResult,
|
||||
result: detailExecution.result,
|
||||
});
|
||||
|
||||
return NextResponse.json(normalized);
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
import { getAuthInfoFromCookie } from '@/lib/auth';
|
||||
import {
|
||||
parseScriptPlayUrlValue,
|
||||
resolveSavedScriptPlayUrl,
|
||||
} from '@/lib/source-script';
|
||||
|
||||
export const runtime = 'nodejs';
|
||||
|
||||
/**
|
||||
* GET /api/source-script/play?key=xxx&sourceId=xxx&lineId=xxx&episodeIndex=0&playUrl=base64url&format=json
|
||||
* format=json: 返回 JSON 格式(用于 play 页面)
|
||||
* 默认: 返回重定向(用于播放器或外部调用)
|
||||
*/
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const authInfo = getAuthInfoFromCookie(request);
|
||||
if (!authInfo || !authInfo.username) {
|
||||
return NextResponse.json({ error: '未授权' }, { status: 401 });
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const key = searchParams.get('key');
|
||||
const sourceId = searchParams.get('sourceId');
|
||||
const lineId = searchParams.get('lineId') || 'default';
|
||||
const episodeIndexRaw = searchParams.get('episodeIndex');
|
||||
const playUrlEncoded = searchParams.get('playUrl');
|
||||
const format = searchParams.get('format');
|
||||
|
||||
if (!key || !sourceId || !episodeIndexRaw || !playUrlEncoded) {
|
||||
return NextResponse.json({ error: '缺少参数' }, { status: 400 });
|
||||
}
|
||||
|
||||
const episodeIndex = Number.parseInt(episodeIndexRaw, 10);
|
||||
if (!Number.isInteger(episodeIndex) || episodeIndex < 0) {
|
||||
return NextResponse.json({ error: '无效的 episodeIndex' }, { status: 400 });
|
||||
}
|
||||
|
||||
const playUrl = parseScriptPlayUrlValue(playUrlEncoded);
|
||||
if (!playUrl) {
|
||||
return NextResponse.json({ error: '无效的播放地址' }, { status: 400 });
|
||||
}
|
||||
|
||||
const result = await resolveSavedScriptPlayUrl({
|
||||
key,
|
||||
sourceId,
|
||||
lineId,
|
||||
episodeIndex,
|
||||
playUrl,
|
||||
});
|
||||
|
||||
if (!result.url || result.url.trim() === '') {
|
||||
throw new Error('获取到的播放链接为空');
|
||||
}
|
||||
|
||||
if (format === 'json') {
|
||||
return NextResponse.json(result);
|
||||
}
|
||||
|
||||
return NextResponse.redirect(result.url);
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ error: (error as Error).message },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
+72
-17
@@ -2127,10 +2127,17 @@ function PlayPageClient() {
|
||||
let newUrl = detailData?.episodes[episodeIndex] || '';
|
||||
|
||||
// 如果是小雅或 openlist 接口,先请求获取真实 URL
|
||||
if (newUrl.startsWith('/api/xiaoya/play') || newUrl.startsWith('/api/openlist/play')) {
|
||||
const isSpecialLazyPlayUrl =
|
||||
newUrl.startsWith('/api/xiaoya/play') ||
|
||||
newUrl.startsWith('/api/openlist/play') ||
|
||||
newUrl.startsWith('/api/source-script/play');
|
||||
|
||||
if (isSpecialLazyPlayUrl) {
|
||||
try {
|
||||
// 保存原始URL(用于后续刷新)
|
||||
currentXiaoyaUrlRef.current = newUrl;
|
||||
if (newUrl.startsWith('/api/xiaoya/play') || newUrl.startsWith('/api/openlist/play')) {
|
||||
currentXiaoyaUrlRef.current = newUrl;
|
||||
}
|
||||
|
||||
// 添加 format=json 参数
|
||||
const separator = newUrl.includes('?') ? '&' : '?';
|
||||
@@ -3247,6 +3254,42 @@ function PlayPageClient() {
|
||||
}
|
||||
};
|
||||
|
||||
const getCachedSourcesData = (query: string): SearchResult[] => {
|
||||
if (typeof window === 'undefined' || !query.trim()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const cacheKey = `search_cache_${query.trim()}`;
|
||||
const cached = sessionStorage.getItem(cacheKey);
|
||||
if (!cached) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const cachedData = JSON.parse(cached);
|
||||
const results = cachedData.filter(
|
||||
(result: SearchResult) =>
|
||||
normalizeTitle(result.title).toLowerCase() ===
|
||||
normalizeTitle(videoTitleRef.current).toLowerCase() &&
|
||||
(videoYearRef.current
|
||||
? result.year.toLowerCase() === videoYearRef.current.toLowerCase() ||
|
||||
!result.year ||
|
||||
result.year.trim() === '' ||
|
||||
result.year === 'unknown' ||
|
||||
!/^\d{4}$/.test(result.year)
|
||||
: true) &&
|
||||
(searchType
|
||||
? getType(result) === searchType
|
||||
: true)
|
||||
);
|
||||
|
||||
return applyCorrectionsToSources(results);
|
||||
} catch (error) {
|
||||
console.error('[Play] 读取缓存失败:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const initAll = async () => {
|
||||
if (currentSource === 'directplay') {
|
||||
if (!currentId) {
|
||||
@@ -3333,22 +3376,34 @@ function PlayPageClient() {
|
||||
let sourcesInfo: SearchResult[] = [];
|
||||
|
||||
if (currentSource && currentId) {
|
||||
// 先快速获取当前源的详情
|
||||
try {
|
||||
// currentSource 已经是完整格式(如 'emby_wumei')
|
||||
// 如果是小雅源且有fileName参数,传递给API
|
||||
const currentSourceDetail = await fetchSourceDetail(
|
||||
currentSource,
|
||||
currentId,
|
||||
searchTitle || videoTitle,
|
||||
currentSource === 'xiaoya' ? fileName : undefined
|
||||
);
|
||||
if (currentSourceDetail.length > 0) {
|
||||
detailData = currentSourceDetail[0];
|
||||
sourcesInfo = currentSourceDetail;
|
||||
const cachedSources = getCachedSourcesData(searchTitle || videoTitle);
|
||||
const cachedTarget = cachedSources.find(
|
||||
(source) => source.source === currentSource && source.id === currentId
|
||||
);
|
||||
|
||||
if (cachedTarget?.episodes?.length) {
|
||||
detailData = cachedTarget;
|
||||
sourcesInfo = cachedSources;
|
||||
setAvailableSources(cachedSources);
|
||||
setSourceSearchLoading(false);
|
||||
} else {
|
||||
// 先快速获取当前源的详情
|
||||
try {
|
||||
// currentSource 已经是完整格式(如 'emby_wumei')
|
||||
// 如果是小雅源且有fileName参数,传递给API
|
||||
const currentSourceDetail = await fetchSourceDetail(
|
||||
currentSource,
|
||||
currentId,
|
||||
searchTitle || videoTitle,
|
||||
currentSource === 'xiaoya' ? fileName : undefined
|
||||
);
|
||||
if (currentSourceDetail.length > 0) {
|
||||
detailData = currentSourceDetail[0];
|
||||
sourcesInfo = currentSourceDetail;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取当前源详情失败:', err);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取当前源详情失败:', err);
|
||||
}
|
||||
|
||||
// 异步获取其他源信息,不阻塞播放
|
||||
|
||||
Reference in New Issue
Block a user