diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-22 02:41:18 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-22 02:41:18 +0200 |
| commit | f5f31b43df9ef46f1afdd63ba759b2f9bd80e7a3 (patch) | |
| tree | 779132620064669a21c5fd9a787ba28187c0384e /apps/web/src/services/storage/migrations/transformers/v17-to-v18.ts | |
| parent | a709af0059dae4702b52197f34af85a817c59a6a (diff) | |
| download | opencut-f5f31b43df9ef46f1afdd63ba759b2f9bd80e7a3.tar.gz | |
refactor: migration run() and pure v1-to-v2 transform
Diffstat (limited to 'apps/web/src/services/storage/migrations/transformers/v17-to-v18.ts')
| -rw-r--r-- | apps/web/src/services/storage/migrations/transformers/v17-to-v18.ts | 218 |
1 files changed, 113 insertions, 105 deletions
diff --git a/apps/web/src/services/storage/migrations/transformers/v17-to-v18.ts b/apps/web/src/services/storage/migrations/transformers/v17-to-v18.ts index 3ef6cde9..660d91ee 100644 --- a/apps/web/src/services/storage/migrations/transformers/v17-to-v18.ts +++ b/apps/web/src/services/storage/migrations/transformers/v17-to-v18.ts @@ -1,105 +1,113 @@ -import type { MigrationResult, ProjectRecord } from "./types";
-import { VOLUME_DB_MIN } from "@/timeline/audio-constants";
-import { clampDb } from "@/timeline/audio-state";
-import { getProjectId, isRecord } from "./utils";
-
-export function transformProjectV17ToV18({
- project,
-}: {
- project: ProjectRecord;
-}): MigrationResult<ProjectRecord> {
- if (!getProjectId({ project })) {
- return { project, skipped: true, reason: "no project id" };
- }
-
- if (typeof project.version === "number" && project.version >= 18) {
- return { project, skipped: true, reason: "already v18" };
- }
-
- return {
- project: {
- ...migrateElementVolumes({ project }),
- version: 18,
- },
- skipped: false,
- };
-}
-
-function migrateElementVolumes({
- project,
-}: {
- project: ProjectRecord;
-}): ProjectRecord {
- const scenesValue = project.scenes;
- if (!Array.isArray(scenesValue)) {
- return project;
- }
-
- const migratedScenes = scenesValue.map((scene) => {
- if (!isRecord(scene)) {
- return scene;
- }
-
- const tracksValue = scene.tracks;
- if (!Array.isArray(tracksValue)) {
- return scene;
- }
-
- const migratedTracks = tracksValue.map((track) => {
- if (!isRecord(track)) {
- return track;
- }
-
- const elementsValue = track.elements;
- if (!Array.isArray(elementsValue)) {
- return track;
- }
-
- const migratedElements = elementsValue.map((element) => {
- if (!isRecord(element)) {
- return element;
- }
-
- if (element.type !== "audio" && element.type !== "video") {
- return element;
- }
-
- const legacyVolume = element.volume;
- return {
- ...element,
- volume:
- typeof legacyVolume === "number"
- ? linearGainToDb(legacyVolume)
- : 0,
- };
- });
-
- return {
- ...track,
- elements: migratedElements,
- };
- });
-
- return {
- ...scene,
- tracks: migratedTracks,
- };
- });
-
- return {
- ...project,
- scenes: migratedScenes,
- };
-}
-
-function linearGainToDb(gain: number): number {
- if (!Number.isFinite(gain)) {
- return 0;
- }
-
- if (gain <= 0) {
- return VOLUME_DB_MIN;
- }
-
- return clampDb(20 * Math.log10(gain));
-}
+import type { MigrationResult, ProjectRecord } from "./types"; +import { getProjectId, isRecord } from "./utils"; + +// Frozen snapshots of v18-era volume bounds. See ./README.md. +const VOLUME_DB_MIN = -60; +const VOLUME_DB_MAX = 20; + +export function transformProjectV17ToV18({ + project, +}: { + project: ProjectRecord; +}): MigrationResult<ProjectRecord> { + if (!getProjectId({ project })) { + return { project, skipped: true, reason: "no project id" }; + } + + if (typeof project.version === "number" && project.version >= 18) { + return { project, skipped: true, reason: "already v18" }; + } + + return { + project: { + ...migrateElementVolumes({ project }), + version: 18, + }, + skipped: false, + }; +} + +function migrateElementVolumes({ + project, +}: { + project: ProjectRecord; +}): ProjectRecord { + const scenesValue = project.scenes; + if (!Array.isArray(scenesValue)) { + return project; + } + + const migratedScenes = scenesValue.map((scene) => { + if (!isRecord(scene)) { + return scene; + } + + const tracksValue = scene.tracks; + if (!Array.isArray(tracksValue)) { + return scene; + } + + const migratedTracks = tracksValue.map((track) => { + if (!isRecord(track)) { + return track; + } + + const elementsValue = track.elements; + if (!Array.isArray(elementsValue)) { + return track; + } + + const migratedElements = elementsValue.map((element) => { + if (!isRecord(element)) { + return element; + } + + if (element.type !== "audio" && element.type !== "video") { + return element; + } + + const legacyVolume = element.volume; + return { + ...element, + volume: + typeof legacyVolume === "number" ? linearGainToDb(legacyVolume) : 0, + }; + }); + + return { + ...track, + elements: migratedElements, + }; + }); + + return { + ...scene, + tracks: migratedTracks, + }; + }); + + return { + ...project, + scenes: migratedScenes, + }; +} + +function linearGainToDb(gain: number): number { + if (!Number.isFinite(gain)) { + return 0; + } + + if (gain <= 0) { + return VOLUME_DB_MIN; + } + + return clampDb(20 * Math.log10(gain)); +} + +function clampDb(value: number): number { + if (!Number.isFinite(value)) { + return 0; + } + + return Math.min(VOLUME_DB_MAX, Math.max(VOLUME_DB_MIN, value)); +} |
