重复转存校验
This commit is contained in:
@@ -168,11 +168,18 @@ export async function GET(request: NextRequest) {
|
||||
throw new Error('未找到已完成的播放链接');
|
||||
}
|
||||
|
||||
// 如果指定了 format=json,返回 JSON 格式
|
||||
// 如果指定了 format=json,尝试解析到最终直链后再返回 JSON
|
||||
if (format === 'json') {
|
||||
const resolvedQualities = await Promise.all(
|
||||
qualities.map(async (quality: any) => ({
|
||||
...quality,
|
||||
url: await getFinalUrl(quality.url),
|
||||
}))
|
||||
);
|
||||
|
||||
return NextResponse.json({
|
||||
url: qualities[0].url,
|
||||
qualities
|
||||
url: resolvedQualities[0].url,
|
||||
qualities: resolvedQualities,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,26 @@ export async function POST(request: NextRequest) {
|
||||
result.folderName
|
||||
);
|
||||
|
||||
if (
|
||||
config.OpenListConfig?.Enabled &&
|
||||
config.OpenListConfig.URL &&
|
||||
config.OpenListConfig.Username &&
|
||||
config.OpenListConfig.Password
|
||||
) {
|
||||
try {
|
||||
const { OpenListClient } = await import('@/lib/openlist.client');
|
||||
const openListClient = new OpenListClient(
|
||||
config.OpenListConfig.URL,
|
||||
config.OpenListConfig.Username,
|
||||
config.OpenListConfig.Password
|
||||
);
|
||||
await openListClient.refreshDirectory(quarkConfig.OpenListTempPath || '/');
|
||||
await openListClient.refreshDirectory(openlistFolderPath);
|
||||
} catch (refreshError) {
|
||||
console.warn('[quark instant-play] 刷新 OpenList 临时目录失败:', refreshError);
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
source: 'quark-temp',
|
||||
|
||||
@@ -307,6 +307,26 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
const videoExtensions = ['.mp4', '.mkv', '.avi', '.m3u8', '.flv', '.ts', '.mov', '.wmv', '.webm', '.rmvb', '.rm', '.mpg', '.mpeg', '.3gp', '.f4v', '.m4v', '.vob'];
|
||||
|
||||
const listTempDirectory = async (currentPath: string, page: number, pageSize: number) => {
|
||||
const load = async (refresh = false) => client.listDirectory(currentPath, page, pageSize, refresh);
|
||||
|
||||
let response = await load(page === 1);
|
||||
if (response.code === 200) {
|
||||
return response;
|
||||
}
|
||||
|
||||
const parentPath = currentPath.substring(0, currentPath.lastIndexOf('/')) || '/';
|
||||
await client.refreshDirectory(parentPath);
|
||||
response = await load(true);
|
||||
|
||||
if (response.code !== 200) {
|
||||
const message = response.message || '目录不存在或 OpenList 路径未映射';
|
||||
throw new Error(`读取临时目录失败: ${message}(路径: ${currentPath})`);
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
const collectFiles = async (currentPath: string): Promise<Array<{ path: string; name: string }>> => {
|
||||
const allFiles: Array<{ path: string; name: string }> = [];
|
||||
let currentPage = 1;
|
||||
@@ -314,10 +334,7 @@ export async function GET(request: NextRequest) {
|
||||
let hasMore = true;
|
||||
|
||||
while (hasMore) {
|
||||
const response = await client.listDirectory(currentPath, currentPage, pageSize);
|
||||
if (response.code !== 200) {
|
||||
throw new Error('读取临时目录失败');
|
||||
}
|
||||
const response = await listTempDirectory(currentPath, currentPage, pageSize);
|
||||
|
||||
for (const item of response.data.content) {
|
||||
const itemPath = `${currentPath}${currentPath.endsWith('/') ? '' : '/'}${item.name}`;
|
||||
|
||||
+75
-7
@@ -22,6 +22,8 @@ export interface QuarkTransferTaskResult {
|
||||
fileCount: number;
|
||||
targetPath: string;
|
||||
folderName?: string;
|
||||
skipped?: boolean;
|
||||
reused?: boolean;
|
||||
}
|
||||
|
||||
const VIDEO_EXTENSIONS = [
|
||||
@@ -208,12 +210,14 @@ async function fetchShareFolderItems(
|
||||
|
||||
async function fetchDriveFolderItems(
|
||||
cookie: string,
|
||||
pdirFid = '0'
|
||||
pdirFid = '0',
|
||||
page = 1,
|
||||
size = 200
|
||||
): Promise<any[]> {
|
||||
const query = new URLSearchParams({
|
||||
pdir_fid: pdirFid,
|
||||
_page: '1',
|
||||
_size: '200',
|
||||
_page: String(page),
|
||||
_size: String(size),
|
||||
_sort: 'file_type:asc,file_name:asc',
|
||||
});
|
||||
|
||||
@@ -230,6 +234,45 @@ async function fetchDriveFolderItems(
|
||||
return data?.data?.list || [];
|
||||
}
|
||||
|
||||
async function fetchAllDriveFolderItems(
|
||||
cookie: string,
|
||||
pdirFid = '0'
|
||||
): Promise<any[]> {
|
||||
const allItems: any[] = [];
|
||||
const pageSize = 200;
|
||||
|
||||
for (let page = 1; page < 100; page += 1) {
|
||||
const items = await fetchDriveFolderItems(cookie, pdirFid, page, pageSize);
|
||||
allItems.push(...items);
|
||||
|
||||
if (items.length < pageSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return allItems;
|
||||
}
|
||||
|
||||
function getDriveItemName(item: any): string {
|
||||
return String(item?.file_name || item?.name || '');
|
||||
}
|
||||
|
||||
function buildInstantPlayFolderName(pwdId: string, title?: string) {
|
||||
const baseName = sanitizeFolderName(title || 'quark-temp') || 'quark-temp';
|
||||
return `${baseName}_${pwdId}`.slice(0, 120);
|
||||
}
|
||||
|
||||
async function findDirectoryByName(
|
||||
cookie: string,
|
||||
parentFid: string,
|
||||
folderName: string
|
||||
): Promise<any | null> {
|
||||
const items = await fetchAllDriveFolderItems(cookie, parentFid);
|
||||
return items.find(
|
||||
(item: any) => Boolean(item.dir || item.is_dir) && getDriveItemName(item) === folderName
|
||||
) || null;
|
||||
}
|
||||
|
||||
export async function validateQuarkCookieReadable(cookie: string): Promise<void> {
|
||||
const safeCookie = assertQuarkCookieHeaderSafe(cookie);
|
||||
await fetchDriveFolderItems(safeCookie, '0');
|
||||
@@ -421,7 +464,19 @@ export async function transferQuarkShare(
|
||||
const { stoken } = await fetchShareToken(safeCookie, share);
|
||||
const topLevelItems = await fetchShareFolderItems(safeCookie, share.pwdId, stoken, '0');
|
||||
const target = await ensureQuarkDrivePath(safeCookie, input.savePath);
|
||||
const taskId = await submitSaveTask(safeCookie, share, stoken, target.fid, topLevelItems);
|
||||
const existedItems = await fetchAllDriveFolderItems(safeCookie, target.fid);
|
||||
const existedNames = new Set(existedItems.map((item: any) => getDriveItemName(item)));
|
||||
const pendingItems = topLevelItems.filter((item) => !existedNames.has(item.fileName));
|
||||
|
||||
if (pendingItems.length === 0) {
|
||||
return {
|
||||
fileCount: 0,
|
||||
targetPath: target.path,
|
||||
skipped: true,
|
||||
};
|
||||
}
|
||||
|
||||
const taskId = await submitSaveTask(safeCookie, share, stoken, target.fid, pendingItems);
|
||||
|
||||
if (taskId) {
|
||||
await pollTask(safeCookie, taskId);
|
||||
@@ -429,7 +484,7 @@ export async function transferQuarkShare(
|
||||
|
||||
return {
|
||||
taskId,
|
||||
fileCount: topLevelItems.length,
|
||||
fileCount: pendingItems.length,
|
||||
targetPath: target.path,
|
||||
};
|
||||
}
|
||||
@@ -454,7 +509,18 @@ export async function createQuarkInstantPlayFolder(
|
||||
}
|
||||
|
||||
const tempRoot = await ensureQuarkDrivePath(safeCookie, input.playTempSavePath);
|
||||
const folderName = `${sanitizeFolderName(input.title || shareTitle || 'quark-temp')}_${Date.now()}`;
|
||||
const folderName = buildInstantPlayFolderName(share.pwdId, input.title || shareTitle);
|
||||
const existedFolder = await findDirectoryByName(safeCookie, tempRoot.fid, folderName);
|
||||
|
||||
if (existedFolder) {
|
||||
return {
|
||||
fileCount: videoItems.length,
|
||||
targetPath: joinPath(tempRoot.path, folderName),
|
||||
folderName,
|
||||
reused: true,
|
||||
};
|
||||
}
|
||||
|
||||
const folderFid = await createDriveFolder(safeCookie, tempRoot.fid, folderName);
|
||||
const taskId = await submitSaveTask(safeCookie, share, stoken, folderFid, videoItems);
|
||||
|
||||
@@ -462,10 +528,12 @@ export async function createQuarkInstantPlayFolder(
|
||||
await pollTask(safeCookie, taskId);
|
||||
}
|
||||
|
||||
const targetPath = joinPath(tempRoot.path, folderName);
|
||||
|
||||
return {
|
||||
taskId,
|
||||
fileCount: videoItems.length,
|
||||
targetPath: joinPath(tempRoot.path, folderName),
|
||||
targetPath,
|
||||
folderName,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user