From e718b43757a231253858eb27224bb1856356ad43 Mon Sep 17 00:00:00 2001 From: Zain Date: Mon, 29 Dec 2025 18:29:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(baidu-adapter):=20=E6=94=AF=E6=8C=81/api/l?= =?UTF-8?q?ist=E9=A1=B6=E5=B1=82list=E5=93=8D=E5=BA=94=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E5=B9=B6=E4=BF=AE=E5=A4=8D=E6=96=87=E4=BB=B6=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改BaiduAdapter以兼容不同API响应结构,当list字段在顶层时也能正确解析 修复parentId使用目标路径而非文件路径的问题 添加相关单元测试验证功能 --- src/adapters/baidu/baidu-adapter.ts | 22 +++++--- src/shared/version.ts | 2 +- tests/unit/adapters/baidu-adapter.test.ts | 66 +++++++++++++++++++++++ 3 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 tests/unit/adapters/baidu-adapter.test.ts diff --git a/src/adapters/baidu/baidu-adapter.ts b/src/adapters/baidu/baidu-adapter.ts index a8d6f4d..3522430 100644 --- a/src/adapters/baidu/baidu-adapter.ts +++ b/src/adapters/baidu/baidu-adapter.ts @@ -14,6 +14,8 @@ interface BaiduAPIResponse { request_id?: number; taskid?: number; 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(); - if (result.errno !== 0 || !result.data?.list) { + if (result.errno !== 0) { const errorMsg = getErrorMessage(result.errno); 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) const files = pageFiles @@ -203,7 +208,7 @@ export class BaiduAdapter extends BasePlatformAdapter { id: String(file.fs_id), name: file.server_filename, ext: ext, - parentId: file.path || targetPath, + parentId: targetPath, size: file.size, 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(); - if (result.errno === 0 && result.data?.list) { - return result.data.list.some(file => file.server_filename === fileName); + if (result.errno !== 0) { + 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) { logger.error('Failed to check name conflict:', error instanceof Error ? error : new Error(String(error))); return true; // Conservative on error diff --git a/src/shared/version.ts b/src/shared/version.ts index 9abdb64..c202dba 100644 --- a/src/shared/version.ts +++ b/src/shared/version.ts @@ -10,7 +10,7 @@ * 1. Edit version in package.json * 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 */ /** diff --git a/tests/unit/adapters/baidu-adapter.test.ts b/tests/unit/adapters/baidu-adapter.test.ts new file mode 100644 index 0000000..4c7b2d4 --- /dev/null +++ b/tests/unit/adapters/baidu-adapter.test.ts @@ -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, + }); + }); + }); +}); +