diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-03-27 00:55:15 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-03-29 15:56:48 +0200 |
| commit | 4d127a038bf768eded68aae3cfa5c1b12241bdac (patch) | |
| tree | 16bbb801caf6770546cff4fdb37b6408ec9ead98 /apps/web/src/lib/commands/media | |
| parent | 82817cb50cb0487350573d6129130aec705f924b (diff) | |
| download | opencut-4d127a038bf768eded68aae3cfa5c1b12241bdac.tar.gz | |
chore: normalize line endings
Diffstat (limited to 'apps/web/src/lib/commands/media')
| -rw-r--r-- | apps/web/src/lib/commands/media/add-media-asset.ts | 34 | ||||
| -rw-r--r-- | apps/web/src/lib/commands/media/remove-media-asset.ts | 198 |
2 files changed, 133 insertions, 99 deletions
diff --git a/apps/web/src/lib/commands/media/add-media-asset.ts b/apps/web/src/lib/commands/media/add-media-asset.ts index a3dec0e6..86fa3e35 100644 --- a/apps/web/src/lib/commands/media/add-media-asset.ts +++ b/apps/web/src/lib/commands/media/add-media-asset.ts @@ -5,11 +5,15 @@ import type { MediaAsset } from "@/lib/media/types"; import { generateUUID } from "@/utils/id"; import { storageService } from "@/services/storage/service"; import { hasMediaId } from "@/lib/timeline/element-utils"; +import { getHighestImportedVideoFps } from "@/lib/project/fps"; +import { UpdateProjectSettingsCommand } from "@/lib/commands/project"; export class AddMediaAssetCommand extends Command { private assetId: string; private savedAssets: MediaAsset[] | null = null; private createdAsset: MediaAsset | null = null; + private previousProjectFps: number | null = null; + private appliedProjectFps: number | null = null; constructor( private projectId: string, @@ -31,6 +35,10 @@ export class AddMediaAssetCommand extends Command { editor.media.setAssets({ assets: [...this.savedAssets, this.createdAsset], }); + this.previousProjectFps = editor.project.getActiveOrNull()?.settings.fps ?? null; + this.appliedProjectFps = editor.project.ratchetFpsForImportedMedia({ + importedAssets: [this.createdAsset], + }); storageService .saveMediaAsset({ @@ -64,6 +72,8 @@ export class AddMediaAssetCommand extends Command { editor.timeline.deleteElements({ elements: orphanedElements }); } + this.restoreProjectFpsAfterFailedSave({ editor }); + if (storageService.isQuotaExceededError({ error })) { toast.error("Not enough browser storage", { description: error instanceof Error ? error.message : undefined, @@ -90,4 +100,28 @@ export class AddMediaAssetCommand extends Command { getAssetId(): string { return this.assetId; } + + private restoreProjectFpsAfterFailedSave({ + editor, + }: { + editor: EditorCore; + }): void { + if (this.previousProjectFps === null || this.appliedProjectFps === null) return; + + const activeProject = editor.project.getActiveOrNull(); + if (!activeProject) return; + if (activeProject.settings.fps !== this.appliedProjectFps) return; + + const highestRemainingVideoFps = getHighestImportedVideoFps({ + mediaAssets: editor.media.getAssets(), + }); + if ( + highestRemainingVideoFps !== null && + highestRemainingVideoFps >= this.appliedProjectFps + ) { + return; + } + + new UpdateProjectSettingsCommand({ fps: this.previousProjectFps }).execute(); + } } diff --git a/apps/web/src/lib/commands/media/remove-media-asset.ts b/apps/web/src/lib/commands/media/remove-media-asset.ts index f519baef..84b395ed 100644 --- a/apps/web/src/lib/commands/media/remove-media-asset.ts +++ b/apps/web/src/lib/commands/media/remove-media-asset.ts @@ -1,99 +1,99 @@ -import { Command } from "@/lib/commands/base-command"; -import { EditorCore } from "@/core"; -import type { MediaAsset } from "@/lib/media/types"; -import { storageService } from "@/services/storage/service"; -import { videoCache } from "@/services/video-cache/service"; -import { hasMediaId } from "@/lib/timeline/element-utils"; -import type { TimelineTrack } from "@/lib/timeline"; - -export class RemoveMediaAssetCommand extends Command { - private savedAssets: MediaAsset[] | null = null; - private savedTracks: TimelineTrack[] | null = null; - private removedAsset: MediaAsset | null = null; - - constructor( - private projectId: string, - private assetId: string, - ) { - super(); - } - - execute(): void { - const editor = EditorCore.getInstance(); - const assets = editor.media.getAssets(); - - this.savedAssets = [...assets]; - this.savedTracks = editor.timeline.getTracks(); - - this.removedAsset = - assets.find((media) => media.id === this.assetId) ?? null; - - if (!this.removedAsset) { - console.error("Media asset not found:", this.assetId); - return; - } - - if (this.removedAsset.url) { - URL.revokeObjectURL(this.removedAsset.url); - } - if (this.removedAsset.thumbnailUrl) { - URL.revokeObjectURL(this.removedAsset.thumbnailUrl); - } - - videoCache.clearVideo({ mediaId: this.assetId }); - - editor.media.setAssets({ - assets: assets.filter((media) => media.id !== this.assetId), - }); - - const elementsToRemove: Array<{ trackId: string; elementId: string }> = []; - - for (const track of this.savedTracks) { - for (const element of track.elements) { - if (hasMediaId(element) && element.mediaId === this.assetId) { - elementsToRemove.push({ trackId: track.id, elementId: element.id }); - } - } - } - - if (elementsToRemove.length > 0) { - editor.timeline.deleteElements({ elements: elementsToRemove }); - } - - storageService - .deleteMediaAsset({ projectId: this.projectId, id: this.assetId }) - .catch((error) => { - console.error("Failed to delete media item:", error); - }); - } - - undo(): void { - const editor = EditorCore.getInstance(); - - if (this.savedAssets && this.removedAsset) { - const restoredAsset: MediaAsset = { - ...this.removedAsset, - url: URL.createObjectURL(this.removedAsset.file), - }; - - editor.media.setAssets({ - assets: this.savedAssets.map((a) => - a.id === this.assetId ? restoredAsset : a, - ), - }); - - storageService - .saveMediaAsset({ - projectId: this.projectId, - mediaAsset: restoredAsset, - }) - .catch((error) => { - console.error("Failed to restore media item on undo:", error); - }); - } - - if (this.savedTracks) { - editor.timeline.updateTracks(this.savedTracks); - } - } -} +import { Command } from "@/lib/commands/base-command";
+import { EditorCore } from "@/core";
+import type { MediaAsset } from "@/lib/media/types";
+import { storageService } from "@/services/storage/service";
+import { videoCache } from "@/services/video-cache/service";
+import { hasMediaId } from "@/lib/timeline/element-utils";
+import type { TimelineTrack } from "@/lib/timeline";
+
+export class RemoveMediaAssetCommand extends Command {
+ private savedAssets: MediaAsset[] | null = null;
+ private savedTracks: TimelineTrack[] | null = null;
+ private removedAsset: MediaAsset | null = null;
+
+ constructor(
+ private projectId: string,
+ private assetId: string,
+ ) {
+ super();
+ }
+
+ execute(): void {
+ const editor = EditorCore.getInstance();
+ const assets = editor.media.getAssets();
+
+ this.savedAssets = [...assets];
+ this.savedTracks = editor.timeline.getTracks();
+
+ this.removedAsset =
+ assets.find((media) => media.id === this.assetId) ?? null;
+
+ if (!this.removedAsset) {
+ console.error("Media asset not found:", this.assetId);
+ return;
+ }
+
+ if (this.removedAsset.url) {
+ URL.revokeObjectURL(this.removedAsset.url);
+ }
+ if (this.removedAsset.thumbnailUrl) {
+ URL.revokeObjectURL(this.removedAsset.thumbnailUrl);
+ }
+
+ videoCache.clearVideo({ mediaId: this.assetId });
+
+ editor.media.setAssets({
+ assets: assets.filter((media) => media.id !== this.assetId),
+ });
+
+ const elementsToRemove: Array<{ trackId: string; elementId: string }> = [];
+
+ for (const track of this.savedTracks) {
+ for (const element of track.elements) {
+ if (hasMediaId(element) && element.mediaId === this.assetId) {
+ elementsToRemove.push({ trackId: track.id, elementId: element.id });
+ }
+ }
+ }
+
+ if (elementsToRemove.length > 0) {
+ editor.timeline.deleteElements({ elements: elementsToRemove });
+ }
+
+ storageService
+ .deleteMediaAsset({ projectId: this.projectId, id: this.assetId })
+ .catch((error) => {
+ console.error("Failed to delete media item:", error);
+ });
+ }
+
+ undo(): void {
+ const editor = EditorCore.getInstance();
+
+ if (this.savedAssets && this.removedAsset) {
+ const restoredAsset: MediaAsset = {
+ ...this.removedAsset,
+ url: URL.createObjectURL(this.removedAsset.file),
+ };
+
+ editor.media.setAssets({
+ assets: this.savedAssets.map((a) =>
+ a.id === this.assetId ? restoredAsset : a,
+ ),
+ });
+
+ storageService
+ .saveMediaAsset({
+ projectId: this.projectId,
+ mediaAsset: restoredAsset,
+ })
+ .catch((error) => {
+ console.error("Failed to restore media item on undo:", error);
+ });
+ }
+
+ if (this.savedTracks) {
+ editor.timeline.updateTracks(this.savedTracks);
+ }
+ }
+}
|
