melies-video-editor 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -44
- package/dist/index.cjs +8 -8
- package/dist/index.js +2197 -1708
- package/dist/style.css +1 -1
- package/dist/types/App.d.ts +17 -1
- package/dist/types/dev/DevRoot.d.ts +4 -0
- package/dist/types/dev/HostApp.d.ts +6 -1
- package/dist/types/mediaCache.d.ts +48 -0
- package/dist/types/services/opfs.d.ts +37 -0
- package/dist/types/services/proxyManager.d.ts +19 -0
- package/dist/types/videoControl.d.ts +57 -30
- package/dist/types/workers/proxyWorker.d.ts +1 -0
- package/package.json +74 -74
package/dist/types/App.d.ts
CHANGED
|
@@ -5,6 +5,22 @@ export type MeliesVideoEditorProps = {
|
|
|
5
5
|
* When omitted or empty, the footage bin will be empty.
|
|
6
6
|
*/
|
|
7
7
|
footageUrls?: string[];
|
|
8
|
+
/**
|
|
9
|
+
* Local Files to show in the footage bin.
|
|
10
|
+
*
|
|
11
|
+
* This is ideal for OPFS (Base44 can load from OPFS and pass `File`s here).
|
|
12
|
+
*/
|
|
13
|
+
footageFiles?: File[];
|
|
14
|
+
/**
|
|
15
|
+
* Handle-like objects (e.g. `FileSystemFileHandle`) that can yield `File`s.
|
|
16
|
+
*
|
|
17
|
+
* We intentionally avoid depending on `FileSystemFileHandle` directly so
|
|
18
|
+
* consumers without that DOM lib type can still compile.
|
|
19
|
+
*/
|
|
20
|
+
footageFileHandles?: Array<{
|
|
21
|
+
getFile: () => Promise<File>;
|
|
22
|
+
name?: string;
|
|
23
|
+
}>;
|
|
8
24
|
/**
|
|
9
25
|
* When true, automatically place `footageUrls` onto the timeline on first initialization
|
|
10
26
|
* (one after another, starting at t=0).
|
|
@@ -13,5 +29,5 @@ export type MeliesVideoEditorProps = {
|
|
|
13
29
|
*/
|
|
14
30
|
autoPlaceFootage?: boolean;
|
|
15
31
|
};
|
|
16
|
-
declare const MeliesVideoEditor: ({ footageUrls, autoPlaceFootage }: MeliesVideoEditorProps) => import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
declare const MeliesVideoEditor: ({ footageUrls, footageFiles, footageFileHandles, autoPlaceFootage, }: MeliesVideoEditorProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
33
|
export default MeliesVideoEditor;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
export default function HostApp({ footageUrls }: {
|
|
1
|
+
export default function HostApp({ footageUrls, footageFiles, footageFileHandles, }: {
|
|
2
2
|
footageUrls?: string[];
|
|
3
|
+
footageFiles?: File[];
|
|
4
|
+
footageFileHandles?: Array<{
|
|
5
|
+
getFile: () => Promise<File>;
|
|
6
|
+
name?: string;
|
|
7
|
+
}>;
|
|
3
8
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,8 +1,56 @@
|
|
|
1
1
|
type MediaKind = 'video' | 'audio' | 'other';
|
|
2
|
+
export type ProxyEvent = {
|
|
3
|
+
type: 'proxy-start';
|
|
4
|
+
originalSrc: string;
|
|
5
|
+
} | {
|
|
6
|
+
type: 'proxy-progress';
|
|
7
|
+
originalSrc: string;
|
|
8
|
+
value?: number;
|
|
9
|
+
status?: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'proxy-ready';
|
|
12
|
+
originalSrc: string;
|
|
13
|
+
proxySrc: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'proxy-failed';
|
|
16
|
+
originalSrc: string;
|
|
17
|
+
error: string;
|
|
18
|
+
};
|
|
2
19
|
declare const guessKind: (src: string) => MediaKind;
|
|
3
20
|
declare class MediaCache {
|
|
4
21
|
private blobUrlBySrc;
|
|
5
22
|
private pendingBySrc;
|
|
23
|
+
private metaBySrc;
|
|
24
|
+
private proxyEventListeners;
|
|
25
|
+
/** Subscribe to proxy generation events (useful for UI debug on mobile where console logs aren't visible). */
|
|
26
|
+
onProxyEvent(listener: (event: ProxyEvent) => void): () => void;
|
|
27
|
+
private emitProxyEvent;
|
|
28
|
+
registerSrcMeta(src: string, meta: {
|
|
29
|
+
name?: string;
|
|
30
|
+
mimeType?: string;
|
|
31
|
+
}): void;
|
|
32
|
+
getSrcMeta(src: string): {
|
|
33
|
+
name?: string;
|
|
34
|
+
mimeType?: string;
|
|
35
|
+
} | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Ingests a File object into OPFS.
|
|
38
|
+
* Returns a virtual 'opfs://' URL that can be used as a src reference.
|
|
39
|
+
*/
|
|
40
|
+
ingest(file: File): Promise<string>;
|
|
41
|
+
private initProxy;
|
|
42
|
+
/**
|
|
43
|
+
* Returns a URL that is safe to assign to a media element (`<video>`/`<audio>`).
|
|
44
|
+
*
|
|
45
|
+
* Notes:
|
|
46
|
+
* - `opfs://...` is NOT directly playable by browsers.
|
|
47
|
+
* - For OPFS sources, this will kick off an async preload (creating a `blob:` URL) and return `undefined`.
|
|
48
|
+
*/
|
|
49
|
+
resolveForMediaElement(src: string): string | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Helper to fetch a file from OPFS given an opfs:// URL
|
|
52
|
+
*/
|
|
53
|
+
getFileFromOpfs(opfsUrl: string): Promise<File | undefined>;
|
|
6
54
|
/**
|
|
7
55
|
* Preloads a URL into memory and returns a blob: URL.
|
|
8
56
|
* Useful to avoid runtime buffering/stalls when seeking frequently.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type OpfsRoot = FileSystemDirectoryHandle;
|
|
2
|
+
export declare const ensureOpfsRoot: () => Promise<OpfsRoot>;
|
|
3
|
+
export declare const ensureDir: (root: OpfsRoot, path: string) => Promise<FileSystemDirectoryHandle>;
|
|
4
|
+
/**
|
|
5
|
+
* Writes a Blob or File to OPFS.
|
|
6
|
+
* Uses createWritable() which is the standard async way to write.
|
|
7
|
+
*/
|
|
8
|
+
export declare const writeFileToOpfs: (opts: {
|
|
9
|
+
root: OpfsRoot;
|
|
10
|
+
dirPath: string;
|
|
11
|
+
fileName: string;
|
|
12
|
+
file: Blob | File;
|
|
13
|
+
}) => Promise<{
|
|
14
|
+
fileHandle: FileSystemFileHandle;
|
|
15
|
+
path: string;
|
|
16
|
+
}>;
|
|
17
|
+
export declare const getOpfsFile: (path: string) => Promise<File | undefined>;
|
|
18
|
+
export declare const listFiles: (opts: {
|
|
19
|
+
root: OpfsRoot;
|
|
20
|
+
dirPath: string;
|
|
21
|
+
}) => Promise<FileSystemFileHandle[]>;
|
|
22
|
+
export declare const clearDir: (opts: {
|
|
23
|
+
root: OpfsRoot;
|
|
24
|
+
dirPath: string;
|
|
25
|
+
}) => Promise<void>;
|
|
26
|
+
type Maybe<T> = T | null | undefined;
|
|
27
|
+
export declare const getFileFromPublicUrl: (url: string, fallbackName?: Maybe<string>) => Promise<File>;
|
|
28
|
+
export declare const writeBlobToOpfs: (opts: {
|
|
29
|
+
root: OpfsRoot;
|
|
30
|
+
dirPath: string;
|
|
31
|
+
fileName: string;
|
|
32
|
+
blob: Blob;
|
|
33
|
+
}) => Promise<{
|
|
34
|
+
fileHandle: FileSystemFileHandle;
|
|
35
|
+
path: string;
|
|
36
|
+
}>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
declare class ProxyManager {
|
|
2
|
+
private activeJobs;
|
|
3
|
+
/**
|
|
4
|
+
* Create (or reuse) a proxy file for an OPFS video.
|
|
5
|
+
*
|
|
6
|
+
* `originalOpfsPath` should be an `opfs://...` URL.
|
|
7
|
+
*/
|
|
8
|
+
createProxy(originalOpfsPath: string, opts?: {
|
|
9
|
+
onProgress?: (info: {
|
|
10
|
+
value?: number;
|
|
11
|
+
status?: string;
|
|
12
|
+
}) => void;
|
|
13
|
+
}): Promise<string>;
|
|
14
|
+
private _runWorker;
|
|
15
|
+
private getHandle;
|
|
16
|
+
private ensureDir;
|
|
17
|
+
}
|
|
18
|
+
export declare const proxyManager: ProxyManager;
|
|
19
|
+
export {};
|
|
@@ -1,44 +1,71 @@
|
|
|
1
|
-
import type { TimelineEngine } from '@xzdarcy/react-timeline-editor';
|
|
1
|
+
import type { TimelineEngine, TimelineRow } from '@xzdarcy/react-timeline-editor';
|
|
2
2
|
declare class VideoControl {
|
|
3
|
-
private
|
|
4
|
-
private
|
|
5
|
-
private
|
|
6
|
-
private
|
|
7
|
-
private videoClaims;
|
|
8
|
-
private activeVideoActionId;
|
|
9
|
-
private lastEngineTime;
|
|
3
|
+
private primaryEl;
|
|
4
|
+
private secondaryEl;
|
|
5
|
+
private activeEl;
|
|
6
|
+
private rowData;
|
|
10
7
|
private boundEngine;
|
|
11
|
-
private boundActionStart;
|
|
12
8
|
private vfcHandle;
|
|
13
9
|
private rafHandle;
|
|
10
|
+
private isPlaying;
|
|
11
|
+
private playbackRate;
|
|
12
|
+
private lastVideoClip;
|
|
13
|
+
private lastKnownTime;
|
|
14
|
+
constructor();
|
|
15
|
+
/**
|
|
16
|
+
* Called by App.tsx to provide the two video elements.
|
|
17
|
+
*/
|
|
18
|
+
attachPrimary(el: HTMLVideoElement | null): void;
|
|
19
|
+
attachSecondary(el: HTMLVideoElement | null): void;
|
|
20
|
+
/**
|
|
21
|
+
* Helper to set initial styling/events for video elements.
|
|
22
|
+
*/
|
|
23
|
+
private initElement;
|
|
24
|
+
/**
|
|
25
|
+
* Deprecated single-element attach, mapped to primary for safety.
|
|
26
|
+
*/
|
|
14
27
|
attach(el: HTMLVideoElement | null): void;
|
|
15
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Called by App.tsx whenever timeline data changes.
|
|
30
|
+
*/
|
|
31
|
+
setEditorData(data: TimelineRow[]): void;
|
|
32
|
+
/**
|
|
33
|
+
* We use claimVideo to drive the dual-buffer logic from the engine's time updates.
|
|
34
|
+
* This ensures we sync to the engine's clock (Slave Mode).
|
|
35
|
+
*/
|
|
16
36
|
claimVideo(data: {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
engine: TimelineEngine;
|
|
21
|
-
isPlaying: boolean;
|
|
22
|
-
time: number;
|
|
23
|
-
actionStart: number;
|
|
24
|
-
offset?: number;
|
|
37
|
+
isPlaying?: boolean;
|
|
38
|
+
time?: number;
|
|
39
|
+
[key: string]: unknown;
|
|
25
40
|
}): void;
|
|
26
|
-
|
|
27
|
-
bindEngine(engine: TimelineEngine, actionStart: number): void;
|
|
41
|
+
bindEngine(engine: TimelineEngine): void;
|
|
28
42
|
unbindEngine(): void;
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
warm(src: string): void;
|
|
32
|
-
setRate(rate: number): void;
|
|
43
|
+
private startLoop;
|
|
44
|
+
private stopLoop;
|
|
33
45
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
46
|
+
* The main heart beat.
|
|
47
|
+
* - If playing: sync engine time to video time.
|
|
48
|
+
* - Always: Check schedule (what should be playing vs preloading).
|
|
36
49
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
private tickLoop;
|
|
51
|
+
/**
|
|
52
|
+
* Evaluate the timeline at `time` (and `time + lookahead`).
|
|
53
|
+
* Manage Primary/Secondary elements.
|
|
54
|
+
*/
|
|
55
|
+
private updateState;
|
|
56
|
+
private makeActive;
|
|
57
|
+
private loadVideo;
|
|
58
|
+
private isLoaded;
|
|
59
|
+
private findClipAtTime;
|
|
60
|
+
private findNextVideoClipStartAfter;
|
|
61
|
+
private findNextVideoClipAfter;
|
|
62
|
+
play(): void;
|
|
41
63
|
pause(): void;
|
|
64
|
+
setRate(rate: number): void;
|
|
65
|
+
seek(time: number): void;
|
|
66
|
+
warm(src: string): void;
|
|
67
|
+
releaseVideo(_actionId: string): void;
|
|
68
|
+
setActive(_active: boolean): void;
|
|
42
69
|
}
|
|
43
70
|
declare const _default: VideoControl;
|
|
44
71
|
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "melies-video-editor",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "A React video timeline editor GUI built on @xzdarcy/react-timeline-editor.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"timeline",
|
|
9
|
-
"video",
|
|
10
|
-
"editor",
|
|
11
|
-
"react",
|
|
12
|
-
"base44"
|
|
13
|
-
],
|
|
14
|
-
"main": "./dist/index.cjs",
|
|
15
|
-
"module": "./dist/index.js",
|
|
16
|
-
"types": "./dist/types/lib/index.d.ts",
|
|
17
|
-
"exports": {
|
|
18
|
-
".": {
|
|
19
|
-
"types": "./dist/types/lib/index.d.ts",
|
|
20
|
-
"import": "./dist/index.js",
|
|
21
|
-
"require": "./dist/index.cjs"
|
|
22
|
-
},
|
|
23
|
-
"./style.css": "./dist/style.css"
|
|
24
|
-
},
|
|
25
|
-
"files": [
|
|
26
|
-
"dist",
|
|
27
|
-
"README.md",
|
|
28
|
-
"LICENSE"
|
|
29
|
-
],
|
|
30
|
-
"sideEffects": [
|
|
31
|
-
"**/*.css"
|
|
32
|
-
],
|
|
33
|
-
"scripts": {
|
|
34
|
-
"dev": "vite --host",
|
|
35
|
-
"dev:server": "node server/index.mjs",
|
|
36
|
-
"build": "tsc -b && vite build && tsc -p tsconfig.types.json",
|
|
37
|
-
"lint": "eslint .",
|
|
38
|
-
"preview": "vite preview"
|
|
39
|
-
},
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"@ant-design/icons": "4.7.0",
|
|
42
|
-
"@dnd-kit/core": "^6.3.1",
|
|
43
|
-
"@xzdarcy/react-timeline-editor": "0.1.8",
|
|
44
|
-
"antd": "4.21.6",
|
|
45
|
-
"howler": "2.2.3",
|
|
46
|
-
"lodash": "4.17.21",
|
|
47
|
-
"lottie-web": "5.10.0"
|
|
48
|
-
},
|
|
49
|
-
"peerDependencies": {
|
|
50
|
-
"react": "^18.0.0",
|
|
51
|
-
"react-dom": "^18.0.0"
|
|
52
|
-
},
|
|
53
|
-
"devDependencies": {
|
|
54
|
-
"@eslint/js": "^9.39.1",
|
|
55
|
-
"@types/node": "^24.10.1",
|
|
56
|
-
"@types/howler": "^2.2.12",
|
|
57
|
-
"@types/react": "^18.3.18",
|
|
58
|
-
"@types/react-dom": "^18.3.5",
|
|
59
|
-
"@vitejs/plugin-react": "^5.1.1",
|
|
60
|
-
"eslint": "^9.39.1",
|
|
61
|
-
"eslint-plugin-react-hooks": "^7.0.1",
|
|
62
|
-
"eslint-plugin-react-refresh": "^0.4.24",
|
|
63
|
-
"express": "^4.21.2",
|
|
64
|
-
"globals": "^16.5.0",
|
|
65
|
-
"less": "^4.5.1",
|
|
66
|
-
"multer": "^2.0.2",
|
|
67
|
-
"react": "^18.2.0",
|
|
68
|
-
"react-dom": "^18.2.0",
|
|
69
|
-
"typescript": "~5.9.3",
|
|
70
|
-
"typescript-eslint": "^8.46.4",
|
|
71
|
-
"vite": "^7.2.4"
|
|
72
|
-
},
|
|
73
|
-
"packageManager": "pnpm@8.7.1+sha1.cb9fb56ca170a718619cd9bc669d99ddadc1afb5"
|
|
74
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "melies-video-editor",
|
|
3
|
+
"version": "0.1.4",
|
|
4
|
+
"description": "A React video timeline editor GUI built on @xzdarcy/react-timeline-editor.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"timeline",
|
|
9
|
+
"video",
|
|
10
|
+
"editor",
|
|
11
|
+
"react",
|
|
12
|
+
"base44"
|
|
13
|
+
],
|
|
14
|
+
"main": "./dist/index.cjs",
|
|
15
|
+
"module": "./dist/index.js",
|
|
16
|
+
"types": "./dist/types/lib/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/types/lib/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"require": "./dist/index.cjs"
|
|
22
|
+
},
|
|
23
|
+
"./style.css": "./dist/style.css"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"sideEffects": [
|
|
31
|
+
"**/*.css"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"dev": "vite --host",
|
|
35
|
+
"dev:server": "node server/index.mjs",
|
|
36
|
+
"build": "tsc -b && vite build && tsc -p tsconfig.types.json",
|
|
37
|
+
"lint": "eslint .",
|
|
38
|
+
"preview": "vite preview"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@ant-design/icons": "4.7.0",
|
|
42
|
+
"@dnd-kit/core": "^6.3.1",
|
|
43
|
+
"@xzdarcy/react-timeline-editor": "0.1.8",
|
|
44
|
+
"antd": "4.21.6",
|
|
45
|
+
"howler": "2.2.3",
|
|
46
|
+
"lodash": "4.17.21",
|
|
47
|
+
"lottie-web": "5.10.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"react": "^18.0.0",
|
|
51
|
+
"react-dom": "^18.0.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@eslint/js": "^9.39.1",
|
|
55
|
+
"@types/node": "^24.10.1",
|
|
56
|
+
"@types/howler": "^2.2.12",
|
|
57
|
+
"@types/react": "^18.3.18",
|
|
58
|
+
"@types/react-dom": "^18.3.5",
|
|
59
|
+
"@vitejs/plugin-react": "^5.1.1",
|
|
60
|
+
"eslint": "^9.39.1",
|
|
61
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
62
|
+
"eslint-plugin-react-refresh": "^0.4.24",
|
|
63
|
+
"express": "^4.21.2",
|
|
64
|
+
"globals": "^16.5.0",
|
|
65
|
+
"less": "^4.5.1",
|
|
66
|
+
"multer": "^2.0.2",
|
|
67
|
+
"react": "^18.2.0",
|
|
68
|
+
"react-dom": "^18.2.0",
|
|
69
|
+
"typescript": "~5.9.3",
|
|
70
|
+
"typescript-eslint": "^8.46.4",
|
|
71
|
+
"vite": "^7.2.4"
|
|
72
|
+
},
|
|
73
|
+
"packageManager": "pnpm@8.7.1+sha1.cb9fb56ca170a718619cd9bc669d99ddadc1afb5"
|
|
74
|
+
}
|