镜像自地址
https://github.com/lhly/cloud-drive-renamer.git
已同步 2026-10-20 05:37:47 +08:00
feat(baidu-adapter): 支持/api/list顶层list响应结构并修复文件列表解析
修改BaiduAdapter以兼容不同API响应结构,当list字段在顶层时也能正确解析 修复parentId使用目标路径而非文件路径的问题 添加相关单元测试验证功能
这个提交包含在:
父节点
a796eca950
当前提交
e718b43757
@ -14,6 +14,8 @@ interface BaiduAPIResponse<T = any> {
|
|||||||
request_id?: number;
|
request_id?: number;
|
||||||
taskid?: number;
|
taskid?: number;
|
||||||
data?: T;
|
data?: T;
|
||||||
|
// Some endpoints (e.g. /api/list) return `list` at top-level instead of inside `data`.
|
||||||
|
list?: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,12 +189,15 @@ export class BaiduAdapter extends BasePlatformAdapter {
|
|||||||
|
|
||||||
const result: BaiduAPIResponse<{ list: BaiduFileListItem[] }> = await response.json();
|
const result: BaiduAPIResponse<{ list: BaiduFileListItem[] }> = await response.json();
|
||||||
|
|
||||||
if (result.errno !== 0 || !result.data?.list) {
|
if (result.errno !== 0) {
|
||||||
const errorMsg = getErrorMessage(result.errno);
|
const errorMsg = getErrorMessage(result.errno);
|
||||||
throw new BaiduAPIError(result.errno, errorMsg, result);
|
throw new BaiduAPIError(result.errno, errorMsg, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageFiles = result.data.list;
|
const pageFiles = (result.data?.list ?? result.list) as BaiduFileListItem[] | undefined;
|
||||||
|
if (!Array.isArray(pageFiles)) {
|
||||||
|
throw new Error('无法解析文件列表响应');
|
||||||
|
}
|
||||||
|
|
||||||
// Filter out folders (only return files, isdir === 0)
|
// Filter out folders (only return files, isdir === 0)
|
||||||
const files = pageFiles
|
const files = pageFiles
|
||||||
@ -203,7 +208,7 @@ export class BaiduAdapter extends BasePlatformAdapter {
|
|||||||
id: String(file.fs_id),
|
id: String(file.fs_id),
|
||||||
name: file.server_filename,
|
name: file.server_filename,
|
||||||
ext: ext,
|
ext: ext,
|
||||||
parentId: file.path || targetPath,
|
parentId: targetPath,
|
||||||
size: file.size,
|
size: file.size,
|
||||||
mtime: file.server_mtime ? file.server_mtime * 1000 : Date.now(),
|
mtime: file.server_mtime ? file.server_mtime * 1000 : Date.now(),
|
||||||
};
|
};
|
||||||
@ -332,11 +337,16 @@ export class BaiduAdapter extends BasePlatformAdapter {
|
|||||||
|
|
||||||
const result: BaiduAPIResponse<{ list: BaiduFileListItem[] }> = await response.json();
|
const result: BaiduAPIResponse<{ list: BaiduFileListItem[] }> = await response.json();
|
||||||
|
|
||||||
if (result.errno === 0 && result.data?.list) {
|
if (result.errno !== 0) {
|
||||||
return result.data.list.some(file => file.server_filename === fileName);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
const list = (result.data?.list ?? result.list) as BaiduFileListItem[] | undefined;
|
||||||
|
if (!Array.isArray(list)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.some(file => file.server_filename === fileName);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to check name conflict:', error instanceof Error ? error : new Error(String(error)));
|
logger.error('Failed to check name conflict:', error instanceof Error ? error : new Error(String(error)));
|
||||||
return true; // Conservative on error
|
return true; // Conservative on error
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
* 1. Edit version in package.json
|
* 1. Edit version in package.json
|
||||||
* 2. Run: npm run sync:version (or automatically via prebuild/predev)
|
* 2. Run: npm run sync:version (or automatically via prebuild/predev)
|
||||||
*
|
*
|
||||||
* Generated at: 2025-12-29T09:42:53.807Z
|
* Generated at: 2025-12-29T10:25:00.256Z
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -0,0 +1,66 @@
|
|||||||
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||||
|
import { BaiduAdapter } from '../../../src/adapters/baidu/baidu-adapter';
|
||||||
|
|
||||||
|
describe('BaiduAdapter', () => {
|
||||||
|
let adapter: BaiduAdapter;
|
||||||
|
let mockFetch: any;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
adapter = new BaiduAdapter({ requestInterval: 0 });
|
||||||
|
|
||||||
|
// Mock global fetch used by BasePlatformAdapter.fetchWithTimeout
|
||||||
|
mockFetch = vi.fn();
|
||||||
|
global.fetch = mockFetch;
|
||||||
|
|
||||||
|
// Avoid relying on MAIN-world injector in unit tests
|
||||||
|
vi.spyOn(adapter as any, 'extractBdstoken').mockResolvedValue('mock-token');
|
||||||
|
vi.spyOn(adapter as any, 'rateLimit').mockResolvedValue(undefined);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getAllFiles', () => {
|
||||||
|
it('应该支持 /api/list 顶层 list 响应结构(errno=0)', async () => {
|
||||||
|
mockFetch.mockResolvedValue({
|
||||||
|
json: async () => ({
|
||||||
|
errno: 0,
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
path: '/test/a.txt',
|
||||||
|
server_filename: 'a.txt',
|
||||||
|
fs_id: 1,
|
||||||
|
md5: 'x',
|
||||||
|
isdir: 0,
|
||||||
|
size: 10,
|
||||||
|
server_mtime: 1700000000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/test/folder',
|
||||||
|
server_filename: 'folder',
|
||||||
|
fs_id: 2,
|
||||||
|
md5: 'y',
|
||||||
|
isdir: 1,
|
||||||
|
size: 0,
|
||||||
|
server_mtime: 1700000001,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const files = await adapter.getAllFiles('/test');
|
||||||
|
|
||||||
|
expect(files).toHaveLength(1);
|
||||||
|
expect(files[0]).toEqual({
|
||||||
|
id: '1',
|
||||||
|
name: 'a.txt',
|
||||||
|
ext: '.txt',
|
||||||
|
parentId: '/test',
|
||||||
|
size: 10,
|
||||||
|
mtime: 1700000000 * 1000,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
正在加载...
在新工单中引用
屏蔽一个用户