diff --git a/docs/qqbot-bangdream-tsugu-global-refactor-plan.md b/docs/qqbot-bangdream-tsugu-global-refactor-plan.md index c81e6fe..8ce72d5 100644 --- a/docs/qqbot-bangdream-tsugu-global-refactor-plan.md +++ b/docs/qqbot-bangdream-tsugu-global-refactor-plan.md @@ -305,6 +305,7 @@ export interface TsuguHook { - 已新增 `models/character-resource-repository.ts`,把 `Character` 的详情请求、角色图标、KV 立绘和名称横幅资源路径从 `bestdoriUrl + callAPIAndCacheResponse/downloadFileCache` 收口到 provider-backed repository;`character-resource-repository.spec.ts` 覆盖详情缓存策略和三类资源路径,本地 `/查角色 1` 图片 smoke 输出非空。 - 已新增 `models/band-resource-repository.ts`,把 `Band` 的乐队 Logo 和乐队图标 SVG 资源路径从 `bestdoriUrl + downloadFileCache` 收口到 provider-backed repository;`band-resource-repository.spec.ts` 覆盖两类资源路径和下载调用,本地 `/查角色 1` 图片 smoke 保持非空输出。 - 已新增 `models/attribute-resource-repository.ts`,把 `Attribute` 的属性图标 SVG 资源路径从 `bestdoriUrl + downloadFileCache` 收口到 provider-backed repository;`attribute-resource-repository.spec.ts` 覆盖属性图标路径和下载调用,本地 `/查卡 472` 图片 smoke 保持非空输出。 +- 已新增 `models/server-resource-repository.ts`,把 `Server` 的服务器图标 SVG 资源路径从 `bestdoriUrl + downloadFileCache` 收口到 provider-backed repository,并把台服本地图标路径改走 asset manifest;`server-resource-repository.spec.ts` 覆盖服务器图标路径、台服本地图标路径和下载调用,本地 `/查卡 472` 图片 smoke 保持非空输出。 - 固化:Windows 下不要用反斜杠测试路径直接调用 Jest pattern,容易出现 `Pattern ... - 0 matches`;指定文件测试统一使用 `pnpm exec jest --runInBand --runTestsByPath test/qqbot/plugins/bangDream/tsugu/.spec.ts ...`,路径用正斜杠。 ### Phase 4:搜索 specification 和 matcher diff --git a/src/qqbot/plugins/bangDream/tsugu/models/server-resource-repository.ts b/src/qqbot/plugins/bangDream/tsugu/models/server-resource-repository.ts new file mode 100644 index 0000000..fcfbb24 --- /dev/null +++ b/src/qqbot/plugins/bangDream/tsugu/models/server-resource-repository.ts @@ -0,0 +1,36 @@ +import { bangDreamBestdoriProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/bestdori-provider'; +import type { BangDreamDataProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/data-provider'; +import { getBangDreamAssetPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/asset-manifest'; + +export class ServerResourceRepository { + constructor( + private readonly provider: BangDreamDataProvider = bangDreamBestdoriProvider, + ) {} + + /** + * 获取服务器图标 SVG 资源路径。 + * + * @param serverName - 服务器代码。 + */ + getIconSvgPath(serverName: string): string { + return `/res/icon/${serverName}.svg`; + } + + /** + * 获取台服本地图标路径。 + */ + getTwIconPath(): string { + return getBangDreamAssetPath('twServerIcon'); + } + + /** + * 下载服务器图标 SVG 资源。 + * + * @param serverName - 服务器代码。 + */ + async getIconSvgBuffer(serverName: string): Promise { + return await this.provider.getAsset(this.getIconSvgPath(serverName)); + } +} + +export const serverResourceRepository = new ServerResourceRepository(); diff --git a/src/qqbot/plugins/bangDream/tsugu/models/server.ts b/src/qqbot/plugins/bangDream/tsugu/models/server.ts index 5615a72..d8ce2cb 100644 --- a/src/qqbot/plugins/bangDream/tsugu/models/server.ts +++ b/src/qqbot/plugins/bangDream/tsugu/models/server.ts @@ -1,20 +1,15 @@ -import { downloadFileCache } from '@/qqbot/plugins/bangDream/tsugu/data-clients/asset-cache-client'; -import * as path from 'path'; import { loadImage, Image } from 'skia-canvas'; import { - assetsRootPath, globalDefaultServer, serverNameFullList, } from '@/qqbot/plugins/bangDream/tsugu/runtime/config'; -import { - globalServerPriority, - bestdoriUrl, -} from '@/qqbot/plugins/bangDream/tsugu/runtime/config'; +import { globalServerPriority } from '@/qqbot/plugins/bangDream/tsugu/runtime/config'; import { loadImageFromPath, convertSvgToPngBuffer, } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils'; import { BANGDREAM_SERVER_CODES } from '@/qqbot/plugins/bangDream/tsugu/models/bangdream-constants'; +import { serverResourceRepository } from '@/qqbot/plugins/bangDream/tsugu/models/server-resource-repository'; export enum Server { jp, @@ -79,10 +74,10 @@ export async function getIcon(server: Server): Promise { } let image: Image; if (server == Server.tw) { - image = await loadImageFromPath(path.join(assetsRootPath, 'tw.png')); + image = await loadImageFromPath(serverResourceRepository.getTwIconPath()); } else { - const iconSvgBuffer = await downloadFileCache( - `${bestdoriUrl}/res/icon/${Server[server]}.svg`, + const iconSvgBuffer = await serverResourceRepository.getIconSvgBuffer( + Server[server], ); const iconPngBuffer = await convertSvgToPngBuffer(iconSvgBuffer); image = await loadImage(iconPngBuffer); diff --git a/test/qqbot/plugins/bangDream/tsugu/server-resource-repository.spec.ts b/test/qqbot/plugins/bangDream/tsugu/server-resource-repository.spec.ts new file mode 100644 index 0000000..da5864e --- /dev/null +++ b/test/qqbot/plugins/bangDream/tsugu/server-resource-repository.spec.ts @@ -0,0 +1,34 @@ +import type { BangDreamDataProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/data-provider'; +import { ServerResourceRepository } from '@/qqbot/plugins/bangDream/tsugu/models/server-resource-repository'; + +function createProviderMock(): jest.Mocked { + return { + getAsset: jest.fn(), + getJson: jest.fn(), + getTracker: jest.fn(), + name: 'MockBestdori', + resolveUrl: jest.fn((pathOrUrl) => `https://bestdori.example${pathOrUrl}`), + }; +} + +describe('BangDream server resource repository', () => { + it('builds server icon paths', () => { + const repository = new ServerResourceRepository(createProviderMock()); + + expect(repository.getIconSvgPath('cn')).toBe('/res/icon/cn.svg'); + expect(repository.getTwIconPath().replace(/\\/g, '/')).toMatch( + /\/tw\.png$/, + ); + }); + + it('downloads server icon assets through the provider', async () => { + const provider = createProviderMock(); + const iconBuffer = Buffer.from(''); + provider.getAsset.mockResolvedValue(iconBuffer); + const repository = new ServerResourceRepository(provider); + + await expect(repository.getIconSvgBuffer('cn')).resolves.toBe(iconBuffer); + + expect(provider.getAsset).toHaveBeenCalledWith('/res/icon/cn.svg'); + }); +});