summaryrefslogtreecommitdiff
path: root/apps/web/src/services/storage/migrations/transformers
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-07 04:41:27 +0200
committerMaze Winther <mazewinther@gmail.com>2026-04-07 04:41:27 +0200
commitcbd1b8212370c67b34a70dccd21bd82de72fead2 (patch)
treed97cbee2aae22c22b59c59a50e9f8a6af0ae8ccf /apps/web/src/services/storage/migrations/transformers
parent4f7d401a974047d37673ee8e3840dceaaddc295c (diff)
downloadopencut-cbd1b8212370c67b34a70dccd21bd82de72fead2.tar.gz
refactor: structured track layout per scene
Diffstat (limited to 'apps/web/src/services/storage/migrations/transformers')
-rw-r--r--apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts113
1 files changed, 113 insertions, 0 deletions
diff --git a/apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts b/apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts
new file mode 100644
index 00000000..710d4dc1
--- /dev/null
+++ b/apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts
@@ -0,0 +1,113 @@
+import type { MigrationResult, ProjectRecord } from "./types";
+import { getProjectId, isRecord } from "./utils";
+
+export function transformProjectV23ToV24({
+ project,
+}: {
+ project: ProjectRecord;
+}): MigrationResult<ProjectRecord> {
+ if (!getProjectId({ project })) {
+ return { project, skipped: true, reason: "no project id" };
+ }
+
+ const version = project.version;
+ if (typeof version !== "number") {
+ return { project, skipped: true, reason: "invalid version" };
+ }
+ if (version >= 24) {
+ return { project, skipped: true, reason: "already v24" };
+ }
+ if (version !== 23) {
+ return { project, skipped: true, reason: "not v23" };
+ }
+
+ return {
+ project: {
+ ...migrateProject({ project }),
+ version: 24,
+ },
+ skipped: false,
+ };
+}
+
+function migrateProject({
+ project,
+}: {
+ project: ProjectRecord;
+}): ProjectRecord {
+ if (!Array.isArray(project.scenes)) {
+ return project;
+ }
+
+ return {
+ ...project,
+ scenes: project.scenes.map((scene) => migrateScene({ scene })),
+ };
+}
+
+function migrateScene({ scene }: { scene: unknown }): unknown {
+ if (!isRecord(scene) || !Array.isArray(scene.tracks)) {
+ return scene;
+ }
+
+ const mainTrack = findMainTrack({ tracks: scene.tracks });
+ if (!mainTrack) {
+ return scene;
+ }
+
+ return {
+ ...scene,
+ tracks: {
+ overlay: scene.tracks
+ .filter((track) => track !== mainTrack)
+ .map((track) => migrateTrack({ track }))
+ .filter(
+ (track): track is ProjectRecord =>
+ isRecord(track) && track.type !== "audio",
+ ),
+ main: migrateTrack({ track: mainTrack }),
+ audio: scene.tracks
+ .map((track) => migrateTrack({ track }))
+ .filter(
+ (track): track is ProjectRecord =>
+ isRecord(track) && track.type === "audio",
+ ),
+ },
+ };
+}
+
+function findMainTrack({
+ tracks,
+}: {
+ tracks: unknown[];
+}): ProjectRecord | null {
+ for (const track of tracks) {
+ if (!isRecord(track)) {
+ continue;
+ }
+ if (track.type === "video" && track.isMain === true) {
+ return track;
+ }
+ }
+
+ for (const track of tracks) {
+ if (!isRecord(track)) {
+ continue;
+ }
+ if (track.type === "video") {
+ return track;
+ }
+ }
+
+ return null;
+}
+
+function migrateTrack({ track }: { track: unknown }): unknown {
+ if (!isRecord(track)) {
+ return track;
+ }
+
+ const nextTrack = { ...track };
+ delete nextTrack.isMain;
+ return nextTrack;
+}