summaryrefslogtreecommitdiff
path: root/apps/web/src/services
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/services')
-rw-r--r--apps/web/src/services/renderer/scene-builder.ts22
-rw-r--r--apps/web/src/services/storage/migrations/index.ts4
-rw-r--r--apps/web/src/services/storage/migrations/transformers/v23-to-v24.ts113
-rw-r--r--apps/web/src/services/storage/migrations/v23-to-v24.ts16
-rw-r--r--apps/web/src/services/storage/service.ts22
5 files changed, 148 insertions, 29 deletions
diff --git a/apps/web/src/services/renderer/scene-builder.ts b/apps/web/src/services/renderer/scene-builder.ts
index 76b97021..22d941be 100644
--- a/apps/web/src/services/renderer/scene-builder.ts
+++ b/apps/web/src/services/renderer/scene-builder.ts
@@ -1,4 +1,4 @@
-import type { TimelineTrack } from "@/lib/timeline";
+import type { SceneTracks, TimelineTrack } from "@/lib/timeline";
import type { MediaAsset } from "@/lib/media/types";
import { RootNode } from "./nodes/root-node";
import { VideoNode } from "./nodes/video-node";
@@ -12,7 +12,6 @@ import { EffectLayerNode } from "./nodes/effect-layer-node";
import type { BaseNode } from "./nodes/base-node";
import type { TBackground, TCanvasSize } from "@/lib/project/types";
import { DEFAULT_BACKGROUND_BLUR_INTENSITY } from "@/lib/background/constants";
-import { isMainTrack } from "@/lib/timeline/placement";
const PREVIEW_MAX_IMAGE_SIZE = 2048;
@@ -209,7 +208,7 @@ function buildBlurBackgroundNodes({
export type BuildSceneParams = {
canvasSize: TCanvasSize;
- tracks: TimelineTrack[];
+ tracks: SceneTracks;
mediaAssets: MediaAsset[];
duration: number;
background: TBackground;
@@ -227,19 +226,12 @@ export function buildScene({
const rootNode = new RootNode({ duration });
const mediaMap = new Map(mediaAssets.map((m) => [m.id, m]));
- const visibleTracks = tracks.filter(
- (track) => !("hidden" in track && track.hidden),
- );
-
- const orderedTracksTopToBottom = [
- ...visibleTracks.filter((track) => !isMainTrack(track)),
- ...visibleTracks.filter((track) => isMainTrack(track)),
+ const visibleTracks = [
+ ...tracks.overlay.filter((track) => !("hidden" in track && track.hidden)),
+ ...(!tracks.main.hidden ? [tracks.main] : []),
];
-
- const orderedTracksBottomToTop = orderedTracksTopToBottom.slice().reverse();
- const mainTrack = orderedTracksBottomToTop.find((track) =>
- isMainTrack(track),
- );
+ const orderedTracksBottomToTop = visibleTracks.slice().reverse();
+ const mainTrack = tracks.main.hidden ? undefined : tracks.main;
const allNodes = buildTrackNodes({
tracks: orderedTracksBottomToTop,
diff --git a/apps/web/src/services/storage/migrations/index.ts b/apps/web/src/services/storage/migrations/index.ts
index 9f0f3e0d..b7ee37f5 100644
--- a/apps/web/src/services/storage/migrations/index.ts
+++ b/apps/web/src/services/storage/migrations/index.ts
@@ -22,10 +22,11 @@ import { V19toV20Migration } from "./v19-to-v20";
import { V20toV21Migration } from "./v20-to-v21";
import { V21toV22Migration } from "./v21-to-v22";
import { V22toV23Migration } from "./v22-to-v23";
+import { V23toV24Migration } from "./v23-to-v24";
export { runStorageMigrations } from "./runner";
export type { MigrationProgress } from "./runner";
-export const CURRENT_PROJECT_VERSION = 23;
+export const CURRENT_PROJECT_VERSION = 24;
export const migrations = [
new V0toV1Migration(),
@@ -51,4 +52,5 @@ export const migrations = [
new V20toV21Migration(),
new V21toV22Migration(),
new V22toV23Migration(),
+ new V23toV24Migration(),
];
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;
+}
diff --git a/apps/web/src/services/storage/migrations/v23-to-v24.ts b/apps/web/src/services/storage/migrations/v23-to-v24.ts
new file mode 100644
index 00000000..fe952bb1
--- /dev/null
+++ b/apps/web/src/services/storage/migrations/v23-to-v24.ts
@@ -0,0 +1,16 @@
+import { StorageMigration } from "./base";
+import type { ProjectRecord } from "./transformers/types";
+import { transformProjectV23ToV24 } from "./transformers/v23-to-v24";
+
+export class V23toV24Migration extends StorageMigration {
+ from = 23;
+ to = 24;
+
+ async transform(project: ProjectRecord): Promise<{
+ project: ProjectRecord;
+ skipped: boolean;
+ reason?: string;
+ }> {
+ return transformProjectV23ToV24({ project });
+ }
+}
diff --git a/apps/web/src/services/storage/service.ts b/apps/web/src/services/storage/service.ts
index 3a014894..1aea0297 100644
--- a/apps/web/src/services/storage/service.ts
+++ b/apps/web/src/services/storage/service.ts
@@ -21,7 +21,7 @@ import {
migrations,
runStorageMigrations,
} from "@/services/storage/migrations";
-import type { Bookmark, TimelineTrack, TScene } from "@/lib/timeline";
+import type { Bookmark, SceneTracks, TScene } from "@/lib/timeline";
function normalizeBookmarks({ raw }: { raw: unknown }): Bookmark[] {
if (!Array.isArray(raw)) return [];
@@ -116,18 +116,18 @@ class StorageService {
private stripAudioBuffers({
tracks,
}: {
- tracks: TimelineTrack[];
- }): TimelineTrack[] {
- return tracks.map((track) => {
- if (track.type !== "audio") return track;
- return {
+ tracks: SceneTracks;
+ }): SceneTracks {
+ return {
+ ...tracks,
+ audio: tracks.audio.map((track) => ({
...track,
elements: track.elements.map((element) => {
const { buffer: _buffer, ...rest } = element;
return rest;
}),
- };
- });
+ })),
+ };
}
async saveProject({ project }: { project: TProject }): Promise<void> {
@@ -178,11 +178,7 @@ class StorageService {
id: scene.id,
name: scene.name,
isMain: scene.isMain,
- tracks: (scene.tracks ?? []).map((track) =>
- track.type === "video"
- ? { ...track, isMain: track.isMain ?? false } // legacy: isMain was optional
- : track,
- ),
+ tracks: scene.tracks,
bookmarks: normalizeBookmarks({ raw: scene.bookmarks }),
createdAt: new Date(scene.createdAt),
updatedAt: new Date(scene.updatedAt),