10dcc2b403
修复画布上传素材持久化回填和项目重进资源元数据恢复 修复图片、音频、视频图层的私有资源换签与视频裸路径回退 修复宣发素材切换模型后卡片尺寸变成1024x1024的问题 修复音视频预览、媒体导出格式、音频默认提示词和前端去背边界 修复角色动作生成在编辑器路径缺少ffprobe时的已知时长兜底 补充图片画布、资源换签、宣发尺寸、媒体导出和chromaKey回归测试 更新图片画布编辑器技术文档
81 lines
2.1 KiB
TypeScript
81 lines
2.1 KiB
TypeScript
export function normalizeCanvasDurationSeconds(value: unknown) {
|
|
return typeof value === 'number' && Number.isFinite(value) && value > 0
|
|
? value
|
|
: null;
|
|
}
|
|
|
|
export function formatCanvasDurationLabel(value: unknown) {
|
|
const durationSeconds = normalizeCanvasDurationSeconds(value);
|
|
if (durationSeconds === null) {
|
|
return '--:--';
|
|
}
|
|
|
|
const totalSeconds = Math.max(1, Math.round(durationSeconds));
|
|
const hours = Math.floor(totalSeconds / 3600);
|
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
const seconds = totalSeconds % 60;
|
|
const paddedSeconds = String(seconds).padStart(2, '0');
|
|
|
|
if (hours > 0) {
|
|
return `${hours}:${String(minutes).padStart(2, '0')}:${paddedSeconds}`;
|
|
}
|
|
|
|
return `${minutes}:${paddedSeconds}`;
|
|
}
|
|
|
|
export function formatCanvasDurationMetric(value: unknown) {
|
|
// 中文注释:音频对象没有视觉分辨率语义,画布角标统一显示时长。
|
|
return `时长 ${formatCanvasDurationLabel(value)}`;
|
|
}
|
|
|
|
type MediaPreviewTone = 'audio' | 'video';
|
|
|
|
type MediaPreviewMarker = {
|
|
tone: MediaPreviewTone;
|
|
variant: number;
|
|
};
|
|
|
|
const MEDIA_PREVIEW_VARIANT_COUNT = 6;
|
|
|
|
function hashMediaPreviewSeed(seed: string) {
|
|
let hash = 0;
|
|
for (let index = 0; index < seed.length; index += 1) {
|
|
hash = (hash * 31 + seed.charCodeAt(index)) >>> 0;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
export function getCanvasMediaPreviewMarker({
|
|
mediaType,
|
|
assetKind,
|
|
title,
|
|
src,
|
|
}: {
|
|
mediaType?: string | null;
|
|
assetKind?: string | null;
|
|
title?: string | null;
|
|
src?: string | null;
|
|
}): MediaPreviewMarker | null {
|
|
if (mediaType !== 'audio' && mediaType !== 'video') {
|
|
return null;
|
|
}
|
|
const seed = `${assetKind ?? ''}|${title ?? ''}|${src ?? ''}`;
|
|
return {
|
|
tone: mediaType,
|
|
variant: hashMediaPreviewSeed(seed) % MEDIA_PREVIEW_VARIANT_COUNT,
|
|
};
|
|
}
|
|
|
|
export function getCanvasMediaPreviewClassName(
|
|
marker: MediaPreviewMarker | null,
|
|
) {
|
|
if (!marker) {
|
|
return '';
|
|
}
|
|
return [
|
|
'image-canvas-editor__media-preview',
|
|
`image-canvas-editor__media-preview--${marker.tone}`,
|
|
`image-canvas-editor__media-preview--variant-${marker.variant}`,
|
|
].join(' ');
|
|
}
|