framewebworker 0.1.4 → 0.2.0

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.
@@ -41,7 +41,8 @@ interface CaptionOptions {
41
41
  segments: CaptionSegment[];
42
42
  style?: Partial<CaptionStyle>;
43
43
  }
44
- interface ClipInput {
44
+ /** Input descriptor for one clip source used by mergeClips() */
45
+ interface ClipSource {
45
46
  /** Video source: URL string, File, Blob, or HTMLVideoElement */
46
47
  source: string | File | Blob | HTMLVideoElement;
47
48
  /** Trim start in seconds (default: 0) */
@@ -90,16 +91,12 @@ interface RenderMetrics {
90
91
  clips: ClipMetrics[];
91
92
  framesPerSecond: number;
92
93
  }
94
+ /** One time-range segment from a single source video, used by exportClips() */
93
95
  interface Segment {
94
96
  start: number;
95
97
  end: number;
96
98
  captions?: CaptionSegment[];
97
99
  }
98
- /** Options for the render()/renderToUrl() single-video API */
99
- interface SingleVideoRenderOptions extends Omit<StitchOptions, 'onProgress' | 'onComplete'> {
100
- onProgress?: (progress: RichProgress) => void;
101
- onComplete?: (metrics: RenderMetrics) => void;
102
- }
103
100
  type ClipStatus = 'pending' | 'rendering' | 'encoding' | 'done' | 'error';
104
101
  interface ClipProgress {
105
102
  index: number;
@@ -110,54 +107,55 @@ interface RichProgress {
110
107
  overall: number;
111
108
  clips: ClipProgress[];
112
109
  }
113
- /** Extends RenderOptions with rich per-clip progress reporting and completion metrics */
114
- interface StitchOptions extends Omit<RenderOptions, 'onProgress'> {
110
+ /** Options for mergeClips() / FrameWorker.mergeClips() */
111
+ interface MergeOptions extends Omit<RenderOptions, 'onProgress'> {
112
+ onProgress?: (progress: RichProgress) => void;
113
+ onComplete?: (metrics: RenderMetrics) => void;
114
+ }
115
+ /** Options for exportClips() / exportClipsToUrl() */
116
+ interface ExportOptions extends Omit<MergeOptions, 'onProgress' | 'onComplete'> {
115
117
  onProgress?: (progress: RichProgress) => void;
116
118
  onComplete?: (metrics: RenderMetrics) => void;
117
119
  }
118
120
  interface FrameWorker {
119
- /** Render a single clip to a Blob */
120
- render(clip: ClipInput, options?: RenderOptions): Promise<Blob>;
121
- /** Render a single clip and return an object URL */
122
- renderToUrl(clip: ClipInput, options?: RenderOptions): Promise<string>;
123
- /** Stitch multiple clips into one Blob */
124
- stitch(clips: ClipInput[], options?: StitchOptions): Promise<{
121
+ /** Render a single clip to a Blob (legacy single-clip API) */
122
+ render(clip: ClipSource, options?: RenderOptions): Promise<Blob>;
123
+ /** Render a single clip and return an object URL (legacy single-clip API) */
124
+ renderToUrl(clip: ClipSource, options?: RenderOptions): Promise<string>;
125
+ /** Merge multiple clip sources into one Blob */
126
+ mergeClips(clips: ClipSource[], options?: MergeOptions): Promise<{
125
127
  blob: Blob;
126
128
  metrics: RenderMetrics;
127
129
  }>;
128
- /** Stitch multiple clips and return an object URL */
129
- stitchToUrl(clips: ClipInput[], options?: StitchOptions): Promise<{
130
+ /** Merge multiple clip sources and return an object URL */
131
+ mergeClipsToUrl(clips: ClipSource[], options?: MergeOptions): Promise<{
132
+ url: string;
133
+ metrics: RenderMetrics;
134
+ }>;
135
+ /** @deprecated Use mergeClips() */
136
+ stitch(clips: ClipSource[], options?: MergeOptions): Promise<{
137
+ blob: Blob;
138
+ metrics: RenderMetrics;
139
+ }>;
140
+ /** @deprecated Use mergeClipsToUrl() */
141
+ stitchToUrl(clips: ClipSource[], options?: MergeOptions): Promise<{
130
142
  url: string;
131
143
  metrics: RenderMetrics;
132
144
  }>;
133
145
  }
134
146
 
135
- interface UseClipRenderState {
136
- progress: number;
137
- isRendering: boolean;
138
- error: Error | null;
139
- blob: Blob | null;
140
- url: string | null;
141
- }
142
- interface UseClipRenderActions {
143
- render: (clip: ClipInput, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;
144
- cancel: () => void;
145
- reset: () => void;
146
- }
147
- type UseClipRenderResult = UseClipRenderState & UseClipRenderActions;
148
- declare function useClipRender(frameWorker: FrameWorker): UseClipRenderResult;
149
- interface UseRenderResult {
147
+ interface UseExportClipsResult {
150
148
  start: () => void;
151
149
  cancel: () => void;
150
+ isRendering: boolean;
152
151
  progress: RichProgress | null;
153
152
  metrics: RenderMetrics | null;
154
153
  url: string | null;
155
154
  error: Error | null;
156
- isRendering: boolean;
157
155
  }
158
- declare function useRender(videoUrl: string | null, segments: Segment[], options?: Omit<SingleVideoRenderOptions, 'onProgress' | 'onComplete' | 'signal'>): UseRenderResult;
156
+ declare function useExportClips(videoUrl: string | null, segments: Segment[], options?: Omit<ExportOptions, 'onProgress' | 'onComplete' | 'signal'>): UseExportClipsResult;
159
157
 
160
- interface UseStitchState {
158
+ interface UseMergeClipsState {
161
159
  progress: RichProgress;
162
160
  isRendering: boolean;
163
161
  error: Error | null;
@@ -165,12 +163,33 @@ interface UseStitchState {
165
163
  url: string | null;
166
164
  metrics: RenderMetrics | null;
167
165
  }
168
- interface UseStitchActions {
169
- stitch: (clips: ClipInput[], options?: Omit<StitchOptions, 'onProgress' | 'onComplete' | 'signal'>) => Promise<Blob | null>;
166
+ interface UseMergeClipsActions {
167
+ mergeClips: (clips: ClipSource[], options?: Omit<MergeOptions, 'onProgress' | 'onComplete' | 'signal'>) => Promise<Blob | null>;
168
+ cancel: () => void;
169
+ reset: () => void;
170
+ }
171
+ type UseMergeClipsResult = UseMergeClipsState & UseMergeClipsActions;
172
+ declare function useMergeClips(frameWorker: FrameWorker): UseMergeClipsResult;
173
+
174
+ interface UsePreviewClipState {
175
+ progress: number;
176
+ isRendering: boolean;
177
+ error: Error | null;
178
+ blob: Blob | null;
179
+ url: string | null;
180
+ }
181
+ interface UsePreviewClipActions {
182
+ render: (clip: ClipSource, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;
170
183
  cancel: () => void;
171
184
  reset: () => void;
172
185
  }
173
- type UseStitchResult = UseStitchState & UseStitchActions;
174
- declare function useStitch(frameWorker: FrameWorker): UseStitchResult;
186
+ type UsePreviewClipResult = UsePreviewClipState & UsePreviewClipActions;
187
+ declare function usePreviewClip(frameWorker: FrameWorker): UsePreviewClipResult;
188
+ /** @deprecated Use UsePreviewClipResult */
189
+ type UseClipRenderResult = UsePreviewClipResult;
190
+ /** @deprecated Use UsePreviewClipState */
191
+ type UseClipRenderState = UsePreviewClipState;
192
+ /** @deprecated Use UsePreviewClipActions */
193
+ type UseClipRenderActions = UsePreviewClipActions;
175
194
 
176
- export { type UseClipRenderActions, type UseClipRenderResult, type UseClipRenderState, type UseRenderResult, type UseStitchActions, type UseStitchResult, type UseStitchState, useClipRender, useRender, useStitch };
195
+ export { type UseClipRenderActions, type UseClipRenderResult, type UseClipRenderState, type UseExportClipsResult, type UseMergeClipsActions, type UseMergeClipsResult, type UseMergeClipsState, type UsePreviewClipActions, type UsePreviewClipResult, type UsePreviewClipState, type UseMergeClipsActions as UseStitchActions, type UseMergeClipsResult as UseStitchResult, type UseMergeClipsState as UseStitchState, usePreviewClip as useClipRender, useExportClips, useMergeClips, usePreviewClip, useExportClips as useRender, useMergeClips as useStitch };
@@ -41,7 +41,8 @@ interface CaptionOptions {
41
41
  segments: CaptionSegment[];
42
42
  style?: Partial<CaptionStyle>;
43
43
  }
44
- interface ClipInput {
44
+ /** Input descriptor for one clip source used by mergeClips() */
45
+ interface ClipSource {
45
46
  /** Video source: URL string, File, Blob, or HTMLVideoElement */
46
47
  source: string | File | Blob | HTMLVideoElement;
47
48
  /** Trim start in seconds (default: 0) */
@@ -90,16 +91,12 @@ interface RenderMetrics {
90
91
  clips: ClipMetrics[];
91
92
  framesPerSecond: number;
92
93
  }
94
+ /** One time-range segment from a single source video, used by exportClips() */
93
95
  interface Segment {
94
96
  start: number;
95
97
  end: number;
96
98
  captions?: CaptionSegment[];
97
99
  }
98
- /** Options for the render()/renderToUrl() single-video API */
99
- interface SingleVideoRenderOptions extends Omit<StitchOptions, 'onProgress' | 'onComplete'> {
100
- onProgress?: (progress: RichProgress) => void;
101
- onComplete?: (metrics: RenderMetrics) => void;
102
- }
103
100
  type ClipStatus = 'pending' | 'rendering' | 'encoding' | 'done' | 'error';
104
101
  interface ClipProgress {
105
102
  index: number;
@@ -110,54 +107,55 @@ interface RichProgress {
110
107
  overall: number;
111
108
  clips: ClipProgress[];
112
109
  }
113
- /** Extends RenderOptions with rich per-clip progress reporting and completion metrics */
114
- interface StitchOptions extends Omit<RenderOptions, 'onProgress'> {
110
+ /** Options for mergeClips() / FrameWorker.mergeClips() */
111
+ interface MergeOptions extends Omit<RenderOptions, 'onProgress'> {
112
+ onProgress?: (progress: RichProgress) => void;
113
+ onComplete?: (metrics: RenderMetrics) => void;
114
+ }
115
+ /** Options for exportClips() / exportClipsToUrl() */
116
+ interface ExportOptions extends Omit<MergeOptions, 'onProgress' | 'onComplete'> {
115
117
  onProgress?: (progress: RichProgress) => void;
116
118
  onComplete?: (metrics: RenderMetrics) => void;
117
119
  }
118
120
  interface FrameWorker {
119
- /** Render a single clip to a Blob */
120
- render(clip: ClipInput, options?: RenderOptions): Promise<Blob>;
121
- /** Render a single clip and return an object URL */
122
- renderToUrl(clip: ClipInput, options?: RenderOptions): Promise<string>;
123
- /** Stitch multiple clips into one Blob */
124
- stitch(clips: ClipInput[], options?: StitchOptions): Promise<{
121
+ /** Render a single clip to a Blob (legacy single-clip API) */
122
+ render(clip: ClipSource, options?: RenderOptions): Promise<Blob>;
123
+ /** Render a single clip and return an object URL (legacy single-clip API) */
124
+ renderToUrl(clip: ClipSource, options?: RenderOptions): Promise<string>;
125
+ /** Merge multiple clip sources into one Blob */
126
+ mergeClips(clips: ClipSource[], options?: MergeOptions): Promise<{
125
127
  blob: Blob;
126
128
  metrics: RenderMetrics;
127
129
  }>;
128
- /** Stitch multiple clips and return an object URL */
129
- stitchToUrl(clips: ClipInput[], options?: StitchOptions): Promise<{
130
+ /** Merge multiple clip sources and return an object URL */
131
+ mergeClipsToUrl(clips: ClipSource[], options?: MergeOptions): Promise<{
132
+ url: string;
133
+ metrics: RenderMetrics;
134
+ }>;
135
+ /** @deprecated Use mergeClips() */
136
+ stitch(clips: ClipSource[], options?: MergeOptions): Promise<{
137
+ blob: Blob;
138
+ metrics: RenderMetrics;
139
+ }>;
140
+ /** @deprecated Use mergeClipsToUrl() */
141
+ stitchToUrl(clips: ClipSource[], options?: MergeOptions): Promise<{
130
142
  url: string;
131
143
  metrics: RenderMetrics;
132
144
  }>;
133
145
  }
134
146
 
135
- interface UseClipRenderState {
136
- progress: number;
137
- isRendering: boolean;
138
- error: Error | null;
139
- blob: Blob | null;
140
- url: string | null;
141
- }
142
- interface UseClipRenderActions {
143
- render: (clip: ClipInput, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;
144
- cancel: () => void;
145
- reset: () => void;
146
- }
147
- type UseClipRenderResult = UseClipRenderState & UseClipRenderActions;
148
- declare function useClipRender(frameWorker: FrameWorker): UseClipRenderResult;
149
- interface UseRenderResult {
147
+ interface UseExportClipsResult {
150
148
  start: () => void;
151
149
  cancel: () => void;
150
+ isRendering: boolean;
152
151
  progress: RichProgress | null;
153
152
  metrics: RenderMetrics | null;
154
153
  url: string | null;
155
154
  error: Error | null;
156
- isRendering: boolean;
157
155
  }
158
- declare function useRender(videoUrl: string | null, segments: Segment[], options?: Omit<SingleVideoRenderOptions, 'onProgress' | 'onComplete' | 'signal'>): UseRenderResult;
156
+ declare function useExportClips(videoUrl: string | null, segments: Segment[], options?: Omit<ExportOptions, 'onProgress' | 'onComplete' | 'signal'>): UseExportClipsResult;
159
157
 
160
- interface UseStitchState {
158
+ interface UseMergeClipsState {
161
159
  progress: RichProgress;
162
160
  isRendering: boolean;
163
161
  error: Error | null;
@@ -165,12 +163,33 @@ interface UseStitchState {
165
163
  url: string | null;
166
164
  metrics: RenderMetrics | null;
167
165
  }
168
- interface UseStitchActions {
169
- stitch: (clips: ClipInput[], options?: Omit<StitchOptions, 'onProgress' | 'onComplete' | 'signal'>) => Promise<Blob | null>;
166
+ interface UseMergeClipsActions {
167
+ mergeClips: (clips: ClipSource[], options?: Omit<MergeOptions, 'onProgress' | 'onComplete' | 'signal'>) => Promise<Blob | null>;
168
+ cancel: () => void;
169
+ reset: () => void;
170
+ }
171
+ type UseMergeClipsResult = UseMergeClipsState & UseMergeClipsActions;
172
+ declare function useMergeClips(frameWorker: FrameWorker): UseMergeClipsResult;
173
+
174
+ interface UsePreviewClipState {
175
+ progress: number;
176
+ isRendering: boolean;
177
+ error: Error | null;
178
+ blob: Blob | null;
179
+ url: string | null;
180
+ }
181
+ interface UsePreviewClipActions {
182
+ render: (clip: ClipSource, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;
170
183
  cancel: () => void;
171
184
  reset: () => void;
172
185
  }
173
- type UseStitchResult = UseStitchState & UseStitchActions;
174
- declare function useStitch(frameWorker: FrameWorker): UseStitchResult;
186
+ type UsePreviewClipResult = UsePreviewClipState & UsePreviewClipActions;
187
+ declare function usePreviewClip(frameWorker: FrameWorker): UsePreviewClipResult;
188
+ /** @deprecated Use UsePreviewClipResult */
189
+ type UseClipRenderResult = UsePreviewClipResult;
190
+ /** @deprecated Use UsePreviewClipState */
191
+ type UseClipRenderState = UsePreviewClipState;
192
+ /** @deprecated Use UsePreviewClipActions */
193
+ type UseClipRenderActions = UsePreviewClipActions;
175
194
 
176
- export { type UseClipRenderActions, type UseClipRenderResult, type UseClipRenderState, type UseRenderResult, type UseStitchActions, type UseStitchResult, type UseStitchState, useClipRender, useRender, useStitch };
195
+ export { type UseClipRenderActions, type UseClipRenderResult, type UseClipRenderState, type UseExportClipsResult, type UseMergeClipsActions, type UseMergeClipsResult, type UseMergeClipsState, type UsePreviewClipActions, type UsePreviewClipResult, type UsePreviewClipState, type UseMergeClipsActions as UseStitchActions, type UseMergeClipsResult as UseStitchResult, type UseMergeClipsState as UseStitchState, usePreviewClip as useClipRender, useExportClips, useMergeClips, usePreviewClip, useExportClips as useRender, useMergeClips as useStitch };
@@ -1,63 +1,8 @@
1
1
  import { useState, useRef, useCallback } from 'react';
2
- import { render } from '../render.js';
2
+ import { exportClips } from '../render.js';
3
3
 
4
- // src/react/useRender.ts
5
- function useClipRender(frameWorker) {
6
- const [state, setState] = useState({
7
- progress: 0,
8
- isRendering: false,
9
- error: null,
10
- blob: null,
11
- url: null
12
- });
13
- const abortRef = useRef(null);
14
- const urlRef = useRef(null);
15
- const cancel = useCallback(() => {
16
- abortRef.current?.abort();
17
- }, []);
18
- const reset = useCallback(() => {
19
- if (urlRef.current) {
20
- URL.revokeObjectURL(urlRef.current);
21
- urlRef.current = null;
22
- }
23
- setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });
24
- }, []);
25
- const render = useCallback(
26
- async (clip, options) => {
27
- if (urlRef.current) {
28
- URL.revokeObjectURL(urlRef.current);
29
- urlRef.current = null;
30
- }
31
- const controller = new AbortController();
32
- abortRef.current = controller;
33
- setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });
34
- try {
35
- const blob = await frameWorker.render(clip, {
36
- ...options,
37
- signal: controller.signal,
38
- onProgress: (p) => {
39
- setState((prev) => ({ ...prev, progress: p }));
40
- }
41
- });
42
- const url = URL.createObjectURL(blob);
43
- urlRef.current = url;
44
- setState({ progress: 1, isRendering: false, error: null, blob, url });
45
- return blob;
46
- } catch (err) {
47
- if (err instanceof DOMException && err.name === "AbortError") {
48
- setState((prev) => ({ ...prev, isRendering: false, error: null }));
49
- return null;
50
- }
51
- const error = err instanceof Error ? err : new Error(String(err));
52
- setState((prev) => ({ ...prev, isRendering: false, error }));
53
- return null;
54
- }
55
- },
56
- [frameWorker]
57
- );
58
- return { ...state, render, cancel, reset };
59
- }
60
- function useRender(videoUrl, segments, options) {
4
+ // src/react/useExportClips.ts
5
+ function useExportClips(videoUrl, segments, options) {
61
6
  const [isRendering, setIsRendering] = useState(false);
62
7
  const [progress, setProgress] = useState(null);
63
8
  const [metrics, setMetrics] = useState(null);
@@ -81,7 +26,7 @@ function useRender(videoUrl, segments, options) {
81
26
  setMetrics(null);
82
27
  setUrl(null);
83
28
  setError(null);
84
- render(videoUrl, segments, {
29
+ exportClips(videoUrl, segments, {
85
30
  ...options,
86
31
  signal: controller.signal,
87
32
  onProgress: (p) => setProgress(p),
@@ -100,10 +45,10 @@ function useRender(videoUrl, segments, options) {
100
45
  setIsRendering(false);
101
46
  });
102
47
  }, [videoUrl, segments, options, isRendering]);
103
- return { start, cancel, progress, metrics, url, error, isRendering };
48
+ return { start, cancel, isRendering, progress, metrics, url, error };
104
49
  }
105
50
  var INITIAL_PROGRESS = { overall: 0, clips: [] };
106
- function useStitch(frameWorker) {
51
+ function useMergeClips(frameWorker) {
107
52
  const [state, setState] = useState({
108
53
  progress: INITIAL_PROGRESS,
109
54
  isRendering: false,
@@ -124,7 +69,7 @@ function useStitch(frameWorker) {
124
69
  }
125
70
  setState({ progress: INITIAL_PROGRESS, isRendering: false, error: null, blob: null, url: null, metrics: null });
126
71
  }, []);
127
- const stitch = useCallback(
72
+ const mergeClips = useCallback(
128
73
  async (clips, options) => {
129
74
  if (urlRef.current) {
130
75
  URL.revokeObjectURL(urlRef.current);
@@ -134,15 +79,11 @@ function useStitch(frameWorker) {
134
79
  abortRef.current = controller;
135
80
  setState({ progress: INITIAL_PROGRESS, isRendering: true, error: null, blob: null, url: null, metrics: null });
136
81
  try {
137
- const { blob, metrics } = await frameWorker.stitch(clips, {
82
+ const { blob, metrics } = await frameWorker.mergeClips(clips, {
138
83
  ...options,
139
84
  signal: controller.signal,
140
- onProgress: (p) => {
141
- setState((prev) => ({ ...prev, progress: p }));
142
- },
143
- onComplete: (m) => {
144
- setState((prev) => ({ ...prev, metrics: m }));
145
- }
85
+ onProgress: (p) => setState((prev) => ({ ...prev, progress: p })),
86
+ onComplete: (m) => setState((prev) => ({ ...prev, metrics: m }))
146
87
  });
147
88
  const url = URL.createObjectURL(blob);
148
89
  urlRef.current = url;
@@ -164,9 +105,62 @@ function useStitch(frameWorker) {
164
105
  },
165
106
  [frameWorker]
166
107
  );
167
- return { ...state, stitch, cancel, reset };
108
+ return { ...state, mergeClips, cancel, reset };
109
+ }
110
+ function usePreviewClip(frameWorker) {
111
+ const [state, setState] = useState({
112
+ progress: 0,
113
+ isRendering: false,
114
+ error: null,
115
+ blob: null,
116
+ url: null
117
+ });
118
+ const abortRef = useRef(null);
119
+ const urlRef = useRef(null);
120
+ const cancel = useCallback(() => {
121
+ abortRef.current?.abort();
122
+ }, []);
123
+ const reset = useCallback(() => {
124
+ if (urlRef.current) {
125
+ URL.revokeObjectURL(urlRef.current);
126
+ urlRef.current = null;
127
+ }
128
+ setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });
129
+ }, []);
130
+ const render = useCallback(
131
+ async (clip, options) => {
132
+ if (urlRef.current) {
133
+ URL.revokeObjectURL(urlRef.current);
134
+ urlRef.current = null;
135
+ }
136
+ const controller = new AbortController();
137
+ abortRef.current = controller;
138
+ setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });
139
+ try {
140
+ const blob = await frameWorker.render(clip, {
141
+ ...options,
142
+ signal: controller.signal,
143
+ onProgress: (p) => setState((prev) => ({ ...prev, progress: p }))
144
+ });
145
+ const url = URL.createObjectURL(blob);
146
+ urlRef.current = url;
147
+ setState({ progress: 1, isRendering: false, error: null, blob, url });
148
+ return blob;
149
+ } catch (err) {
150
+ if (err instanceof DOMException && err.name === "AbortError") {
151
+ setState((prev) => ({ ...prev, isRendering: false, error: null }));
152
+ return null;
153
+ }
154
+ const error = err instanceof Error ? err : new Error(String(err));
155
+ setState((prev) => ({ ...prev, isRendering: false, error }));
156
+ return null;
157
+ }
158
+ },
159
+ [frameWorker]
160
+ );
161
+ return { ...state, render, cancel, reset };
168
162
  }
169
163
 
170
- export { useClipRender, useRender, useStitch };
164
+ export { usePreviewClip as useClipRender, useExportClips, useMergeClips, usePreviewClip, useExportClips as useRender, useMergeClips as useStitch };
171
165
  //# sourceMappingURL=index.js.map
172
166
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/useRender.ts","../../src/react/useStitch.ts"],"names":["renderSegments","useState","useRef","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["'use client';\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { ClipInput, RenderOptions, FrameWorker } from '../types.js';\nimport type { Segment, SingleVideoRenderOptions, RichProgress, RenderMetrics } from '../types.js';\nimport { render as renderSegments } from '../render.js';\n\n// ── useClipRender — wraps FrameWorker.render(clip) ───────────────────────────\n\nexport interface UseClipRenderState {\n progress: number;\n isRendering: boolean;\n error: Error | null;\n blob: Blob | null;\n url: string | null;\n}\n\nexport interface UseClipRenderActions {\n render: (clip: ClipInput, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;\n cancel: () => void;\n reset: () => void;\n}\n\nexport type UseClipRenderResult = UseClipRenderState & UseClipRenderActions;\n\nexport function useClipRender(frameWorker: FrameWorker): UseClipRenderResult {\n const [state, setState] = useState<UseClipRenderState>({\n progress: 0,\n isRendering: false,\n error: null,\n blob: null,\n url: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });\n }, []);\n\n const render = useCallback(\n async (\n clip: ClipInput,\n options?: Omit<RenderOptions, 'onProgress' | 'signal'>\n ): Promise<Blob | null> => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });\n\n try {\n const blob = await frameWorker.render(clip, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => {\n setState((prev) => ({ ...prev, progress: p }));\n },\n });\n\n const url = URL.createObjectURL(blob);\n urlRef.current = url;\n setState({ progress: 1, isRendering: false, error: null, blob, url });\n return blob;\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setState((prev) => ({ ...prev, isRendering: false, error: null }));\n return null;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({ ...prev, isRendering: false, error }));\n return null;\n }\n },\n [frameWorker]\n );\n\n return { ...state, render, cancel, reset };\n}\n\n// ── useRender — single-video multi-segment API ────────────────────────────────\n\nexport interface UseRenderResult {\n start: () => void;\n cancel: () => void;\n progress: RichProgress | null;\n metrics: RenderMetrics | null;\n url: string | null;\n error: Error | null;\n isRendering: boolean;\n}\n\nexport function useRender(\n videoUrl: string | null,\n segments: Segment[],\n options?: Omit<SingleVideoRenderOptions, 'onProgress' | 'onComplete' | 'signal'>\n): UseRenderResult {\n const [isRendering, setIsRendering] = useState(false);\n const [progress, setProgress] = useState<RichProgress | null>(null);\n const [metrics, setMetrics] = useState<RenderMetrics | null>(null);\n const [url, setUrl] = useState<string | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const start = useCallback(() => {\n if (!videoUrl || isRendering) return;\n\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setIsRendering(true);\n setProgress(null);\n setMetrics(null);\n setUrl(null);\n setError(null);\n\n renderSegments(videoUrl, segments, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => setProgress(p),\n onComplete: (m) => setMetrics(m),\n }).then(({ blob }) => {\n const objectUrl = URL.createObjectURL(blob);\n urlRef.current = objectUrl;\n setUrl(objectUrl);\n setIsRendering(false);\n }).catch((err) => {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setIsRendering(false);\n return;\n }\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsRendering(false);\n });\n }, [videoUrl, segments, options, isRendering]);\n\n return { start, cancel, progress, metrics, url, error, isRendering };\n}\n","'use client';\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { ClipInput, StitchOptions, RichProgress, RenderMetrics, FrameWorker } from '../types.js';\n\nexport interface UseStitchState {\n progress: RichProgress;\n isRendering: boolean;\n error: Error | null;\n blob: Blob | null;\n url: string | null;\n metrics: RenderMetrics | null;\n}\n\nexport interface UseStitchActions {\n stitch: (clips: ClipInput[], options?: Omit<StitchOptions, 'onProgress' | 'onComplete' | 'signal'>) => Promise<Blob | null>;\n cancel: () => void;\n reset: () => void;\n}\n\nexport type UseStitchResult = UseStitchState & UseStitchActions;\n\nconst INITIAL_PROGRESS: RichProgress = { overall: 0, clips: [] };\n\nexport function useStitch(frameWorker: FrameWorker): UseStitchResult {\n const [state, setState] = useState<UseStitchState>({\n progress: INITIAL_PROGRESS,\n isRendering: false,\n error: null,\n blob: null,\n url: null,\n metrics: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n setState({ progress: INITIAL_PROGRESS, isRendering: false, error: null, blob: null, url: null, metrics: null });\n }, []);\n\n const stitch = useCallback(\n async (\n clips: ClipInput[],\n options?: Omit<StitchOptions, 'onProgress' | 'onComplete' | 'signal'>\n ): Promise<Blob | null> => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ progress: INITIAL_PROGRESS, isRendering: true, error: null, blob: null, url: null, metrics: null });\n\n try {\n const { blob, metrics } = await frameWorker.stitch(clips, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => {\n setState((prev) => ({ ...prev, progress: p }));\n },\n onComplete: (m) => {\n setState((prev) => ({ ...prev, metrics: m }));\n },\n });\n\n const url = URL.createObjectURL(blob);\n urlRef.current = url;\n const doneProgress: RichProgress = {\n overall: 1,\n clips: clips.map((_, i) => ({ index: i, status: 'done', progress: 1 })),\n };\n setState((prev) => ({ ...prev, progress: doneProgress, isRendering: false, blob, url }));\n return blob;\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setState((prev) => ({ ...prev, isRendering: false, error: null }));\n return null;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({ ...prev, isRendering: false, error }));\n return null;\n }\n },\n [frameWorker]\n );\n\n return { ...state, stitch, cancel, reset };\n}\n"]}
1
+ {"version":3,"sources":["../../src/react/useExportClips.ts","../../src/react/useMergeClips.ts","../../src/react/useRender.ts"],"names":["useState","useRef","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["'use client';\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { Segment, ExportOptions, RichProgress, RenderMetrics } from '../types.js';\nimport { exportClips } from '../render.js';\n\nexport interface UseExportClipsResult {\n start: () => void;\n cancel: () => void;\n isRendering: boolean;\n progress: RichProgress | null;\n metrics: RenderMetrics | null;\n url: string | null;\n error: Error | null;\n}\n\nexport function useExportClips(\n videoUrl: string | null,\n segments: Segment[],\n options?: Omit<ExportOptions, 'onProgress' | 'onComplete' | 'signal'>\n): UseExportClipsResult {\n const [isRendering, setIsRendering] = useState(false);\n const [progress, setProgress] = useState<RichProgress | null>(null);\n const [metrics, setMetrics] = useState<RenderMetrics | null>(null);\n const [url, setUrl] = useState<string | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const start = useCallback(() => {\n if (!videoUrl || isRendering) return;\n\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setIsRendering(true);\n setProgress(null);\n setMetrics(null);\n setUrl(null);\n setError(null);\n\n exportClips(videoUrl, segments, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => setProgress(p),\n onComplete: (m) => setMetrics(m),\n }).then(({ blob }) => {\n const objectUrl = URL.createObjectURL(blob);\n urlRef.current = objectUrl;\n setUrl(objectUrl);\n setIsRendering(false);\n }).catch((err) => {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setIsRendering(false);\n return;\n }\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsRendering(false);\n });\n }, [videoUrl, segments, options, isRendering]);\n\n return { start, cancel, isRendering, progress, metrics, url, error };\n}\n","'use client';\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { ClipSource, MergeOptions, RichProgress, RenderMetrics, FrameWorker } from '../types.js';\n\nexport interface UseMergeClipsState {\n progress: RichProgress;\n isRendering: boolean;\n error: Error | null;\n blob: Blob | null;\n url: string | null;\n metrics: RenderMetrics | null;\n}\n\nexport interface UseMergeClipsActions {\n mergeClips: (clips: ClipSource[], options?: Omit<MergeOptions, 'onProgress' | 'onComplete' | 'signal'>) => Promise<Blob | null>;\n cancel: () => void;\n reset: () => void;\n}\n\nexport type UseMergeClipsResult = UseMergeClipsState & UseMergeClipsActions;\n\nconst INITIAL_PROGRESS: RichProgress = { overall: 0, clips: [] };\n\nexport function useMergeClips(frameWorker: FrameWorker): UseMergeClipsResult {\n const [state, setState] = useState<UseMergeClipsState>({\n progress: INITIAL_PROGRESS,\n isRendering: false,\n error: null,\n blob: null,\n url: null,\n metrics: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n setState({ progress: INITIAL_PROGRESS, isRendering: false, error: null, blob: null, url: null, metrics: null });\n }, []);\n\n const mergeClips = useCallback(\n async (\n clips: ClipSource[],\n options?: Omit<MergeOptions, 'onProgress' | 'onComplete' | 'signal'>\n ): Promise<Blob | null> => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ progress: INITIAL_PROGRESS, isRendering: true, error: null, blob: null, url: null, metrics: null });\n\n try {\n const { blob, metrics } = await frameWorker.mergeClips(clips, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => setState((prev) => ({ ...prev, progress: p })),\n onComplete: (m) => setState((prev) => ({ ...prev, metrics: m })),\n });\n\n const url = URL.createObjectURL(blob);\n urlRef.current = url;\n const doneProgress: RichProgress = {\n overall: 1,\n clips: clips.map((_, i) => ({ index: i, status: 'done', progress: 1 })),\n };\n setState((prev) => ({ ...prev, progress: doneProgress, isRendering: false, blob, url }));\n return blob;\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setState((prev) => ({ ...prev, isRendering: false, error: null }));\n return null;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({ ...prev, isRendering: false, error }));\n return null;\n }\n },\n [frameWorker]\n );\n\n return { ...state, mergeClips, cancel, reset };\n}\n","'use client';\n\n// ── usePreviewClip — wraps FrameWorker.render(clip) ──────────────────────────\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { ClipSource, RenderOptions, FrameWorker } from '../types.js';\n\nexport interface UsePreviewClipState {\n progress: number;\n isRendering: boolean;\n error: Error | null;\n blob: Blob | null;\n url: string | null;\n}\n\nexport interface UsePreviewClipActions {\n render: (clip: ClipSource, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;\n cancel: () => void;\n reset: () => void;\n}\n\nexport type UsePreviewClipResult = UsePreviewClipState & UsePreviewClipActions;\n\nexport function usePreviewClip(frameWorker: FrameWorker): UsePreviewClipResult {\n const [state, setState] = useState<UsePreviewClipState>({\n progress: 0,\n isRendering: false,\n error: null,\n blob: null,\n url: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });\n }, []);\n\n const render = useCallback(\n async (\n clip: ClipSource,\n options?: Omit<RenderOptions, 'onProgress' | 'signal'>\n ): Promise<Blob | null> => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });\n\n try {\n const blob = await frameWorker.render(clip, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => setState((prev) => ({ ...prev, progress: p })),\n });\n\n const url = URL.createObjectURL(blob);\n urlRef.current = url;\n setState({ progress: 1, isRendering: false, error: null, blob, url });\n return blob;\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setState((prev) => ({ ...prev, isRendering: false, error: null }));\n return null;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({ ...prev, isRendering: false, error }));\n return null;\n }\n },\n [frameWorker]\n );\n\n return { ...state, render, cancel, reset };\n}\n\n// Deprecated aliases\n/** @deprecated Use usePreviewClip() */\nexport const useClipRender = usePreviewClip;\n/** @deprecated Use UsePreviewClipResult */\nexport type UseClipRenderResult = UsePreviewClipResult;\n/** @deprecated Use UsePreviewClipState */\nexport type UseClipRenderState = UsePreviewClipState;\n/** @deprecated Use UsePreviewClipActions */\nexport type UseClipRenderActions = UsePreviewClipActions;\n"]}