summaryrefslogtreecommitdiff
path: root/apps/web/src/services/storage/migrations/v1-to-v2.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-02-03 14:00:04 +0100
committerMaze Winther <mazewinther@gmail.com>2026-02-03 14:00:04 +0100
commit7366cb27e98d9e0b15e0176ac7ca32816c460284 (patch)
tree07635628d37c06489519f7daf336c7f3f4fd3a2a /apps/web/src/services/storage/migrations/v1-to-v2.ts
parent34daad9df7ed6dac4fbeba8619ca1958bb2dac86 (diff)
downloadopencut-7366cb27e98d9e0b15e0176ac7ca32816c460284.tar.gz
fix v1 to v2 migration
Diffstat (limited to 'apps/web/src/services/storage/migrations/v1-to-v2.ts')
-rw-r--r--apps/web/src/services/storage/migrations/v1-to-v2.ts87
1 files changed, 76 insertions, 11 deletions
diff --git a/apps/web/src/services/storage/migrations/v1-to-v2.ts b/apps/web/src/services/storage/migrations/v1-to-v2.ts
index a4e1f20b..d593d8a1 100644
--- a/apps/web/src/services/storage/migrations/v1-to-v2.ts
+++ b/apps/web/src/services/storage/migrations/v1-to-v2.ts
@@ -1,10 +1,14 @@
-/*
- * Adds default values for new project properties introduced in v2
- */
-
-import { IndexedDBAdapter } from "@/services/storage/indexeddb-adapter";
+import {
+ IndexedDBAdapter,
+ deleteDatabase,
+} from "@/services/storage/indexeddb-adapter";
+import type { MediaAssetData } from "@/services/storage/types";
import { StorageMigration } from "./base";
-import { getProjectId, transformProjectV1ToV2 } from "./transformers/v1-to-v2";
+import {
+ getProjectId,
+ transformProjectV1ToV2,
+ type TransformV1ToV2Options,
+} from "./transformers/v1-to-v2";
export class V1toV2Migration extends StorageMigration {
from = 1;
@@ -23,20 +27,81 @@ export class V1toV2Migration extends StorageMigration {
continue;
}
- const result = transformProjectV1ToV2({
+ const projectId = getProjectId({
project: project as Record<string, unknown>,
});
-
- if (result.skipped) {
+ if (!projectId) {
continue;
}
- const projectId = getProjectId({ project: result.project });
- if (!projectId) {
+ const loadMediaAsset = createMediaAssetLoader({ projectId });
+
+ const result = await transformProjectV1ToV2({
+ project: project as Record<string, unknown>,
+ options: { loadMediaAsset },
+ });
+
+ if (result.skipped) {
continue;
}
await projectsAdapter.set(projectId, result.project);
+
+ await cleanupLegacyTimelineDBs({ projectId, project: result.project });
+ }
+ }
+}
+
+function createMediaAssetLoader({
+ projectId,
+}: {
+ projectId: string;
+}): TransformV1ToV2Options["loadMediaAsset"] {
+ return async ({ mediaId }: { mediaId: string }) => {
+ const mediaMetadataAdapter = new IndexedDBAdapter<MediaAssetData>(
+ `video-editor-media-${projectId}`,
+ "media-metadata",
+ 1,
+ );
+
+ return mediaMetadataAdapter.get(mediaId);
+ };
+}
+
+async function cleanupLegacyTimelineDBs({
+ projectId,
+ project,
+}: {
+ projectId: string;
+ project: Record<string, unknown>;
+}): Promise<void> {
+ const scenes = project.scenes;
+ if (!Array.isArray(scenes)) {
+ return;
+ }
+
+ const dbNamesToDelete: string[] = [];
+
+ for (const scene of scenes) {
+ if (typeof scene !== "object" || scene === null) {
+ continue;
+ }
+
+ const sceneId = scene.id;
+ if (typeof sceneId === "string") {
+ const sceneDbName = `video-editor-timelines-${projectId}-${sceneId}`;
+ dbNamesToDelete.push(sceneDbName);
+ }
+ }
+
+ const projectDbName = `video-editor-timelines-${projectId}`;
+ dbNamesToDelete.push(projectDbName);
+
+ for (const dbName of dbNamesToDelete) {
+ try {
+ await deleteDatabase({ dbName });
+ } catch {
+ // ignore errors, DB might not exist or already deleted
}
}
}