// 资产到时间线片段的纯转换:只做类型映射和结构组装,不读取网络或修改编辑器状态。 // 资产是"仅时间线作用域"的直连媒体:nodeId 用 `asset:` 前缀(不指向画布节点), // 预览/导出从 directMedia 解析媒体,不回画布查节点。 import type { ProjectAsset } from "@/services/api/projects"; import type { TimelineClip, TimelineClipKind } from "@/types/timeline"; const MEDIA_TYPE_TO_KIND: Record = { video: "video", audio: "audio", image: "image", text: "text", }; export function assetToClipKind(mediaType: string): TimelineClipKind | null { return MEDIA_TYPE_TO_KIND[mediaType] ?? null; } export type MakeClipFromAssetOptions = { /** 目标轨道 id(调用方已按 kind 选好轨道)。 */ trackId: string; /** 时间线起点(毫秒,通常为该轨道当前末尾)。 */ startMs: number; /** 默认时长(毫秒);资产无时长元数据时使用。 */ defaultDurationMs?: number; /** 时间线内唯一 id(调用方负责去重,通常 `asset::`)。 */ id?: string; }; export function makeClipFromAsset(asset: ProjectAsset, options: MakeClipFromAssetOptions): TimelineClip | null { const kind = assetToClipKind(asset.mediaType); if (!kind) return null; if (kind === "text") return null; // 文本资产不直接入轨(走字幕/文字工具) return { id: options.id ?? `asset:${asset.id}`, kind, nodeId: `asset:${asset.id}`, trackId: options.trackId, startMs: options.startMs, durationMs: asset.durationMs && asset.durationMs > 0 ? asset.durationMs : (options.defaultDurationMs ?? 3_000), title: asset.title, directMedia: { id: asset.id, kind: kind === "subtitle" ? "text" : kind, title: asset.title, storageKey: asset.storageKey, }, }; }