修复旧媒体图层恢复类型
在缺少权威素材类型时保留历史音视频媒体类型 拆分图层恢复中的嵌套状态判定 补充旧音视频恢复回归测试
This commit is contained in:
@@ -602,6 +602,33 @@ describe('ImageCanvasEditorModel', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('preserves legacy audio and video media types when assetKind is absent', () => {
|
||||
for (const mediaType of ['video', 'audio'] as const) {
|
||||
const hydrated = hydrateLayer(
|
||||
{
|
||||
layerId: `legacy-${mediaType}-layer`,
|
||||
resourceId: `legacy-${mediaType}-resource`,
|
||||
title: `旧${mediaType}`,
|
||||
sourceType: 'uploaded',
|
||||
mediaType,
|
||||
},
|
||||
new Map([
|
||||
[
|
||||
`legacy-${mediaType}-resource`,
|
||||
{
|
||||
imageSrc:
|
||||
mediaType === 'video'
|
||||
? '/legacy/cutscene.mp4'
|
||||
: '/legacy/theme.mp3',
|
||||
},
|
||||
],
|
||||
]),
|
||||
);
|
||||
|
||||
expect(hydrated?.mediaType).toBe(mediaType);
|
||||
}
|
||||
});
|
||||
|
||||
it('recovers the normal source model after the owner payload removes an internal model', () => {
|
||||
const hydrated = hydrateLayer(
|
||||
{
|
||||
|
||||
@@ -761,11 +761,15 @@ export function hydrateLayer(
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
const imageSequenceFrames = isFormalCharacterAnimation
|
||||
? resourceImageSequenceFrames
|
||||
: isSelfContainedLocalResource || snapshot.mediaType === 'image-sequence'
|
||||
? snapshotImageSequenceFrames
|
||||
: [];
|
||||
let imageSequenceFrames: NonNullable<CanvasLayer['imageSequenceFrames']> = [];
|
||||
if (isFormalCharacterAnimation) {
|
||||
imageSequenceFrames = resourceImageSequenceFrames;
|
||||
} else if (
|
||||
isSelfContainedLocalResource ||
|
||||
snapshot.mediaType === 'image-sequence'
|
||||
) {
|
||||
imageSequenceFrames = snapshotImageSequenceFrames;
|
||||
}
|
||||
const firstSequenceFrame = imageSequenceFrames[0]?.imageSrc ?? '';
|
||||
const src = isFormalCharacterAnimation
|
||||
? firstSequenceFrame || resource?.imageSrc || ''
|
||||
@@ -786,16 +790,37 @@ export function hydrateLayer(
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
let resourcePersistenceState: CanvasLayer['resourcePersistenceState'];
|
||||
if (resource) {
|
||||
resourcePersistenceState = 'registered';
|
||||
} else if (isSelfContainedLocalResource) {
|
||||
resourcePersistenceState = 'self-contained-local';
|
||||
} else if (resourceId.startsWith('local-')) {
|
||||
resourcePersistenceState = 'unresolved-local';
|
||||
}
|
||||
let sourceType: CanvasLayer['sourceType'] = 'uploaded';
|
||||
if (isCanvasSourceType(resource?.sourceType)) {
|
||||
sourceType = resource.sourceType;
|
||||
} else if (isCanvasSourceType(snapshot.sourceType)) {
|
||||
sourceType = snapshot.sourceType;
|
||||
}
|
||||
const mediaType = resolveHydratedLayerMediaType(
|
||||
snapshot,
|
||||
assetKind,
|
||||
isSelfContainedLocalResource,
|
||||
);
|
||||
let imageSequenceDurationMs: number | undefined;
|
||||
if (isFormalCharacterAnimation) {
|
||||
imageSequenceDurationMs =
|
||||
audioDurationOrNull(resource?.imageSequenceDurationMs) ?? undefined;
|
||||
} else if (isSelfContainedLocalResource) {
|
||||
imageSequenceDurationMs =
|
||||
audioDurationOrNull(snapshot.imageSequenceDurationMs) ?? undefined;
|
||||
}
|
||||
return {
|
||||
id: layerId,
|
||||
resourceId,
|
||||
resourcePersistenceState: resource
|
||||
? 'registered'
|
||||
: isSelfContainedLocalResource
|
||||
? 'self-contained-local'
|
||||
: resourceId.startsWith('local-')
|
||||
? 'unresolved-local'
|
||||
: undefined,
|
||||
resourcePersistenceState,
|
||||
title,
|
||||
src,
|
||||
x: numberFromSnapshot(snapshot.x, 0),
|
||||
@@ -813,14 +838,8 @@ export function hydrateLayer(
|
||||
};
|
||||
})(),
|
||||
zIndex: numberFromSnapshot(snapshot.zIndex, 1),
|
||||
sourceType: isCanvasSourceType(resource?.sourceType)
|
||||
? resource.sourceType
|
||||
: isCanvasSourceType(snapshot.sourceType)
|
||||
? snapshot.sourceType
|
||||
: 'uploaded',
|
||||
mediaType: isSelfContainedLocalResource
|
||||
? 'image-sequence'
|
||||
: resolveCanvasMediaTypeFromAssetKind(assetKind),
|
||||
sourceType,
|
||||
mediaType,
|
||||
thumbnailSrc: isFormalCharacterAnimation
|
||||
? firstSequenceFrame || null
|
||||
: stringOrNull(snapshot.thumbnailSrc),
|
||||
@@ -860,11 +879,7 @@ export function hydrateLayer(
|
||||
? undefined
|
||||
: (audioDurationOrNull(snapshot.durationSeconds) ??
|
||||
audioDurationOrNull(resource?.durationSeconds)),
|
||||
imageSequenceDurationMs: isFormalCharacterAnimation
|
||||
? audioDurationOrNull(resource?.imageSequenceDurationMs)
|
||||
: isSelfContainedLocalResource
|
||||
? audioDurationOrNull(snapshot.imageSequenceDurationMs)
|
||||
: undefined,
|
||||
imageSequenceDurationMs,
|
||||
sourceResourceId: isFormalCharacterAnimation
|
||||
? stringOrNull(resource?.sourceResourceId)
|
||||
: (stringOrNull(snapshot.sourceResourceId) ??
|
||||
@@ -887,6 +902,23 @@ export function hydrateLayer(
|
||||
};
|
||||
}
|
||||
|
||||
function resolveHydratedLayerMediaType(
|
||||
snapshot: EditorProjectLayerSnapshot,
|
||||
assetKind: CanvasAssetKind | null,
|
||||
isSelfContainedLocalResource: boolean,
|
||||
): CanvasMediaType {
|
||||
if (isSelfContainedLocalResource) {
|
||||
return 'image-sequence';
|
||||
}
|
||||
if (assetKind) {
|
||||
return resolveCanvasMediaTypeFromAssetKind(assetKind);
|
||||
}
|
||||
if (snapshot.mediaType === 'video' || snapshot.mediaType === 'audio') {
|
||||
return snapshot.mediaType;
|
||||
}
|
||||
return 'image';
|
||||
}
|
||||
|
||||
function isSelfContainedLegacyLocalImageSequence(
|
||||
snapshot: EditorProjectLayerSnapshot,
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user