120 lines
3.1 KiB
TypeScript
120 lines
3.1 KiB
TypeScript
import { Command, type CommandResult } from "@/commands/base-command";
|
|
import { EditorCore } from "@/core";
|
|
import type { MediaAsset } from "@/media/types";
|
|
import { buildWaveformSourceKey } from "@/media/waveform-summary";
|
|
import { storageService } from "@/services/storage/service";
|
|
import { videoCache } from "@/services/video-cache/service";
|
|
import { waveformCache } from "@/services/waveform-cache/service";
|
|
import { hasMediaId } from "@/timeline/element-utils";
|
|
import type { SceneTracks } from "@/timeline";
|
|
|
|
export class RemoveMediaAssetCommand extends Command {
|
|
private savedAssets: MediaAsset[] | null = null;
|
|
private savedTracks: SceneTracks | null = null;
|
|
private removedAsset: MediaAsset | null = null;
|
|
|
|
constructor({
|
|
projectId,
|
|
assetId,
|
|
}: {
|
|
projectId: string;
|
|
assetId: string;
|
|
}) {
|
|
super();
|
|
this.projectId = projectId;
|
|
this.assetId = assetId;
|
|
}
|
|
|
|
private projectId: string;
|
|
private assetId: string;
|
|
|
|
execute(): CommandResult | undefined {
|
|
const editor = EditorCore.getInstance();
|
|
const assets = editor.media.getAssets();
|
|
|
|
this.savedAssets = [...assets];
|
|
this.savedTracks = editor.scenes.getActiveScene().tracks;
|
|
|
|
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 });
|
|
waveformCache.clearSource({
|
|
sourceKey: buildWaveformSourceKey({
|
|
kind: "media",
|
|
id: 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.overlay,
|
|
this.savedTracks.main,
|
|
...this.savedTracks.audio,
|
|
]) {
|
|
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);
|
|
}
|
|
}
|
|
}
|