refactor: 收口 BangDream 歌曲资源仓储
This commit is contained in:
parent
286f57f63a
commit
4493174ad3
@ -14,7 +14,7 @@
|
|||||||
## 当前事实
|
## 当前事实
|
||||||
|
|
||||||
- Tsugu 源码目录:`src/qqbot/plugins/bangDream/tsugu`
|
- Tsugu 源码目录:`src/qqbot/plugins/bangDream/tsugu`
|
||||||
- TS 文件:初始基线 92;当前 `tsugu` 源码 128
|
- TS 文件:初始基线 92;当前 `tsugu` 源码 132
|
||||||
- 函数节点:481,其中稳定函数 410,匿名/内联回调 71
|
- 函数节点:481,其中稳定函数 410,匿名/内联回调 71
|
||||||
- 源码 JSDoc:稳定函数 410/410 已覆盖
|
- 源码 JSDoc:稳定函数 410/410 已覆盖
|
||||||
- 变量声明:1896
|
- 变量声明:1896
|
||||||
@ -298,6 +298,7 @@ export interface TsuguHook {
|
|||||||
- 已新增 `test/qqbot/plugins/bangDream/tsugu/data-provider.spec.ts`,覆盖 provider URL 解析、Bestdori/HHWX mock 数据源、retry/cache wrapper。
|
- 已新增 `test/qqbot/plugins/bangDream/tsugu/data-provider.spec.ts`,覆盖 provider URL 解析、Bestdori/HHWX mock 数据源、retry/cache wrapper。
|
||||||
- 已新增 `cache-client-policy.spec.ts`,覆盖缓存客户端 retry/status/not-found 策略;`file-cache-client.spec.ts` 补 SVG 缺失资源 404 缓存,避免 SVG 素材缺失仍反复请求。
|
- 已新增 `cache-client-policy.spec.ts`,覆盖缓存客户端 retry/status/not-found 策略;`file-cache-client.spec.ts` 补 SVG 缺失资源 404 缓存,避免 SVG 素材缺失仍反复请求。
|
||||||
- 本地图片烟测已生成查歌 `136`、查活动 `50` 简易背景和真实活动背景图片,证明 provider/repository 第一段迁移后仍能输出非空图片。
|
- 本地图片烟测已生成查歌 `136`、查活动 `50` 简易背景和真实活动背景图片,证明 provider/repository 第一段迁移后仍能输出非空图片。
|
||||||
|
- 已新增 `models/song-resource-repository.ts`,把 `Song` 的歌曲详情、谱面、封面路径、封面完整 URL 和封面缺失时服务器回退下载收口到不依赖 `Song` 类的资源 repository,避免 `song.ts` 继续直接拼 Bestdori API/asset 路径;`song-resource-repository.spec.ts` 覆盖 detail/chart provider 调用、13/40 旧封面批次、273 强制 CN 和封面 fallback 行为,本地 `/查曲 136`、`/查谱面 136 expert` 图片 smoke 输出非空。
|
||||||
|
|
||||||
### Phase 4:搜索 specification 和 matcher
|
### Phase 4:搜索 specification 和 matcher
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,192 @@
|
|||||||
|
import { assetErrorImageBuffer } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
|
import { bangDreamBestdoriProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/bestdori-provider';
|
||||||
|
import type { BangDreamDataProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/data-provider';
|
||||||
|
import {
|
||||||
|
BANGDREAM_DIFFICULTY_NAME_BY_ID,
|
||||||
|
BANGDREAM_SERVER_CODES,
|
||||||
|
} from '@/qqbot/plugins/bangDream/tsugu/models/bangdream-constants';
|
||||||
|
import {
|
||||||
|
getServerByPriority,
|
||||||
|
Server,
|
||||||
|
} from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
||||||
|
|
||||||
|
export interface SongJacketSource {
|
||||||
|
jacketImage: Array<string>;
|
||||||
|
publishedAt: Array<number | null>;
|
||||||
|
songId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const difficultyNameById: Record<number, string> =
|
||||||
|
BANGDREAM_DIFFICULTY_NAME_BY_ID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将服务器枚举值转换为 Bestdori 资源路径中的服务器编码。
|
||||||
|
*
|
||||||
|
* @param server - 服务器枚举值。
|
||||||
|
*/
|
||||||
|
function getServerCode(server: Server | undefined): string {
|
||||||
|
return server == null ? 'undefined' : Server[server];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SongResourceRepository {
|
||||||
|
constructor(
|
||||||
|
private readonly provider: BangDreamDataProvider = bangDreamBestdoriProvider,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取歌曲远端详情。
|
||||||
|
*
|
||||||
|
* @param songId - 歌曲 ID。
|
||||||
|
*/
|
||||||
|
async getDetail(songId: number): Promise<Record<string, any>> {
|
||||||
|
return await this.provider.getJson<Record<string, any>>(
|
||||||
|
`/api/songs/${songId}.json`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取歌曲谱面数据。
|
||||||
|
*
|
||||||
|
* @param songId - 歌曲 ID。
|
||||||
|
* @param difficultyId - 难度 ID。
|
||||||
|
*/
|
||||||
|
async getChart(songId: number, difficultyId: number): Promise<object> {
|
||||||
|
return await this.provider.getJson<object>(
|
||||||
|
`/api/charts/${songId}/${difficultyNameById[difficultyId]}.json`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取歌曲封面资源批次。
|
||||||
|
*
|
||||||
|
* @param songId - 歌曲 ID。
|
||||||
|
*/
|
||||||
|
getSongRip(songId: number): number {
|
||||||
|
return Math.ceil(songId / 10) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取歌曲封面资源路径。
|
||||||
|
*
|
||||||
|
* @param source - 歌曲封面来源字段。
|
||||||
|
* @param displayedServerList - 可展示服务器优先级。
|
||||||
|
*/
|
||||||
|
getJacketImagePath(
|
||||||
|
source: SongJacketSource,
|
||||||
|
displayedServerList?: Server[],
|
||||||
|
): string {
|
||||||
|
const { server, songRip } = this.getJacketServerAndRip(
|
||||||
|
source,
|
||||||
|
displayedServerList,
|
||||||
|
);
|
||||||
|
const jacketImageName = this.getJacketImageName(source).toLowerCase();
|
||||||
|
return this.buildJacketImagePath(
|
||||||
|
getServerCode(server),
|
||||||
|
songRip,
|
||||||
|
jacketImageName,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取歌曲封面完整 URL。
|
||||||
|
*
|
||||||
|
* @param source - 歌曲封面来源字段。
|
||||||
|
* @param displayedServerList - 可展示服务器优先级。
|
||||||
|
*/
|
||||||
|
resolveJacketImageUrl(
|
||||||
|
source: SongJacketSource,
|
||||||
|
displayedServerList?: Server[],
|
||||||
|
): string {
|
||||||
|
return this.provider.resolveUrl(
|
||||||
|
this.getJacketImagePath(source, displayedServerList),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载歌曲封面 Buffer,并在缺失时按服务器顺序回退。
|
||||||
|
*
|
||||||
|
* @param source - 歌曲封面来源字段。
|
||||||
|
* @param displayedServerList - 可展示服务器优先级。
|
||||||
|
*/
|
||||||
|
async getJacketImageBuffer(
|
||||||
|
source: SongJacketSource,
|
||||||
|
displayedServerList: Server[] = [Server.jp, Server.cn],
|
||||||
|
): Promise<Buffer> {
|
||||||
|
let jacketImageBuffer = await this.provider.getAsset(
|
||||||
|
this.getJacketImagePath(source, displayedServerList),
|
||||||
|
{ memoryCache: false },
|
||||||
|
);
|
||||||
|
if (!jacketImageBuffer.equals(assetErrorImageBuffer)) {
|
||||||
|
return jacketImageBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const retryPath of this.getFallbackJacketImagePaths(source)) {
|
||||||
|
jacketImageBuffer = await this.provider.getAsset(retryPath, {
|
||||||
|
ignoreError: true,
|
||||||
|
memoryCache: false,
|
||||||
|
retryCount: 1,
|
||||||
|
});
|
||||||
|
if (!jacketImageBuffer.equals(assetErrorImageBuffer)) break;
|
||||||
|
}
|
||||||
|
return jacketImageBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算歌曲封面优先服务器和资源批次。
|
||||||
|
*
|
||||||
|
* @param source - 歌曲封面来源字段。
|
||||||
|
* @param displayedServerList - 可展示服务器优先级。
|
||||||
|
*/
|
||||||
|
private getJacketServerAndRip(
|
||||||
|
source: SongJacketSource,
|
||||||
|
displayedServerList?: Server[],
|
||||||
|
): { server: Server | undefined; songRip: number } {
|
||||||
|
let server = getServerByPriority(source.publishedAt, displayedServerList);
|
||||||
|
let songRip = this.getSongRip(source.songId);
|
||||||
|
if (source.songId === 13 || source.songId === 40) {
|
||||||
|
songRip = 30;
|
||||||
|
} else if (source.songId === 273) {
|
||||||
|
server = Server.cn;
|
||||||
|
}
|
||||||
|
return { server, songRip };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取歌曲封面缺失时的服务器回退路径列表。
|
||||||
|
*
|
||||||
|
* @param source - 歌曲封面来源字段。
|
||||||
|
*/
|
||||||
|
private getFallbackJacketImagePaths(source: SongJacketSource): string[] {
|
||||||
|
const jacketImageName = this.getJacketImageName(source);
|
||||||
|
const songRip = this.getSongRip(source.songId);
|
||||||
|
return BANGDREAM_SERVER_CODES.map((serverCode) =>
|
||||||
|
this.buildJacketImagePath(serverCode, songRip, jacketImageName),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拼接歌曲封面资源路径。
|
||||||
|
*
|
||||||
|
* @param serverCode - Bestdori 服务器编码。
|
||||||
|
* @param songRip - 歌曲资源批次。
|
||||||
|
* @param jacketImageName - 封面资源名称。
|
||||||
|
*/
|
||||||
|
private buildJacketImagePath(
|
||||||
|
serverCode: string,
|
||||||
|
songRip: number,
|
||||||
|
jacketImageName: string,
|
||||||
|
): string {
|
||||||
|
return `/assets/${serverCode}/musicjacket/musicjacket${songRip}_rip/assets-star-forassetbundle-startapp-musicjacket-musicjacket${songRip}-${jacketImageName}-jacket.png`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取歌曲封面资源名称。
|
||||||
|
*
|
||||||
|
* @param source - 歌曲封面来源字段。
|
||||||
|
*/
|
||||||
|
private getJacketImageName(source: SongJacketSource): string {
|
||||||
|
return source.jacketImage[source.jacketImage.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const songResourceRepository = new SongResourceRepository();
|
||||||
@ -1,19 +1,14 @@
|
|||||||
import { Image, loadImage } from 'skia-canvas';
|
import { Image, loadImage } from 'skia-canvas';
|
||||||
import { bangDreamBestdoriProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/bestdori-provider';
|
import { Server } from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
||||||
import {
|
|
||||||
getServerByPriority,
|
|
||||||
Server,
|
|
||||||
} from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
|
||||||
import { bangDreamMainDataRepository } from '@/qqbot/plugins/bangDream/tsugu/models/main-data-repository';
|
import { bangDreamMainDataRepository } from '@/qqbot/plugins/bangDream/tsugu/models/main-data-repository';
|
||||||
import { stringToNumberArray } from '@/qqbot/plugins/bangDream/tsugu/models/model-utils';
|
import { stringToNumberArray } from '@/qqbot/plugins/bangDream/tsugu/models/model-utils';
|
||||||
import { assetErrorImageBuffer } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
|
||||||
import {
|
import {
|
||||||
BANGDREAM_DIFFICULTY_COLORS,
|
BANGDREAM_DIFFICULTY_COLORS,
|
||||||
BANGDREAM_DIFFICULTY_NAME_BY_ID,
|
BANGDREAM_DIFFICULTY_NAME_BY_ID,
|
||||||
BANGDREAM_DIFFICULTY_NAMES,
|
BANGDREAM_DIFFICULTY_NAMES,
|
||||||
BANGDREAM_SERVER_CODES,
|
|
||||||
BANGDREAM_SONG_TAG_NAME,
|
BANGDREAM_SONG_TAG_NAME,
|
||||||
} from '@/qqbot/plugins/bangDream/tsugu/models/bangdream-constants';
|
} from '@/qqbot/plugins/bangDream/tsugu/models/bangdream-constants';
|
||||||
|
import { songResourceRepository } from '@/qqbot/plugins/bangDream/tsugu/models/song-resource-repository';
|
||||||
|
|
||||||
export const difficultyName: Record<number, string> =
|
export const difficultyName: Record<number, string> =
|
||||||
BANGDREAM_DIFFICULTY_NAME_BY_ID;
|
BANGDREAM_DIFFICULTY_NAME_BY_ID;
|
||||||
@ -190,12 +185,7 @@ export class Song {
|
|||||||
* 在 Song 模型中请求当前模型的远端详情数据。
|
* 在 Song 模型中请求当前模型的远端详情数据。
|
||||||
*/
|
*/
|
||||||
async getData() {
|
async getData() {
|
||||||
const songData = await bangDreamBestdoriProvider.getJson<
|
return await songResourceRepository.getDetail(this.songId);
|
||||||
Record<string, any>
|
|
||||||
>(
|
|
||||||
`/api/songs/${this.songId}.json`,
|
|
||||||
);
|
|
||||||
return songData;
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 在 Song 模型中获取歌曲资源批次。
|
* 在 Song 模型中获取歌曲资源批次。
|
||||||
@ -203,7 +193,7 @@ export class Song {
|
|||||||
* @returns 计算后的数值。
|
* @returns 计算后的数值。
|
||||||
*/
|
*/
|
||||||
getSongRip(): number {
|
getSongRip(): number {
|
||||||
return Math.ceil(this.songId / 10) * 10;
|
return songResourceRepository.getSongRip(this.songId);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 在 Song 模型中获取歌曲封面图片。
|
* 在 Song 模型中获取歌曲封面图片。
|
||||||
@ -214,22 +204,10 @@ export class Song {
|
|||||||
async getSongJacketImage(
|
async getSongJacketImage(
|
||||||
displayedServerList: Server[] = [Server.jp, Server.cn],
|
displayedServerList: Server[] = [Server.jp, Server.cn],
|
||||||
): Promise<Image> {
|
): Promise<Image> {
|
||||||
let jacketImageBuffer = await bangDreamBestdoriProvider.getAsset(
|
const jacketImageBuffer = await songResourceRepository.getJacketImageBuffer(
|
||||||
this.getSongJacketImagePath(displayedServerList),
|
this,
|
||||||
{ memoryCache: false },
|
displayedServerList,
|
||||||
);
|
);
|
||||||
//下载失败自动尝试切换服务器下载
|
|
||||||
if (jacketImageBuffer.equals(assetErrorImageBuffer)) {
|
|
||||||
const jacketImageName = this.jacketImage[this.jacketImage.length - 1];
|
|
||||||
for (const server of BANGDREAM_SERVER_CODES) {
|
|
||||||
const retryPath = `/assets/${server}/musicjacket/musicjacket${this.getSongRip()}_rip/assets-star-forassetbundle-startapp-musicjacket-musicjacket${this.getSongRip()}-${jacketImageName}-jacket.png`;
|
|
||||||
jacketImageBuffer = await bangDreamBestdoriProvider.getAsset(
|
|
||||||
retryPath,
|
|
||||||
{ ignoreError: true, memoryCache: false, retryCount: 1 },
|
|
||||||
);
|
|
||||||
if (!jacketImageBuffer.equals(assetErrorImageBuffer)) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return await loadImage(jacketImageBuffer);
|
return await loadImage(jacketImageBuffer);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -239,8 +217,9 @@ export class Song {
|
|||||||
* @returns 格式化后的文本。
|
* @returns 格式化后的文本。
|
||||||
*/
|
*/
|
||||||
getSongJacketImageURL(displayedServerList?: Server[]): string {
|
getSongJacketImageURL(displayedServerList?: Server[]): string {
|
||||||
return bangDreamBestdoriProvider.resolveUrl(
|
return songResourceRepository.resolveJacketImageUrl(
|
||||||
this.getSongJacketImagePath(displayedServerList),
|
this,
|
||||||
|
displayedServerList,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -250,16 +229,7 @@ export class Song {
|
|||||||
* @returns 格式化后的资源路径。
|
* @returns 格式化后的资源路径。
|
||||||
*/
|
*/
|
||||||
getSongJacketImagePath(displayedServerList?: Server[]): string {
|
getSongJacketImagePath(displayedServerList?: Server[]): string {
|
||||||
let server = getServerByPriority(this.publishedAt, displayedServerList);
|
return songResourceRepository.getJacketImagePath(this, displayedServerList);
|
||||||
const jacketImageName = this.jacketImage[this.jacketImage.length - 1];
|
|
||||||
let songRip = this.getSongRip();
|
|
||||||
if (this.songId == 13 || this.songId == 40) {
|
|
||||||
songRip = 30;
|
|
||||||
} else if (this.songId == 273) {
|
|
||||||
//针对273的修复
|
|
||||||
server = Server.cn;
|
|
||||||
}
|
|
||||||
return `/assets/${Server[server]}/musicjacket/musicjacket${songRip}_rip/assets-star-forassetbundle-startapp-musicjacket-musicjacket${songRip}-${jacketImageName.toLowerCase()}-jacket.png`;
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 在 Song 模型中获取Tag名称。
|
* 在 Song 模型中获取Tag名称。
|
||||||
@ -279,10 +249,7 @@ export class Song {
|
|||||||
* @returns 异步处理结果。
|
* @returns 异步处理结果。
|
||||||
*/
|
*/
|
||||||
async getSongChart(difficultyId: number): Promise<object> {
|
async getSongChart(difficultyId: number): Promise<object> {
|
||||||
const songChart = await bangDreamBestdoriProvider.getJson<object>(
|
return await songResourceRepository.getChart(this.songId, difficultyId);
|
||||||
`/api/charts/${this.songId}/${difficultyName[difficultyId]}.json`,
|
|
||||||
);
|
|
||||||
return songChart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -0,0 +1,97 @@
|
|||||||
|
import { assetErrorImageBuffer } from '@/qqbot/plugins/bangDream/tsugu/canvas/image-utils';
|
||||||
|
import type { BangDreamDataProvider } from '@/qqbot/plugins/bangDream/tsugu/data-clients/data-provider';
|
||||||
|
import { Server } from '@/qqbot/plugins/bangDream/tsugu/models/server';
|
||||||
|
import {
|
||||||
|
SongResourceRepository,
|
||||||
|
type SongJacketSource,
|
||||||
|
} from '@/qqbot/plugins/bangDream/tsugu/models/song-resource-repository';
|
||||||
|
|
||||||
|
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 createSongSource(
|
||||||
|
overrides: Partial<SongJacketSource> = {},
|
||||||
|
): SongJacketSource {
|
||||||
|
return {
|
||||||
|
jacketImage: ['SummerFest'],
|
||||||
|
publishedAt: [100, null, null, 200, null],
|
||||||
|
songId: 136,
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('BangDream song resource repository', () => {
|
||||||
|
it('routes song detail and chart requests through the provider', async () => {
|
||||||
|
const provider = createProviderMock();
|
||||||
|
provider.getJson.mockResolvedValue({ ok: true });
|
||||||
|
const repository = new SongResourceRepository(provider);
|
||||||
|
|
||||||
|
await expect(repository.getDetail(136)).resolves.toEqual({ ok: true });
|
||||||
|
await expect(repository.getChart(136, 3)).resolves.toEqual({ ok: true });
|
||||||
|
|
||||||
|
expect(provider.getJson).toHaveBeenNthCalledWith(1, '/api/songs/136.json');
|
||||||
|
expect(provider.getJson).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
'/api/charts/136/expert.json',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('builds jacket paths from server priority and legacy song exceptions', () => {
|
||||||
|
const repository = new SongResourceRepository(createProviderMock());
|
||||||
|
|
||||||
|
expect(
|
||||||
|
repository.getJacketImagePath(createSongSource(), [Server.cn, Server.jp]),
|
||||||
|
).toBe(
|
||||||
|
'/assets/cn/musicjacket/musicjacket140_rip/assets-star-forassetbundle-startapp-musicjacket-musicjacket140-summerfest-jacket.png',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
repository.getJacketImagePath(
|
||||||
|
createSongSource({
|
||||||
|
publishedAt: [100, null, null, null, null],
|
||||||
|
songId: 13,
|
||||||
|
}),
|
||||||
|
[Server.jp],
|
||||||
|
),
|
||||||
|
).toContain('/assets/jp/musicjacket/musicjacket30_rip/');
|
||||||
|
expect(
|
||||||
|
repository.getJacketImagePath(
|
||||||
|
createSongSource({
|
||||||
|
publishedAt: [100, null, null, null, null],
|
||||||
|
songId: 273,
|
||||||
|
}),
|
||||||
|
[Server.jp],
|
||||||
|
),
|
||||||
|
).toContain('/assets/cn/musicjacket/musicjacket280_rip/');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('falls back through server jacket paths when the primary asset is missing', async () => {
|
||||||
|
const provider = createProviderMock();
|
||||||
|
const validImage = Buffer.from('valid');
|
||||||
|
provider.getAsset
|
||||||
|
.mockResolvedValueOnce(assetErrorImageBuffer)
|
||||||
|
.mockResolvedValueOnce(validImage);
|
||||||
|
const repository = new SongResourceRepository(provider);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
repository.getJacketImageBuffer(createSongSource(), [Server.cn]),
|
||||||
|
).resolves.toBe(validImage);
|
||||||
|
|
||||||
|
expect(provider.getAsset).toHaveBeenNthCalledWith(
|
||||||
|
1,
|
||||||
|
'/assets/cn/musicjacket/musicjacket140_rip/assets-star-forassetbundle-startapp-musicjacket-musicjacket140-summerfest-jacket.png',
|
||||||
|
{ memoryCache: false },
|
||||||
|
);
|
||||||
|
expect(provider.getAsset).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
'/assets/jp/musicjacket/musicjacket140_rip/assets-star-forassetbundle-startapp-musicjacket-musicjacket140-SummerFest-jacket.png',
|
||||||
|
{ ignoreError: true, memoryCache: false, retryCount: 1 },
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user