diff --git a/docs/qqbot-bangdream-tsugu-global-refactor-plan.md b/docs/qqbot-bangdream-tsugu-global-refactor-plan.md index 6efb411..7e7bd02 100644 --- a/docs/qqbot-bangdream-tsugu-global-refactor-plan.md +++ b/docs/qqbot-bangdream-tsugu-global-refactor-plan.md @@ -364,7 +364,7 @@ export interface TsuguHook { - 已新增 `gacha-simulate-spec.spec.ts`,覆盖 10 抽网格、汇总模式、重复卡叠层、计数字样和横幅尺寸;本地生成 `gacha-simulate-spec-10-259.jpg` 和 `gacha-simulate-spec-50-259-after-cache-fix.jpg`,验证抽卡模拟两种布局模式图片输出正常。 - 抽卡模拟 50 抽 smoke 暴露资源下载短时失败会把 URL 写入无过期错误缓存,导致后续重试直接输出 `asset error`;已改为只有 HTTP 404 进入错误缓存,超时/网络抖动不污染 URL,并新增 `file-cache-client.spec.ts` 覆盖瞬时失败后可再次下载、404 缓存缺失资源两种路径。 - 已新增 `render-blocks/event-stage-spec.ts`,收口试炼列表最大列高、歌曲单元格/封面/ID/难度条尺寸、试炼类型顶部文字规格和换列判断;`event-stage.ts` 与 `list-event-stage.ts` 改为消费 spec,活动/歌曲选择和输出结构保持不变。 -- 线上 smoke 暴露 `/查试炼 310 -m` 将所有列横向拼成一张巨大 canvas 会触发 Pod `OOMKilled exit=137`;已改为边绘制边按列输出多张 CQ 图片,不再创建最终横向巨图,普通版和 meta 版均拆成 5 张输出。 +- 线上 smoke 暴露 `/查试炼 310 -m` 将所有列横向拼成一张巨大 canvas 会触发 Pod `OOMKilled exit=137`;已改为按小批次绘制 stage、边分列边输出多张 CQ 图片,不再创建最终横向巨图,普通版和 meta 版均拆成 5 张输出,同时避免完全串行导致冷缓存首条命令耗时过长。 - 已新增 `event-stage-spec.spec.ts`,覆盖试炼歌曲行尺寸、类型顶部文字规格、换列判断和按列高拆分算法;本地生成 `event-stage-split-310*.jpg`、`event-stage-split-310-meta*.jpg`,验证 `/查试炼 310` 与 `/查试炼 310 -m` 图片输出正常。 - smoke/Jenkins/远程调试卡点继续按已固化规则处理:同一卡点第二次尝试前必须改变可验证变量;Jenkins 查询 URL 含方括号时用 `curl -g` 或改查 Jenkins home;线上图片 smoke 必须查询 `commandId`、拉回图片、展示图片、查日志并清理本轮临时目录;PowerShell 双引号 here-string 中不要写 JS `${...}` 模板字面量,避免被 PowerShell 提前插值;smoke 没有真实图片落盘时必须失败。 diff --git a/src/qqbot/plugins/bangDream/tsugu/command-renderers/event-stage.ts b/src/qqbot/plugins/bangDream/tsugu/command-renderers/event-stage.ts index e24913a..3721677 100644 --- a/src/qqbot/plugins/bangDream/tsugu/command-renderers/event-stage.ts +++ b/src/qqbot/plugins/bangDream/tsugu/command-renderers/event-stage.ts @@ -13,7 +13,10 @@ import { import { outputEasyImages } from '@/qqbot/plugins/bangDream/tsugu/canvas/output'; import { drawDataBlock } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/data-block'; import { stackImage } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/image-stack'; -import { shouldStartNewEventStageColumn } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec'; +import { + getEventStageStageBatchSize, + shouldStartNewEventStageColumn, +} from '@/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec'; import { Canvas } from 'skia-canvas'; /** @@ -58,6 +61,7 @@ export async function drawEventStage( let currentColumn: Canvas[] = []; let currentHeight = 0; let pageIndex = 0; + const stageBatchSize = getEventStageStageBatchSize(); //绘制活动stage,每个stage一个图片 /** @@ -83,19 +87,23 @@ export async function drawEventStage( pageIndex += 1; } - for (const stage of stageList) { - const stageImage = await drawStageSong(stage); - if ( - shouldStartNewEventStageColumn( - currentHeight, - stageImage.height, - currentColumn.length, - ) - ) { - await flushColumn(); + for (let start = 0; start < stageList.length; start += stageBatchSize) { + const stageImages = await Promise.all( + stageList.slice(start, start + stageBatchSize).map(drawStageSong), + ); + for (const stageImage of stageImages) { + if ( + shouldStartNewEventStageColumn( + currentHeight, + stageImage.height, + currentColumn.length, + ) + ) { + await flushColumn(); + } + currentColumn.push(stageImage); + currentHeight += stageImage.height; } - currentColumn.push(stageImage); - currentHeight += stageImage.height; } await flushColumn(); diff --git a/src/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec.ts b/src/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec.ts index 8fbdec9..4e53afc 100644 --- a/src/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec.ts +++ b/src/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec.ts @@ -5,6 +5,7 @@ export interface EventStageCanvasLike { export const BANGDREAM_EVENT_STAGE_SPEC = { list: { maxColumnHeight: 6000, + stageBatchSize: 8, }, songRow: { difficultyHeightScale: 10, @@ -66,6 +67,13 @@ export function getEventStageSongRowSize(): { height: number; width: number } { }; } +/** + * 获取试炼 stage 绘制批大小。 + */ +export function getEventStageStageBatchSize(): number { + return BANGDREAM_EVENT_STAGE_SPEC.list.stageBatchSize; +} + /** * 判断下一张试炼 stage 图是否应该换到新列。 * diff --git a/test/qqbot/plugins/bangDream/tsugu/event-stage-spec.spec.ts b/test/qqbot/plugins/bangDream/tsugu/event-stage-spec.spec.ts index ca3243c..99794d6 100644 --- a/test/qqbot/plugins/bangDream/tsugu/event-stage-spec.spec.ts +++ b/test/qqbot/plugins/bangDream/tsugu/event-stage-spec.spec.ts @@ -4,6 +4,7 @@ import { getEventStageSongCellWidth, getEventStageSongJacketHeight, getEventStageSongRowSize, + getEventStageStageBatchSize, shouldStartNewEventStageColumn, splitEventStageImagesByColumnHeight, } from '@/qqbot/plugins/bangDream/tsugu/render-blocks/event-stage-spec'; @@ -23,6 +24,7 @@ describe('BangDream event stage spec', () => { expect(BANGDREAM_EVENT_STAGE_SPEC.typeTop.fontSize).toBe(25); expect(BANGDREAM_EVENT_STAGE_SPEC.typeTop.strokeWidth).toBe(4.5); expect(BANGDREAM_EVENT_STAGE_SPEC.list.maxColumnHeight).toBe(6000); + expect(getEventStageStageBatchSize()).toBe(8); }); it('splits stage images by max column height', () => {