mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
chore: normalize line endings
This commit is contained in:
@@ -1,272 +1,272 @@
|
||||
import type { TimelineTrack } from "@/lib/timeline";
|
||||
import type { MediaAsset } from "@/lib/media/types";
|
||||
import { RootNode } from "./nodes/root-node";
|
||||
import { VideoNode } from "./nodes/video-node";
|
||||
import { ImageNode } from "./nodes/image-node";
|
||||
import { TextNode } from "./nodes/text-node";
|
||||
import { StickerNode } from "./nodes/sticker-node";
|
||||
import { GraphicNode } from "./nodes/graphic-node";
|
||||
import { ColorNode } from "./nodes/color-node";
|
||||
import { BlurBackgroundNode } from "./nodes/blur-background-node";
|
||||
import { EffectLayerNode } from "./nodes/effect-layer-node";
|
||||
import type { BaseNode } from "./nodes/base-node";
|
||||
import type { TBackground, TCanvasSize } from "@/lib/project/types";
|
||||
import { DEFAULT_BLUR_INTENSITY } from "@/constants/project-constants";
|
||||
import { isMainTrack } from "@/lib/timeline";
|
||||
|
||||
const PREVIEW_MAX_IMAGE_SIZE = 2048;
|
||||
|
||||
function getVisibleSortedElements({ track }: { track: TimelineTrack }) {
|
||||
return track.elements
|
||||
.filter((element) => !("hidden" in element && element.hidden))
|
||||
.slice()
|
||||
.sort((a, b) => {
|
||||
if (a.startTime !== b.startTime) return a.startTime - b.startTime;
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
}
|
||||
|
||||
function buildTrackNodes({
|
||||
tracks,
|
||||
mediaMap,
|
||||
canvasSize,
|
||||
isPreview,
|
||||
}: {
|
||||
tracks: TimelineTrack[];
|
||||
mediaMap: Map<string, MediaAsset>;
|
||||
canvasSize: TCanvasSize;
|
||||
isPreview?: boolean;
|
||||
}): BaseNode[] {
|
||||
const nodes: BaseNode[] = [];
|
||||
|
||||
for (const track of tracks) {
|
||||
const elements = getVisibleSortedElements({ track });
|
||||
|
||||
for (const element of elements) {
|
||||
if (element.type === "effect") {
|
||||
nodes.push(
|
||||
new EffectLayerNode({
|
||||
effectType: element.effectType,
|
||||
effectParams: element.params,
|
||||
timeOffset: element.startTime,
|
||||
duration: element.duration,
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (element.type === "video" || element.type === "image") {
|
||||
const mediaAsset = mediaMap.get(element.mediaId);
|
||||
if (!mediaAsset?.file || !mediaAsset?.url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (element.type === "video" && mediaAsset.type === "video") {
|
||||
nodes.push(
|
||||
new VideoNode({
|
||||
mediaId: mediaAsset.id,
|
||||
url: mediaAsset.url,
|
||||
file: mediaAsset.file,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
retime: element.retime,
|
||||
transform: element.transform,
|
||||
animations: element.animations,
|
||||
opacity: element.opacity,
|
||||
blendMode: element.blendMode,
|
||||
effects: element.effects,
|
||||
masks: element.masks,
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (element.type === "image" && mediaAsset.type === "image") {
|
||||
nodes.push(
|
||||
new ImageNode({
|
||||
url: mediaAsset.url,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
transform: element.transform,
|
||||
animations: element.animations,
|
||||
opacity: element.opacity,
|
||||
blendMode: element.blendMode,
|
||||
effects: element.effects,
|
||||
masks: element.masks,
|
||||
...(isPreview && {
|
||||
maxSourceSize: PREVIEW_MAX_IMAGE_SIZE,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (element.type === "text") {
|
||||
nodes.push(
|
||||
new TextNode({
|
||||
...element,
|
||||
canvasCenter: { x: canvasSize.width / 2, y: canvasSize.height / 2 },
|
||||
canvasHeight: canvasSize.height,
|
||||
textBaseline: "middle",
|
||||
effects: element.effects,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (element.type === "sticker") {
|
||||
nodes.push(
|
||||
new StickerNode({
|
||||
stickerId: element.stickerId,
|
||||
intrinsicWidth: element.intrinsicWidth,
|
||||
intrinsicHeight: element.intrinsicHeight,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
transform: element.transform,
|
||||
animations: element.animations,
|
||||
opacity: element.opacity,
|
||||
blendMode: element.blendMode,
|
||||
effects: element.effects,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (element.type === "graphic") {
|
||||
nodes.push(
|
||||
new GraphicNode({
|
||||
definitionId: element.definitionId,
|
||||
params: element.params,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
transform: element.transform,
|
||||
animations: element.animations,
|
||||
opacity: element.opacity,
|
||||
blendMode: element.blendMode,
|
||||
effects: element.effects,
|
||||
masks: element.masks,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function buildBlurBackgroundNodes({
|
||||
track,
|
||||
mediaMap,
|
||||
blurIntensity,
|
||||
}: {
|
||||
track: TimelineTrack | undefined;
|
||||
mediaMap: Map<string, MediaAsset>;
|
||||
blurIntensity: number;
|
||||
}): BaseNode[] {
|
||||
if (!track) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const nodes: BaseNode[] = [];
|
||||
const elements = getVisibleSortedElements({ track });
|
||||
|
||||
for (const element of elements) {
|
||||
if (element.type !== "video" && element.type !== "image") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mediaAsset = mediaMap.get(element.mediaId);
|
||||
if (
|
||||
!mediaAsset?.file ||
|
||||
!mediaAsset?.url ||
|
||||
(mediaAsset.type !== "video" && mediaAsset.type !== "image")
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nodes.push(
|
||||
new BlurBackgroundNode({
|
||||
mediaId: mediaAsset.id,
|
||||
url: mediaAsset.url,
|
||||
file: mediaAsset.file,
|
||||
mediaType: mediaAsset.type,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
retime: element.type === "video" ? element.retime : undefined,
|
||||
blurIntensity,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export type BuildSceneParams = {
|
||||
canvasSize: TCanvasSize;
|
||||
tracks: TimelineTrack[];
|
||||
mediaAssets: MediaAsset[];
|
||||
duration: number;
|
||||
background: TBackground;
|
||||
isPreview?: boolean;
|
||||
};
|
||||
|
||||
export function buildScene({
|
||||
canvasSize,
|
||||
tracks,
|
||||
mediaAssets,
|
||||
duration,
|
||||
background,
|
||||
isPreview,
|
||||
}: BuildSceneParams) {
|
||||
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 orderedTracksBottomToTop = orderedTracksTopToBottom.slice().reverse();
|
||||
const mainTrack = orderedTracksBottomToTop.find((track) =>
|
||||
isMainTrack(track),
|
||||
);
|
||||
|
||||
const allNodes = buildTrackNodes({
|
||||
tracks: orderedTracksBottomToTop,
|
||||
mediaMap,
|
||||
canvasSize,
|
||||
isPreview,
|
||||
});
|
||||
|
||||
if (background.type === "blur") {
|
||||
const blurNodes = buildBlurBackgroundNodes({
|
||||
track: mainTrack,
|
||||
mediaMap,
|
||||
blurIntensity: background.blurIntensity ?? DEFAULT_BLUR_INTENSITY,
|
||||
});
|
||||
for (const node of blurNodes) {
|
||||
rootNode.add(node);
|
||||
}
|
||||
} else if (
|
||||
background.type === "color" &&
|
||||
background.color !== "transparent"
|
||||
) {
|
||||
rootNode.add(new ColorNode({ color: background.color }));
|
||||
}
|
||||
|
||||
for (const node of allNodes) {
|
||||
rootNode.add(node);
|
||||
}
|
||||
|
||||
return rootNode;
|
||||
}
|
||||
import type { TimelineTrack } from "@/lib/timeline";
|
||||
import type { MediaAsset } from "@/lib/media/types";
|
||||
import { RootNode } from "./nodes/root-node";
|
||||
import { VideoNode } from "./nodes/video-node";
|
||||
import { ImageNode } from "./nodes/image-node";
|
||||
import { TextNode } from "./nodes/text-node";
|
||||
import { StickerNode } from "./nodes/sticker-node";
|
||||
import { GraphicNode } from "./nodes/graphic-node";
|
||||
import { ColorNode } from "./nodes/color-node";
|
||||
import { BlurBackgroundNode } from "./nodes/blur-background-node";
|
||||
import { EffectLayerNode } from "./nodes/effect-layer-node";
|
||||
import type { BaseNode } from "./nodes/base-node";
|
||||
import type { TBackground, TCanvasSize } from "@/lib/project/types";
|
||||
import { DEFAULT_BLUR_INTENSITY } from "@/constants/project-constants";
|
||||
import { isMainTrack } from "@/lib/timeline";
|
||||
|
||||
const PREVIEW_MAX_IMAGE_SIZE = 2048;
|
||||
|
||||
function getVisibleSortedElements({ track }: { track: TimelineTrack }) {
|
||||
return track.elements
|
||||
.filter((element) => !("hidden" in element && element.hidden))
|
||||
.slice()
|
||||
.sort((a, b) => {
|
||||
if (a.startTime !== b.startTime) return a.startTime - b.startTime;
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
}
|
||||
|
||||
function buildTrackNodes({
|
||||
tracks,
|
||||
mediaMap,
|
||||
canvasSize,
|
||||
isPreview,
|
||||
}: {
|
||||
tracks: TimelineTrack[];
|
||||
mediaMap: Map<string, MediaAsset>;
|
||||
canvasSize: TCanvasSize;
|
||||
isPreview?: boolean;
|
||||
}): BaseNode[] {
|
||||
const nodes: BaseNode[] = [];
|
||||
|
||||
for (const track of tracks) {
|
||||
const elements = getVisibleSortedElements({ track });
|
||||
|
||||
for (const element of elements) {
|
||||
if (element.type === "effect") {
|
||||
nodes.push(
|
||||
new EffectLayerNode({
|
||||
effectType: element.effectType,
|
||||
effectParams: element.params,
|
||||
timeOffset: element.startTime,
|
||||
duration: element.duration,
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (element.type === "video" || element.type === "image") {
|
||||
const mediaAsset = mediaMap.get(element.mediaId);
|
||||
if (!mediaAsset?.file || !mediaAsset?.url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (element.type === "video" && mediaAsset.type === "video") {
|
||||
nodes.push(
|
||||
new VideoNode({
|
||||
mediaId: mediaAsset.id,
|
||||
url: mediaAsset.url,
|
||||
file: mediaAsset.file,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
retime: element.retime,
|
||||
transform: element.transform,
|
||||
animations: element.animations,
|
||||
opacity: element.opacity,
|
||||
blendMode: element.blendMode,
|
||||
effects: element.effects,
|
||||
masks: element.masks,
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (element.type === "image" && mediaAsset.type === "image") {
|
||||
nodes.push(
|
||||
new ImageNode({
|
||||
url: mediaAsset.url,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
transform: element.transform,
|
||||
animations: element.animations,
|
||||
opacity: element.opacity,
|
||||
blendMode: element.blendMode,
|
||||
effects: element.effects,
|
||||
masks: element.masks,
|
||||
...(isPreview && {
|
||||
maxSourceSize: PREVIEW_MAX_IMAGE_SIZE,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (element.type === "text") {
|
||||
nodes.push(
|
||||
new TextNode({
|
||||
...element,
|
||||
canvasCenter: { x: canvasSize.width / 2, y: canvasSize.height / 2 },
|
||||
canvasHeight: canvasSize.height,
|
||||
textBaseline: "middle",
|
||||
effects: element.effects,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (element.type === "sticker") {
|
||||
nodes.push(
|
||||
new StickerNode({
|
||||
stickerId: element.stickerId,
|
||||
intrinsicWidth: element.intrinsicWidth,
|
||||
intrinsicHeight: element.intrinsicHeight,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
transform: element.transform,
|
||||
animations: element.animations,
|
||||
opacity: element.opacity,
|
||||
blendMode: element.blendMode,
|
||||
effects: element.effects,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (element.type === "graphic") {
|
||||
nodes.push(
|
||||
new GraphicNode({
|
||||
definitionId: element.definitionId,
|
||||
params: element.params,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
transform: element.transform,
|
||||
animations: element.animations,
|
||||
opacity: element.opacity,
|
||||
blendMode: element.blendMode,
|
||||
effects: element.effects,
|
||||
masks: element.masks,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function buildBlurBackgroundNodes({
|
||||
track,
|
||||
mediaMap,
|
||||
blurIntensity,
|
||||
}: {
|
||||
track: TimelineTrack | undefined;
|
||||
mediaMap: Map<string, MediaAsset>;
|
||||
blurIntensity: number;
|
||||
}): BaseNode[] {
|
||||
if (!track) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const nodes: BaseNode[] = [];
|
||||
const elements = getVisibleSortedElements({ track });
|
||||
|
||||
for (const element of elements) {
|
||||
if (element.type !== "video" && element.type !== "image") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mediaAsset = mediaMap.get(element.mediaId);
|
||||
if (
|
||||
!mediaAsset?.file ||
|
||||
!mediaAsset?.url ||
|
||||
(mediaAsset.type !== "video" && mediaAsset.type !== "image")
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nodes.push(
|
||||
new BlurBackgroundNode({
|
||||
mediaId: mediaAsset.id,
|
||||
url: mediaAsset.url,
|
||||
file: mediaAsset.file,
|
||||
mediaType: mediaAsset.type,
|
||||
duration: element.duration,
|
||||
timeOffset: element.startTime,
|
||||
trimStart: element.trimStart,
|
||||
trimEnd: element.trimEnd,
|
||||
retime: element.type === "video" ? element.retime : undefined,
|
||||
blurIntensity,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export type BuildSceneParams = {
|
||||
canvasSize: TCanvasSize;
|
||||
tracks: TimelineTrack[];
|
||||
mediaAssets: MediaAsset[];
|
||||
duration: number;
|
||||
background: TBackground;
|
||||
isPreview?: boolean;
|
||||
};
|
||||
|
||||
export function buildScene({
|
||||
canvasSize,
|
||||
tracks,
|
||||
mediaAssets,
|
||||
duration,
|
||||
background,
|
||||
isPreview,
|
||||
}: BuildSceneParams) {
|
||||
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 orderedTracksBottomToTop = orderedTracksTopToBottom.slice().reverse();
|
||||
const mainTrack = orderedTracksBottomToTop.find((track) =>
|
||||
isMainTrack(track),
|
||||
);
|
||||
|
||||
const allNodes = buildTrackNodes({
|
||||
tracks: orderedTracksBottomToTop,
|
||||
mediaMap,
|
||||
canvasSize,
|
||||
isPreview,
|
||||
});
|
||||
|
||||
if (background.type === "blur") {
|
||||
const blurNodes = buildBlurBackgroundNodes({
|
||||
track: mainTrack,
|
||||
mediaMap,
|
||||
blurIntensity: background.blurIntensity ?? DEFAULT_BLUR_INTENSITY,
|
||||
});
|
||||
for (const node of blurNodes) {
|
||||
rootNode.add(node);
|
||||
}
|
||||
} else if (
|
||||
background.type === "color" &&
|
||||
background.color !== "transparent"
|
||||
) {
|
||||
rootNode.add(new ColorNode({ color: background.color }));
|
||||
}
|
||||
|
||||
for (const node of allNodes) {
|
||||
rootNode.add(node);
|
||||
}
|
||||
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user