Skip to content
This repository was archived by the owner on Aug 17, 2025. It is now read-only.

Commit bd00f27

Browse files
committed
Started implementing plugin for video support
1 parent 402ee7f commit bd00f27

File tree

8 files changed

+112
-46
lines changed

8 files changed

+112
-46
lines changed

src/features/graph/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
export * from "./store/index"
1+
export * from "./store/index"
2+
export * from "./renderer"
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
export { type IRenderer } from "./IRenderer"
2-
export { type IRendererRegistry } from "./IRenderer"
3-
export { rendererRegistry } from "./rendererRegistry"
4-
1+
export { type IRenderer, type IRendererRegistry } from "./IRenderer"
2+
export { rendererRegistry, type NodeRenderer } from "./rendererRegistry"
53
export { default as NodesRenderer } from "./components/NodesRenderer"

src/plugins/video/VideoImporter.ts

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,55 @@
1-
import { addNode } from "@/redux/nodes/nodesSlice";
2-
import { Dispatch } from "@reduxjs/toolkit";
3-
import { createNode } from "@/utils/nodeUtils";
4-
import { IImporter } from "@/features/importing/IImporter";
1+
import { addNode } from "@/features/graph"
2+
import { IImporter, ImportEvent, ImportResult } from "@/features/importing"
3+
import { getFileFormat } from "@/utils"
4+
import { createNodeFromImportEvent } from "@/utils/nodeUtils"
5+
import { VideoNodeData } from "./types"
56

6-
export class VideoImporter extends IImporter {
7-
importData(file: File, dispatch: Dispatch): void {
8-
const videoUrl = URL.createObjectURL(file);
9-
const video = document.createElement('video') as HTMLVideoElement;
10-
11-
video.onloadedmetadata = () => {
12-
const newNode = createNode({
13-
type: "video",
14-
position: {
15-
x: 0,
16-
y: 0,
17-
},
18-
size: {
19-
width: video.videoWidth,
20-
height: video.videoHeight,
21-
},
22-
aspect: video.videoWidth / video.videoHeight,
23-
data: {
24-
src: videoUrl,
25-
alt: file.name,
26-
type: file.type
27-
}
28-
})
29-
dispatch(addNode(newNode));
7+
const VIDEO_FORMATS = ['mp4', 'webm', 'ogg']
8+
export class VideoImporter implements IImporter {
9+
async canHandle(_file: File, content: ArrayBuffer): Promise<boolean> {
10+
const fileType = await getFileFormat(content)
11+
if (!fileType) {
12+
return false
3013
}
31-
video.src = videoUrl;
14+
15+
return Promise.resolve(VIDEO_FORMATS.includes(fileType))
3216
}
3317

34-
getSupportedFormats(): string[] {
35-
return ['mp4', 'webm', 'ogg']
18+
async importData(event: ImportEvent): Promise<ImportResult> {
19+
try {
20+
const videoUrl = URL.createObjectURL(event.file)
21+
const video = document.createElement('video') as HTMLVideoElement
22+
video.src = videoUrl
23+
24+
await new Promise<void>((resolve, reject) => {
25+
video.onloadedmetadata = () => resolve()
26+
video.onerror = () => reject(new Error("Failed to load video metadata"))
27+
})
28+
29+
const file = event.file
30+
const size = {
31+
width: video.videoWidth,
32+
height: video.videoHeight,
33+
}
34+
35+
video.onloadedmetadata = () => {
36+
const newNode = createNodeFromImportEvent<VideoNodeData>(event, size,
37+
{
38+
type: "video",
39+
data: {
40+
src: videoUrl,
41+
type: file.type
42+
}
43+
})
44+
event.dispatch(addNode(newNode))
45+
}
46+
video.src = videoUrl
47+
console.log("Video URL: ", videoUrl)
48+
49+
return { success: true, message: 'Image imported successfully.' }
50+
} catch (error) {
51+
const message = error instanceof Error ? error.message : String(error)
52+
return { success: false, message: `Error importing image: ${message}` }
53+
}
3654
}
3755
}

src/plugins/video/VideoNode.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1+
import { GraphNodeData } from '@/features/graph';
12
import './videoNode.style.css'
23
import { GraphNode } from "@/features/graph/graphview";
4+
import { NodeRenderer } from '@/features/graph/renderer';
35
import React from "react";
4-
import { type NodeRenderer } from "../../features/graph/renderer/RendererRegistry";
5-
6-
type VideoNodeData = {
7-
src: string;
8-
type: string
9-
}
6+
import { VideoNodeData } from './types';
107

118
const OptimizedVideo = React.memo(({ src, type }: { src: string; type: string }) => (
129
<video
@@ -16,15 +13,18 @@ const OptimizedVideo = React.memo(({ src, type }: { src: string; type: string })
1613
>
1714
<source src={src} type={type} />
1815
</video>
19-
));
16+
))
17+
OptimizedVideo.displayName = 'VideoNode';
2018

21-
const VideoNode: NodeRenderer<VideoNodeData> = ({ node }) => {
22-
const { src, type } = node.data;
19+
const VideoNode: NodeRenderer<VideoNodeData> = ({ node }: { node: GraphNodeData<VideoNodeData> }) => {
20+
const { src, type } = node.data
21+
const { width, height } = node.size
22+
const aspect = width / height;
2323

2424
return (
2525
<GraphNode
2626
nodeId={node.id}
27-
aspectRatio={node.aspect}
27+
aspectRatio={aspect}
2828
className="video-node"
2929
>
3030
<OptimizedVideo src={src ?? "/fallback-image.png"} type={type} />
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { GraphNodeData } from "@/features/graph"
2+
import { IRenderer } from "@/features/graph/renderer"
3+
import { VideoNodeData } from "./types"
4+
import VideoNode from "./VideoNode"
5+
6+
export class VideoNodeRenderer implements IRenderer<VideoNodeData> {
7+
render = (node: GraphNodeData<unknown>): JSX.Element | null => {
8+
const nodeData = node as GraphNodeData<VideoNodeData>
9+
const data = nodeData.data
10+
11+
if (!nodeData) return null
12+
if (!data || !data.src) {
13+
return null
14+
}
15+
16+
return (
17+
<VideoNode node={node as GraphNodeData<VideoNodeData>} />
18+
)
19+
}
20+
}

src/plugins/video/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { PluginDefinition } from "@/features/plugins";
2+
import { VideoNodeRenderer } from "./VideoNodeRenderer";
3+
import { VideoImporter } from "./VideoImporter";
4+
import { rendererRegistry } from "@/features/graph";
5+
import { importerRegistry } from "@/features/importing";
6+
7+
let renderer: VideoNodeRenderer
8+
let importer: VideoImporter
9+
10+
export const pluginDefinition: PluginDefinition = {
11+
name: "Video Plugin",
12+
id: "core-video-plugin",
13+
description: "A plugin that adds video support to the application.",
14+
version: "1.0.0",
15+
onRegister: () => {
16+
renderer = new VideoNodeRenderer()
17+
importer = new VideoImporter()
18+
rendererRegistry.registerRenderer("video", renderer)
19+
importerRegistry.registerImporter(importer)
20+
},
21+
onUnload: () => {
22+
rendererRegistry.removeRenderer("video")
23+
importerRegistry.unregisterImporter(importer)
24+
},
25+
}

src/plugins/video/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export type VideoNodeData = {
2+
src: string;
3+
type: string
4+
}

src/ui/index.ts

Whitespace-only changes.

0 commit comments

Comments
 (0)