refactor: 收口 BangDream 道具资源仓储
This commit is contained in:
parent
4816354344
commit
dbc2fab5af
@ -308,6 +308,7 @@ export interface TsuguHook {
|
|||||||
- 已新增 `models/server-resource-repository.ts`,把 `Server` 的服务器图标 SVG 资源路径从 `bestdoriUrl + downloadFileCache` 收口到 provider-backed repository,并把台服本地图标路径改走 asset manifest;`server-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 保持非空输出。
|
||||||
- 已新增 `render-blocks/card-art-resource-repository.ts`,把 `card-art.ts` 的卡牌小图/插画边框资源下载从 `bestdoriUrl + downloadFileCache` 收口到 provider-backed repository,`card-art-spec.ts` 改为只生成 `/res/image/...` 相对资源路径;`card-art-resource-repository.spec.ts` 覆盖边框下载调用,本地 `/查卡 472` 图片 smoke 保持非空输出。
|
- 已新增 `render-blocks/card-art-resource-repository.ts`,把 `card-art.ts` 的卡牌小图/插画边框资源下载从 `bestdoriUrl + downloadFileCache` 收口到 provider-backed repository,`card-art-spec.ts` 改为只生成 `/res/image/...` 相对资源路径;`card-art-resource-repository.spec.ts` 覆盖边框下载调用,本地 `/查卡 472` 图片 smoke 保持非空输出。
|
||||||
- 已新增 `models/costume-resource-repository.ts`,把 `Costume` 的服装详情请求和 Live2D 缩略图素材路径从 `bestdoriUrl + callAPIAndCacheResponse/downloadFile` 收口到 provider-backed repository;`costume-resource-repository.spec.ts` 覆盖详情路径、`sdchara.png` 路径和非内存缓存下载调用,本地 `/查卡 472` 图片 smoke 保持演出缩略图正常输出。
|
- 已新增 `models/costume-resource-repository.ts`,把 `Costume` 的服装详情请求和 Live2D 缩略图素材路径从 `bestdoriUrl + callAPIAndCacheResponse/downloadFile` 收口到 provider-backed repository;`costume-resource-repository.spec.ts` 覆盖详情路径、`sdchara.png` 路径和非内存缓存下载调用,本地 `/查卡 472` 图片 smoke 保持演出缩略图正常输出。
|
||||||
|
- 已新增 `models/item-resource-repository.ts`,把 `Item` 的道具缩略图路径从 `bestdoriUrl + downloadFileCache` 收口到 provider-backed repository;`item-resource-repository.spec.ts` 覆盖 material、star 和 common item 三类路径,本地 `/查卡池 259` 图片 smoke 输出非空。
|
||||||
- 固化:Windows 下不要用反斜杠测试路径直接调用 Jest pattern,容易出现 `Pattern ... - 0 matches`;指定文件测试统一使用 `pnpm exec jest --runInBand --runTestsByPath test/qqbot/plugins/bangDream/tsugu/<file>.spec.ts ...`,路径用正斜杠。
|
- 固化:Windows 下不要用反斜杠测试路径直接调用 Jest pattern,容易出现 `Pattern ... - 0 matches`;指定文件测试统一使用 `pnpm exec jest --runInBand --runTestsByPath test/qqbot/plugins/bangDream/tsugu/<file>.spec.ts ...`,路径用正斜杠。
|
||||||
|
|
||||||
### Phase 4:搜索 specification 和 matcher
|
### Phase 4:搜索 specification 和 matcher
|
||||||
|
|||||||
@ -0,0 +1,51 @@
|
|||||||
|
import { bangDreamBestdoriProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/bestdori-provider';
|
||||||
|
import type { BangDreamDataProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/data-provider';
|
||||||
|
import { formatNumber } from '@/qqbot/plugins/bangDream/tsugu/models/model-utils';
|
||||||
|
import { Server } from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
||||||
|
|
||||||
|
export interface ItemResourceSource {
|
||||||
|
resourceId: number;
|
||||||
|
typeName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toServerCode(server: Server | undefined): string {
|
||||||
|
return server == null ? 'undefined' : Server[server];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ItemResourceRepository {
|
||||||
|
constructor(
|
||||||
|
private readonly provider: BangDreamDataProvider = bangDreamBestdoriProvider,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取道具缩略图资源路径。
|
||||||
|
*
|
||||||
|
* @param source - 道具资源来源字段。
|
||||||
|
* @param server - 目标服务器。
|
||||||
|
*/
|
||||||
|
getImagePath(source: ItemResourceSource, server: Server | undefined): string {
|
||||||
|
const serverCode = toServerCode(server);
|
||||||
|
if (source.typeName === 'material') {
|
||||||
|
return `/assets/${serverCode}/thumb/material_rip/${source.typeName}${formatNumber(source.resourceId, 3)}.png`;
|
||||||
|
}
|
||||||
|
if (source.typeName === 'star') {
|
||||||
|
return `/assets/${serverCode}/thumb/common_rip/star.png`;
|
||||||
|
}
|
||||||
|
return `/assets/${serverCode}/thumb/common_rip/${source.typeName}${source.resourceId}.png`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载道具缩略图资源。
|
||||||
|
*
|
||||||
|
* @param source - 道具资源来源字段。
|
||||||
|
* @param server - 目标服务器。
|
||||||
|
*/
|
||||||
|
async getImageBuffer(
|
||||||
|
source: ItemResourceSource,
|
||||||
|
server: Server | undefined,
|
||||||
|
): Promise<Buffer> {
|
||||||
|
return await this.provider.getAsset(this.getImagePath(source, server));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const itemResourceRepository = new ItemResourceRepository();
|
||||||
@ -1,15 +1,11 @@
|
|||||||
import { Image, loadImage } from 'skia-canvas';
|
import { Image, loadImage } from 'skia-canvas';
|
||||||
import { downloadFileCache } from '@/qqbot/plugins/bangDream/tsugu/data-clients/asset-cache-client';
|
|
||||||
import {
|
import {
|
||||||
Server,
|
Server,
|
||||||
getServerByPriority,
|
getServerByPriority,
|
||||||
} from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
} from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
||||||
import { formatNumber } from '@/qqbot/plugins/bangDream/tsugu/models/model-utils';
|
|
||||||
import mainAPI from '@/qqbot/plugins/bangDream/tsugu/models/main-data-store';
|
import mainAPI from '@/qqbot/plugins/bangDream/tsugu/models/main-data-store';
|
||||||
import {
|
import { itemResourceRepository } from '@/qqbot/plugins/bangDream/tsugu/models/item-resource-repository';
|
||||||
globalDefaultServer,
|
import { globalDefaultServer } from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
||||||
bestdoriUrl,
|
|
||||||
} from '@/qqbot/plugins/bangDream/tsugu/runtime/config';
|
|
||||||
import { BANGDREAM_ITEM_TYPE_PREFIXES } from '@/qqbot/plugins/bangDream/tsugu/models/bangdream-constants';
|
import { BANGDREAM_ITEM_TYPE_PREFIXES } from '@/qqbot/plugins/bangDream/tsugu/models/bangdream-constants';
|
||||||
|
|
||||||
export class Item {
|
export class Item {
|
||||||
@ -82,20 +78,10 @@ export class Item {
|
|||||||
server = getServerByPriority(this.name, displayedServerList);
|
server = getServerByPriority(this.name, displayedServerList);
|
||||||
}
|
}
|
||||||
server = getServerByPriority(this.name, displayedServerList);
|
server = getServerByPriority(this.name, displayedServerList);
|
||||||
let itemImageBuffer: Buffer;
|
const itemImageBuffer = await itemResourceRepository.getImageBuffer(
|
||||||
if (this.typeName == 'material') {
|
this,
|
||||||
itemImageBuffer = await downloadFileCache(
|
server,
|
||||||
`${bestdoriUrl}/assets/${Server[server]}/thumb/material_rip/${this.typeName}${formatNumber(this.resourceId, 3)}.png`,
|
);
|
||||||
);
|
|
||||||
} else if (this.typeName == 'star') {
|
|
||||||
itemImageBuffer = await downloadFileCache(
|
|
||||||
`${bestdoriUrl}/assets/${Server[server]}/thumb/common_rip/star.png`,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
itemImageBuffer = await downloadFileCache(
|
|
||||||
`${bestdoriUrl}/assets/${Server[server]}/thumb/common_rip/${this.typeName}${this.resourceId}.png`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return await loadImage(itemImageBuffer);
|
return await loadImage(itemImageBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
import type { BangDreamDataProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/data-provider';
|
||||||
|
import {
|
||||||
|
ItemResourceRepository,
|
||||||
|
type ItemResourceSource,
|
||||||
|
} from '@/qqbot/plugins/bangDream/tsugu/models/item-resource-repository';
|
||||||
|
import { Server } from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
||||||
|
|
||||||
|
function createProviderMock(): jest.Mocked<BangDreamDataProvider> {
|
||||||
|
return {
|
||||||
|
getAsset: jest.fn(),
|
||||||
|
getJson: jest.fn(),
|
||||||
|
getTracker: jest.fn(),
|
||||||
|
name: 'MockBestdori',
|
||||||
|
resolveUrl: jest.fn((pathOrUrl) => `https://bestdori.example${pathOrUrl}`),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createItemSource(
|
||||||
|
overrides: Partial<ItemResourceSource> = {},
|
||||||
|
): ItemResourceSource {
|
||||||
|
return {
|
||||||
|
resourceId: 7,
|
||||||
|
typeName: 'gacha_ticket_',
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('BangDream item resource repository', () => {
|
||||||
|
it('builds material, star, and common item image paths', () => {
|
||||||
|
const repository = new ItemResourceRepository(createProviderMock());
|
||||||
|
|
||||||
|
expect(
|
||||||
|
repository.getImagePath(
|
||||||
|
createItemSource({ resourceId: 3, typeName: 'material' }),
|
||||||
|
Server.cn,
|
||||||
|
),
|
||||||
|
).toBe('/assets/cn/thumb/material_rip/material003.png');
|
||||||
|
expect(
|
||||||
|
repository.getImagePath(createItemSource({ typeName: 'star' }), Server.jp),
|
||||||
|
).toBe('/assets/jp/thumb/common_rip/star.png');
|
||||||
|
expect(repository.getImagePath(createItemSource(), Server.cn)).toBe(
|
||||||
|
'/assets/cn/thumb/common_rip/gacha_ticket_7.png',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('downloads item images through the provider', async () => {
|
||||||
|
const provider = createProviderMock();
|
||||||
|
const itemBuffer = Buffer.from('item');
|
||||||
|
provider.getAsset.mockResolvedValue(itemBuffer);
|
||||||
|
const repository = new ItemResourceRepository(provider);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
repository.getImageBuffer(createItemSource(), Server.cn),
|
||||||
|
).resolves.toBe(itemBuffer);
|
||||||
|
|
||||||
|
expect(provider.getAsset).toHaveBeenCalledWith(
|
||||||
|
'/assets/cn/thumb/common_rip/gacha_ticket_7.png',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user