@movementinfra/expo-twostep-video 0.1.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.
- package/LICENSE +21 -0
- package/README.md +420 -0
- package/build/ExpoTwostepVideo.types.d.ts +65 -0
- package/build/ExpoTwostepVideo.types.d.ts.map +1 -0
- package/build/ExpoTwostepVideo.types.js +2 -0
- package/build/ExpoTwostepVideo.types.js.map +1 -0
- package/build/ExpoTwostepVideoModule.d.ts +70 -0
- package/build/ExpoTwostepVideoModule.d.ts.map +1 -0
- package/build/ExpoTwostepVideoModule.js +5 -0
- package/build/ExpoTwostepVideoModule.js.map +1 -0
- package/build/ExpoTwostepVideoModule.web.d.ts +14 -0
- package/build/ExpoTwostepVideoModule.web.d.ts.map +1 -0
- package/build/ExpoTwostepVideoModule.web.js +12 -0
- package/build/ExpoTwostepVideoModule.web.js.map +1 -0
- package/build/ExpoTwostepVideoView.d.ts +27 -0
- package/build/ExpoTwostepVideoView.d.ts.map +1 -0
- package/build/ExpoTwostepVideoView.js +47 -0
- package/build/ExpoTwostepVideoView.js.map +1 -0
- package/build/ExpoTwostepVideoView.web.d.ts +4 -0
- package/build/ExpoTwostepVideoView.web.d.ts.map +1 -0
- package/build/ExpoTwostepVideoView.web.js +8 -0
- package/build/ExpoTwostepVideoView.web.js.map +1 -0
- package/build/index.d.ts +569 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +430 -0
- package/build/index.js.map +1 -0
- package/expo-module.config.json +10 -0
- package/ios/ExpoTwostepVideo.podspec +30 -0
- package/ios/ExpoTwostepVideoModule.swift +739 -0
- package/ios/ExpoTwostepVideoView.swift +223 -0
- package/ios/Package.swift +32 -0
- package/ios/TwoStepVideo/Core/AssetLoader.swift +175 -0
- package/ios/TwoStepVideo/Core/VideoExporter.swift +353 -0
- package/ios/TwoStepVideo/Core/VideoTransformer.swift +365 -0
- package/ios/TwoStepVideo/Core/VideoTrimmer.swift +300 -0
- package/ios/TwoStepVideo/Models/ExportConfiguration.swift +104 -0
- package/ios/TwoStepVideo/Models/LoopConfiguration.swift +101 -0
- package/ios/TwoStepVideo/Models/TimeRange.swift +98 -0
- package/ios/TwoStepVideo/Models/VideoAsset.swift +126 -0
- package/ios/TwoStepVideo/Models/VideoEditingError.swift +82 -0
- package/ios/TwoStepVideo/TwoStepVideo.swift +30 -0
- package/package.json +57 -0
package/build/index.js
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TwoStepVideo - Professional video editing for React Native
|
|
3
|
+
* Built on native AVFoundation with Expo Modules
|
|
4
|
+
*/
|
|
5
|
+
import ExpoTwoStepVideoModule from './ExpoTwostepVideoModule';
|
|
6
|
+
// MARK: - Constants
|
|
7
|
+
/**
|
|
8
|
+
* Quality constants
|
|
9
|
+
*/
|
|
10
|
+
export const Quality = {
|
|
11
|
+
LOW: ExpoTwoStepVideoModule.QUALITY_LOW,
|
|
12
|
+
MEDIUM: ExpoTwoStepVideoModule.QUALITY_MEDIUM,
|
|
13
|
+
HIGH: ExpoTwoStepVideoModule.QUALITY_HIGH,
|
|
14
|
+
HIGHEST: ExpoTwoStepVideoModule.QUALITY_HIGHEST,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Mirror axis constants
|
|
18
|
+
*/
|
|
19
|
+
export const Mirror = {
|
|
20
|
+
HORIZONTAL: ExpoTwoStepVideoModule.MIRROR_HORIZONTAL,
|
|
21
|
+
VERTICAL: ExpoTwoStepVideoModule.MIRROR_VERTICAL,
|
|
22
|
+
BOTH: ExpoTwoStepVideoModule.MIRROR_BOTH,
|
|
23
|
+
};
|
|
24
|
+
// MARK: - API Functions
|
|
25
|
+
/**
|
|
26
|
+
* Load a video asset from a file URI
|
|
27
|
+
*
|
|
28
|
+
* @param options - Load options containing the file URI
|
|
29
|
+
* @returns Promise resolving to video asset metadata
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const asset = await TwoStepVideo.loadAsset({
|
|
34
|
+
* uri: 'file:///path/to/video.mp4'
|
|
35
|
+
* });
|
|
36
|
+
* console.log(`Duration: ${asset.duration}s, Size: ${asset.width}x${asset.height}`);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export async function loadAsset(options) {
|
|
40
|
+
return await ExpoTwoStepVideoModule.loadAsset(options.uri);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Load a video asset from the Photos library
|
|
44
|
+
*
|
|
45
|
+
* @param localIdentifier - PHAsset local identifier from the Photos library
|
|
46
|
+
* @returns Promise resolving to video asset metadata
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* // After using expo-media-library to get a photo asset
|
|
51
|
+
* const asset = await TwoStepVideo.loadAssetFromPhotos(photoAsset.id);
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export async function loadAssetFromPhotos(localIdentifier) {
|
|
55
|
+
return await ExpoTwoStepVideoModule.loadAssetFromPhotos(localIdentifier);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Validate a video file URI without loading the full asset
|
|
59
|
+
* Useful for quick validation before processing
|
|
60
|
+
*
|
|
61
|
+
* @param uri - File URI to validate
|
|
62
|
+
* @returns Promise resolving to true if valid video file
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const isValid = await TwoStepVideo.validateVideoUri('file:///path/to/video.mp4');
|
|
67
|
+
* if (isValid) {
|
|
68
|
+
* const asset = await TwoStepVideo.loadAsset({ uri });
|
|
69
|
+
* }
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export async function validateVideoUri(uri) {
|
|
73
|
+
return await ExpoTwoStepVideoModule.validateVideoUri(uri);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Trim a video to a single time range
|
|
77
|
+
*
|
|
78
|
+
* @param options - Trim options including asset ID and time range
|
|
79
|
+
* @returns Promise resolving to composition metadata
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const asset = await TwoStepVideo.loadAsset({ uri });
|
|
84
|
+
* const composition = await TwoStepVideo.trimVideo({
|
|
85
|
+
* assetId: asset.id,
|
|
86
|
+
* startTime: 5.0,
|
|
87
|
+
* endTime: 15.0
|
|
88
|
+
* });
|
|
89
|
+
* console.log(`Trimmed to ${composition.duration}s`);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export async function trimVideo(options) {
|
|
93
|
+
return await ExpoTwoStepVideoModule.trimVideo(options.assetId, options.startTime, options.endTime);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Trim a video to multiple segments and concatenate them
|
|
97
|
+
*
|
|
98
|
+
* @param options - Trim options including asset ID and segments
|
|
99
|
+
* @returns Promise resolving to composition metadata
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const composition = await TwoStepVideo.trimVideoMultiple({
|
|
104
|
+
* assetId: asset.id,
|
|
105
|
+
* segments: [
|
|
106
|
+
* { start: 0, end: 3 }, // First 3 seconds
|
|
107
|
+
* { start: 10, end: 13 }, // 3 seconds from middle
|
|
108
|
+
* { start: 20, end: 23 } // 3 seconds from end
|
|
109
|
+
* ]
|
|
110
|
+
* });
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export async function trimVideoMultiple(options) {
|
|
114
|
+
return await ExpoTwoStepVideoModule.trimVideoMultiple(options.assetId, options.segments);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Mirror a video horizontally, vertically, or both
|
|
118
|
+
*
|
|
119
|
+
* @param options - Mirror options including asset ID and axis
|
|
120
|
+
* @returns Promise resolving to composition metadata
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* // Mirror horizontally (flip left-right, common for selfie videos)
|
|
125
|
+
* const composition = await TwoStepVideo.mirrorVideo({
|
|
126
|
+
* assetId: asset.id,
|
|
127
|
+
* axis: 'horizontal'
|
|
128
|
+
* });
|
|
129
|
+
*
|
|
130
|
+
* // Mirror a specific segment
|
|
131
|
+
* const composition = await TwoStepVideo.mirrorVideo({
|
|
132
|
+
* assetId: asset.id,
|
|
133
|
+
* axis: 'vertical',
|
|
134
|
+
* startTime: 5,
|
|
135
|
+
* endTime: 10
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
export async function mirrorVideo(options) {
|
|
140
|
+
return await ExpoTwoStepVideoModule.mirrorVideo(options.assetId, options.axis, options.startTime, options.endTime);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Adjust the playback speed of a video
|
|
144
|
+
*
|
|
145
|
+
* @param options - Speed options including asset ID and speed multiplier
|
|
146
|
+
* @returns Promise resolving to composition metadata
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* // Slow motion (0.5x speed = 2x slower)
|
|
151
|
+
* const slowMo = await TwoStepVideo.adjustSpeed({
|
|
152
|
+
* assetId: asset.id,
|
|
153
|
+
* speed: 0.5
|
|
154
|
+
* });
|
|
155
|
+
*
|
|
156
|
+
* // Fast forward (2x speed)
|
|
157
|
+
* const fastForward = await TwoStepVideo.adjustSpeed({
|
|
158
|
+
* assetId: asset.id,
|
|
159
|
+
* speed: 2.0
|
|
160
|
+
* });
|
|
161
|
+
*
|
|
162
|
+
* // Speed up a specific segment
|
|
163
|
+
* const timelapse = await TwoStepVideo.adjustSpeed({
|
|
164
|
+
* assetId: asset.id,
|
|
165
|
+
* speed: 4.0,
|
|
166
|
+
* startTime: 10,
|
|
167
|
+
* endTime: 30
|
|
168
|
+
* });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
export async function adjustSpeed(options) {
|
|
172
|
+
return await ExpoTwoStepVideoModule.adjustSpeed(options.assetId, options.speed, options.startTime, options.endTime);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Transform a video with combined trimming, mirroring, and speed adjustment
|
|
176
|
+
* Use the player's `loop` prop for continuous playback looping
|
|
177
|
+
*
|
|
178
|
+
* @param options - Transform options including asset ID, speed, and mirror axis
|
|
179
|
+
* @returns Promise resolving to composition metadata
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* // Mirror and slow down
|
|
184
|
+
* const transformed = await TwoStepVideo.transformVideo({
|
|
185
|
+
* assetId: asset.id,
|
|
186
|
+
* speed: 0.5,
|
|
187
|
+
* mirrorAxis: 'horizontal'
|
|
188
|
+
* });
|
|
189
|
+
*
|
|
190
|
+
* // Just mirror (speed defaults to 1.0)
|
|
191
|
+
* const mirrored = await TwoStepVideo.transformVideo({
|
|
192
|
+
* assetId: asset.id,
|
|
193
|
+
* mirrorAxis: 'both'
|
|
194
|
+
* });
|
|
195
|
+
*
|
|
196
|
+
* // Transform a specific segment (trim + mirror + speed)
|
|
197
|
+
* const segment = await TwoStepVideo.transformVideo({
|
|
198
|
+
* assetId: asset.id,
|
|
199
|
+
* speed: 2.0,
|
|
200
|
+
* mirrorAxis: 'horizontal',
|
|
201
|
+
* startTime: 0,
|
|
202
|
+
* endTime: 5
|
|
203
|
+
* });
|
|
204
|
+
*
|
|
205
|
+
* // Play in loop mode
|
|
206
|
+
* <TwoStepVideoView compositionId={segment.id} loop />
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
export async function transformVideo(options) {
|
|
210
|
+
return await ExpoTwoStepVideoModule.transformVideo(options.assetId, options.speed, options.mirrorAxis, options.startTime, options.endTime);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Loop a segment of a video multiple times
|
|
214
|
+
*
|
|
215
|
+
* @param options - Loop options including segment time range and repeat count
|
|
216
|
+
* @returns Promise resolving to loop result with duration info
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* // Loop a 2-second segment 3 times (plays 4 times total)
|
|
221
|
+
* const looped = await TwoStepVideo.loopSegment({
|
|
222
|
+
* assetId: asset.id,
|
|
223
|
+
* startTime: 5,
|
|
224
|
+
* endTime: 7,
|
|
225
|
+
* loopCount: 3
|
|
226
|
+
* });
|
|
227
|
+
* console.log(`Duration: ${looped.duration}s (plays ${looped.totalPlays} times)`);
|
|
228
|
+
*
|
|
229
|
+
* // Create a perfect loop for social media
|
|
230
|
+
* const perfectLoop = await TwoStepVideo.loopSegment({
|
|
231
|
+
* assetId: asset.id,
|
|
232
|
+
* startTime: 0,
|
|
233
|
+
* endTime: 3,
|
|
234
|
+
* loopCount: 4 // 15 seconds total (3s * 5 plays)
|
|
235
|
+
* });
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
export async function loopSegment(options) {
|
|
239
|
+
return await ExpoTwoStepVideoModule.loopSegment(options.assetId, options.startTime, options.endTime, options.loopCount);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Generate thumbnail images from a video at specific times
|
|
243
|
+
*
|
|
244
|
+
* @param options - Thumbnail generation options
|
|
245
|
+
* @returns Promise resolving to array of base64 encoded PNG images
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* ```typescript
|
|
249
|
+
* const thumbnails = await TwoStepVideo.generateThumbnails({
|
|
250
|
+
* assetId: asset.id,
|
|
251
|
+
* times: [1, 5, 10, 15],
|
|
252
|
+
* size: { width: 300, height: 300 }
|
|
253
|
+
* });
|
|
254
|
+
*
|
|
255
|
+
* // Use in Image component
|
|
256
|
+
* <Image source={{ uri: `data:image/png;base64,${thumbnails[0]}` }} />
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
export async function generateThumbnails(options) {
|
|
260
|
+
return await ExpoTwoStepVideoModule.generateThumbnails(options.assetId, options.times, options.size);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Export a composition to a video file
|
|
264
|
+
*
|
|
265
|
+
* @param options - Export options including composition ID and quality
|
|
266
|
+
* @returns Promise resolving to export result with file URI
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```typescript
|
|
270
|
+
* const result = await TwoStepVideo.exportVideo({
|
|
271
|
+
* compositionId: composition.id,
|
|
272
|
+
* quality: 'high'
|
|
273
|
+
* });
|
|
274
|
+
* console.log(`Exported to: ${result.uri}`);
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
export async function exportVideo(options) {
|
|
278
|
+
return await ExpoTwoStepVideoModule.exportVideo(options.compositionId, options.outputUri, options.quality);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Export an asset directly without creating a composition
|
|
282
|
+
* Useful for re-encoding or changing quality without trimming
|
|
283
|
+
*
|
|
284
|
+
* @param options - Export options including asset ID and quality
|
|
285
|
+
* @returns Promise resolving to export result with file URI
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```typescript
|
|
289
|
+
* const result = await TwoStepVideo.exportAsset({
|
|
290
|
+
* assetId: asset.id,
|
|
291
|
+
* quality: 'medium'
|
|
292
|
+
* });
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
export async function exportAsset(options) {
|
|
296
|
+
return await ExpoTwoStepVideoModule.exportAsset(options.assetId, options.outputUri, options.quality);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Clean up a temporary file
|
|
300
|
+
* Call this after you're done with exported files in the temp directory
|
|
301
|
+
*
|
|
302
|
+
* @param uri - File URI to clean up
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```typescript
|
|
306
|
+
* const result = await TwoStepVideo.exportVideo({ ... });
|
|
307
|
+
* // ... do something with result.uri
|
|
308
|
+
* TwoStepVideo.cleanupFile(result.uri);
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
export function cleanupFile(uri) {
|
|
312
|
+
ExpoTwoStepVideoModule.cleanupFile(uri);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Release an asset from memory
|
|
316
|
+
* Call this when you're done with an asset to free up memory
|
|
317
|
+
*
|
|
318
|
+
* @param assetId - ID of the asset to release
|
|
319
|
+
*/
|
|
320
|
+
export function releaseAsset(assetId) {
|
|
321
|
+
ExpoTwoStepVideoModule.releaseAsset(assetId);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Release a composition from memory
|
|
325
|
+
*
|
|
326
|
+
* @param compositionId - ID of the composition to release
|
|
327
|
+
*/
|
|
328
|
+
export function releaseComposition(compositionId) {
|
|
329
|
+
ExpoTwoStepVideoModule.releaseComposition(compositionId);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Release all cached assets and compositions
|
|
333
|
+
* Useful for cleanup when unmounting screens
|
|
334
|
+
*/
|
|
335
|
+
export function releaseAll() {
|
|
336
|
+
ExpoTwoStepVideoModule.releaseAll();
|
|
337
|
+
}
|
|
338
|
+
// MARK: - Event Listeners
|
|
339
|
+
/**
|
|
340
|
+
* Add a listener for export progress events
|
|
341
|
+
*
|
|
342
|
+
* @param listener - Callback function receiving progress events
|
|
343
|
+
* @returns Subscription object with remove() method
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* ```typescript
|
|
347
|
+
* const subscription = TwoStepVideo.addExportProgressListener((event) => {
|
|
348
|
+
* console.log(`Export progress: ${Math.round(event.progress * 100)}%`);
|
|
349
|
+
* setProgress(event.progress);
|
|
350
|
+
* });
|
|
351
|
+
*
|
|
352
|
+
* // Later, remove the listener
|
|
353
|
+
* subscription.remove();
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
export function addExportProgressListener(listener) {
|
|
357
|
+
return ExpoTwoStepVideoModule.addListener('onExportProgress', listener);
|
|
358
|
+
}
|
|
359
|
+
// MARK: - Helper Hook (for React)
|
|
360
|
+
/**
|
|
361
|
+
* React hook for managing export progress
|
|
362
|
+
* Only works in React components
|
|
363
|
+
*
|
|
364
|
+
* @returns Current export progress (0.0 to 1.0)
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```typescript
|
|
368
|
+
* function VideoEditor() {
|
|
369
|
+
* const progress = useExportProgress();
|
|
370
|
+
*
|
|
371
|
+
* return (
|
|
372
|
+
* <View>
|
|
373
|
+
* <Text>Export Progress: {Math.round(progress * 100)}%</Text>
|
|
374
|
+
* </View>
|
|
375
|
+
* );
|
|
376
|
+
* }
|
|
377
|
+
* ```
|
|
378
|
+
*/
|
|
379
|
+
export function useExportProgress() {
|
|
380
|
+
const [progress, setProgress] = React.useState(0);
|
|
381
|
+
React.useEffect(() => {
|
|
382
|
+
const subscription = addExportProgressListener((event) => {
|
|
383
|
+
setProgress(event.progress);
|
|
384
|
+
});
|
|
385
|
+
return () => subscription.remove();
|
|
386
|
+
}, []);
|
|
387
|
+
return progress;
|
|
388
|
+
}
|
|
389
|
+
// Note: React import needed for the hook
|
|
390
|
+
// If React is not available, the hook won't be usable but
|
|
391
|
+
// the rest of the module will work fine
|
|
392
|
+
let React;
|
|
393
|
+
try {
|
|
394
|
+
React = require('react');
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
// React not available, hook won't work
|
|
398
|
+
}
|
|
399
|
+
// MARK: - Exports
|
|
400
|
+
export default {
|
|
401
|
+
// Constants
|
|
402
|
+
Quality,
|
|
403
|
+
Mirror,
|
|
404
|
+
// Core functions
|
|
405
|
+
loadAsset,
|
|
406
|
+
loadAssetFromPhotos,
|
|
407
|
+
validateVideoUri,
|
|
408
|
+
trimVideo,
|
|
409
|
+
trimVideoMultiple,
|
|
410
|
+
generateThumbnails,
|
|
411
|
+
exportVideo,
|
|
412
|
+
exportAsset,
|
|
413
|
+
// Transformation functions
|
|
414
|
+
mirrorVideo,
|
|
415
|
+
adjustSpeed,
|
|
416
|
+
transformVideo,
|
|
417
|
+
loopSegment,
|
|
418
|
+
// Memory management
|
|
419
|
+
cleanupFile,
|
|
420
|
+
releaseAsset,
|
|
421
|
+
releaseComposition,
|
|
422
|
+
releaseAll,
|
|
423
|
+
// Events
|
|
424
|
+
addExportProgressListener,
|
|
425
|
+
// React hook
|
|
426
|
+
useExportProgress,
|
|
427
|
+
};
|
|
428
|
+
// MARK: - View Component Export
|
|
429
|
+
export { default as TwoStepVideoView } from './ExpoTwostepVideoView';
|
|
430
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TwoStepVideo - Professional video editing for React Native\n * Built on native AVFoundation with Expo Modules\n */\n\nimport { type EventSubscription } from 'expo-modules-core';\nimport ExpoTwoStepVideoModule from './ExpoTwostepVideoModule';\n\n// MARK: - Types\n\n/**\n * Quality presets for video export\n */\nexport type VideoQuality = 'low' | 'medium' | 'high' | 'highest';\n\n/**\n * Mirror axis options for video mirroring\n */\nexport type MirrorAxis = 'horizontal' | 'vertical' | 'both';\n\n/**\n * Video asset metadata returned after loading\n */\nexport interface VideoAsset {\n /** Unique identifier for this asset */\n id: string;\n /** Duration in seconds */\n duration: number;\n /** Video width in pixels */\n width: number;\n /** Video height in pixels */\n height: number;\n /** Frame rate (fps) */\n frameRate: number;\n /** Whether the video has audio */\n hasAudio: boolean;\n}\n\n/**\n * Video composition metadata\n */\nexport interface VideoComposition {\n /** Unique identifier for this composition */\n id: string;\n /** Total duration in seconds */\n duration: number;\n}\n\n/**\n * Time segment for multi-segment trimming\n */\nexport interface TimeSegment {\n /** Start time in seconds */\n start: number;\n /** End time in seconds */\n end: number;\n}\n\n/**\n * Export result containing output file information\n */\nexport interface ExportResult {\n /** File URI (e.g., \"file:///path/to/video.mp4\") */\n uri: string;\n /** Absolute file path */\n path: string;\n}\n\n/**\n * Export progress event\n */\nexport interface ExportProgressEvent {\n /** Progress from 0.0 to 1.0 */\n progress: number;\n /** Asset ID if exporting asset directly */\n assetId?: string;\n /** Composition ID if exporting composition */\n compositionId?: string;\n}\n\n/**\n * Options for loading a video asset\n */\nexport interface LoadAssetOptions {\n /** File URI (e.g., \"file:///path/to/video.mp4\") */\n uri: string;\n}\n\n/**\n * Options for trimming a video\n */\nexport interface TrimVideoOptions {\n /** Asset ID to trim */\n assetId: string;\n /** Start time in seconds */\n startTime: number;\n /** End time in seconds */\n endTime: number;\n}\n\n/**\n * Options for multi-segment trimming\n */\nexport interface TrimMultipleOptions {\n /** Asset ID to trim */\n assetId: string;\n /** Array of time segments to extract and concatenate */\n segments: TimeSegment[];\n}\n\n/**\n * Options for generating thumbnails\n */\nexport interface GenerateThumbnailsOptions {\n /** Asset ID to generate thumbnails from */\n assetId: string;\n /** Array of times (in seconds) to extract thumbnails */\n times: number[];\n /** Optional size for thumbnails */\n size?: {\n width: number;\n height: number;\n };\n}\n\n/**\n * Options for exporting a composition\n */\nexport interface ExportCompositionOptions {\n /** Composition ID to export */\n compositionId: string;\n /** Optional output URI (uses temp directory if not provided) */\n outputUri?: string;\n /** Quality preset (default: 'high') */\n quality?: VideoQuality;\n}\n\n/**\n * Options for exporting an asset directly\n */\nexport interface ExportAssetOptions {\n /** Asset ID to export */\n assetId: string;\n /** Optional output URI (uses temp directory if not provided) */\n outputUri?: string;\n /** Quality preset (default: 'high') */\n quality?: VideoQuality;\n}\n\n/**\n * Options for mirroring a video\n */\nexport interface MirrorVideoOptions {\n /** Asset ID to mirror */\n assetId: string;\n /** Axis to mirror on: 'horizontal', 'vertical', or 'both' */\n axis: MirrorAxis;\n /** Optional start time in seconds (for segment mirroring) */\n startTime?: number;\n /** Optional end time in seconds (for segment mirroring) */\n endTime?: number;\n}\n\n/**\n * Options for adjusting video speed\n */\nexport interface AdjustSpeedOptions {\n /** Asset ID to adjust */\n assetId: string;\n /** Speed multiplier (0.25 = 4x slower, 2.0 = 2x faster) */\n speed: number;\n /** Optional start time in seconds */\n startTime?: number;\n /** Optional end time in seconds */\n endTime?: number;\n}\n\n/**\n * Options for combined video transformation\n */\nexport interface TransformVideoOptions {\n /** Asset ID to transform */\n assetId: string;\n /** Speed multiplier (default: 1.0) */\n speed?: number;\n /** Optional mirror axis */\n mirrorAxis?: MirrorAxis;\n /** Optional start time in seconds (for trimming) */\n startTime?: number;\n /** Optional end time in seconds (for trimming) */\n endTime?: number;\n}\n\n/**\n * Options for looping a video segment\n */\nexport interface LoopSegmentOptions {\n /** Asset ID to loop */\n assetId: string;\n /** Start time of the segment to loop (in seconds) */\n startTime: number;\n /** End time of the segment to loop (in seconds) */\n endTime: number;\n /** Number of times to repeat (total plays = loopCount + 1) */\n loopCount: number;\n}\n\n/**\n * Result from looping a video segment\n */\nexport interface LoopResult {\n /** Unique identifier for this composition */\n id: string;\n /** Total duration in seconds */\n duration: number;\n /** Number of times the segment repeats */\n loopCount: number;\n /** Total number of times the segment plays */\n totalPlays: number;\n}\n\n// MARK: - Constants\n\n/**\n * Quality constants\n */\nexport const Quality = {\n LOW: ExpoTwoStepVideoModule.QUALITY_LOW,\n MEDIUM: ExpoTwoStepVideoModule.QUALITY_MEDIUM,\n HIGH: ExpoTwoStepVideoModule.QUALITY_HIGH,\n HIGHEST: ExpoTwoStepVideoModule.QUALITY_HIGHEST,\n} as const;\n\n/**\n * Mirror axis constants\n */\nexport const Mirror = {\n HORIZONTAL: ExpoTwoStepVideoModule.MIRROR_HORIZONTAL,\n VERTICAL: ExpoTwoStepVideoModule.MIRROR_VERTICAL,\n BOTH: ExpoTwoStepVideoModule.MIRROR_BOTH,\n} as const;\n\n// MARK: - API Functions\n\n/**\n * Load a video asset from a file URI\n *\n * @param options - Load options containing the file URI\n * @returns Promise resolving to video asset metadata\n *\n * @example\n * ```typescript\n * const asset = await TwoStepVideo.loadAsset({\n * uri: 'file:///path/to/video.mp4'\n * });\n * console.log(`Duration: ${asset.duration}s, Size: ${asset.width}x${asset.height}`);\n * ```\n */\nexport async function loadAsset(options: LoadAssetOptions): Promise<VideoAsset> {\n return await ExpoTwoStepVideoModule.loadAsset(options.uri);\n}\n\n/**\n * Load a video asset from the Photos library\n *\n * @param localIdentifier - PHAsset local identifier from the Photos library\n * @returns Promise resolving to video asset metadata\n *\n * @example\n * ```typescript\n * // After using expo-media-library to get a photo asset\n * const asset = await TwoStepVideo.loadAssetFromPhotos(photoAsset.id);\n * ```\n */\nexport async function loadAssetFromPhotos(localIdentifier: string): Promise<VideoAsset> {\n return await ExpoTwoStepVideoModule.loadAssetFromPhotos(localIdentifier);\n}\n\n/**\n * Validate a video file URI without loading the full asset\n * Useful for quick validation before processing\n *\n * @param uri - File URI to validate\n * @returns Promise resolving to true if valid video file\n *\n * @example\n * ```typescript\n * const isValid = await TwoStepVideo.validateVideoUri('file:///path/to/video.mp4');\n * if (isValid) {\n * const asset = await TwoStepVideo.loadAsset({ uri });\n * }\n * ```\n */\nexport async function validateVideoUri(uri: string): Promise<boolean> {\n return await ExpoTwoStepVideoModule.validateVideoUri(uri);\n}\n\n/**\n * Trim a video to a single time range\n *\n * @param options - Trim options including asset ID and time range\n * @returns Promise resolving to composition metadata\n *\n * @example\n * ```typescript\n * const asset = await TwoStepVideo.loadAsset({ uri });\n * const composition = await TwoStepVideo.trimVideo({\n * assetId: asset.id,\n * startTime: 5.0,\n * endTime: 15.0\n * });\n * console.log(`Trimmed to ${composition.duration}s`);\n * ```\n */\nexport async function trimVideo(options: TrimVideoOptions): Promise<VideoComposition> {\n return await ExpoTwoStepVideoModule.trimVideo(\n options.assetId,\n options.startTime,\n options.endTime\n );\n}\n\n/**\n * Trim a video to multiple segments and concatenate them\n *\n * @param options - Trim options including asset ID and segments\n * @returns Promise resolving to composition metadata\n *\n * @example\n * ```typescript\n * const composition = await TwoStepVideo.trimVideoMultiple({\n * assetId: asset.id,\n * segments: [\n * { start: 0, end: 3 }, // First 3 seconds\n * { start: 10, end: 13 }, // 3 seconds from middle\n * { start: 20, end: 23 } // 3 seconds from end\n * ]\n * });\n * ```\n */\nexport async function trimVideoMultiple(options: TrimMultipleOptions): Promise<VideoComposition> {\n return await ExpoTwoStepVideoModule.trimVideoMultiple(options.assetId, options.segments);\n}\n\n/**\n * Mirror a video horizontally, vertically, or both\n *\n * @param options - Mirror options including asset ID and axis\n * @returns Promise resolving to composition metadata\n *\n * @example\n * ```typescript\n * // Mirror horizontally (flip left-right, common for selfie videos)\n * const composition = await TwoStepVideo.mirrorVideo({\n * assetId: asset.id,\n * axis: 'horizontal'\n * });\n *\n * // Mirror a specific segment\n * const composition = await TwoStepVideo.mirrorVideo({\n * assetId: asset.id,\n * axis: 'vertical',\n * startTime: 5,\n * endTime: 10\n * });\n * ```\n */\nexport async function mirrorVideo(options: MirrorVideoOptions): Promise<VideoComposition> {\n return await ExpoTwoStepVideoModule.mirrorVideo(\n options.assetId,\n options.axis,\n options.startTime,\n options.endTime\n );\n}\n\n/**\n * Adjust the playback speed of a video\n *\n * @param options - Speed options including asset ID and speed multiplier\n * @returns Promise resolving to composition metadata\n *\n * @example\n * ```typescript\n * // Slow motion (0.5x speed = 2x slower)\n * const slowMo = await TwoStepVideo.adjustSpeed({\n * assetId: asset.id,\n * speed: 0.5\n * });\n *\n * // Fast forward (2x speed)\n * const fastForward = await TwoStepVideo.adjustSpeed({\n * assetId: asset.id,\n * speed: 2.0\n * });\n *\n * // Speed up a specific segment\n * const timelapse = await TwoStepVideo.adjustSpeed({\n * assetId: asset.id,\n * speed: 4.0,\n * startTime: 10,\n * endTime: 30\n * });\n * ```\n */\nexport async function adjustSpeed(options: AdjustSpeedOptions): Promise<VideoComposition> {\n return await ExpoTwoStepVideoModule.adjustSpeed(\n options.assetId,\n options.speed,\n options.startTime,\n options.endTime\n );\n}\n\n/**\n * Transform a video with combined trimming, mirroring, and speed adjustment\n * Use the player's `loop` prop for continuous playback looping\n *\n * @param options - Transform options including asset ID, speed, and mirror axis\n * @returns Promise resolving to composition metadata\n *\n * @example\n * ```typescript\n * // Mirror and slow down\n * const transformed = await TwoStepVideo.transformVideo({\n * assetId: asset.id,\n * speed: 0.5,\n * mirrorAxis: 'horizontal'\n * });\n *\n * // Just mirror (speed defaults to 1.0)\n * const mirrored = await TwoStepVideo.transformVideo({\n * assetId: asset.id,\n * mirrorAxis: 'both'\n * });\n *\n * // Transform a specific segment (trim + mirror + speed)\n * const segment = await TwoStepVideo.transformVideo({\n * assetId: asset.id,\n * speed: 2.0,\n * mirrorAxis: 'horizontal',\n * startTime: 0,\n * endTime: 5\n * });\n *\n * // Play in loop mode\n * <TwoStepVideoView compositionId={segment.id} loop />\n * ```\n */\nexport async function transformVideo(options: TransformVideoOptions): Promise<VideoComposition> {\n return await ExpoTwoStepVideoModule.transformVideo(\n options.assetId,\n options.speed,\n options.mirrorAxis,\n options.startTime,\n options.endTime\n );\n}\n\n/**\n * Loop a segment of a video multiple times\n *\n * @param options - Loop options including segment time range and repeat count\n * @returns Promise resolving to loop result with duration info\n *\n * @example\n * ```typescript\n * // Loop a 2-second segment 3 times (plays 4 times total)\n * const looped = await TwoStepVideo.loopSegment({\n * assetId: asset.id,\n * startTime: 5,\n * endTime: 7,\n * loopCount: 3\n * });\n * console.log(`Duration: ${looped.duration}s (plays ${looped.totalPlays} times)`);\n *\n * // Create a perfect loop for social media\n * const perfectLoop = await TwoStepVideo.loopSegment({\n * assetId: asset.id,\n * startTime: 0,\n * endTime: 3,\n * loopCount: 4 // 15 seconds total (3s * 5 plays)\n * });\n * ```\n */\nexport async function loopSegment(options: LoopSegmentOptions): Promise<LoopResult> {\n return await ExpoTwoStepVideoModule.loopSegment(\n options.assetId,\n options.startTime,\n options.endTime,\n options.loopCount\n );\n}\n\n/**\n * Generate thumbnail images from a video at specific times\n *\n * @param options - Thumbnail generation options\n * @returns Promise resolving to array of base64 encoded PNG images\n *\n * @example\n * ```typescript\n * const thumbnails = await TwoStepVideo.generateThumbnails({\n * assetId: asset.id,\n * times: [1, 5, 10, 15],\n * size: { width: 300, height: 300 }\n * });\n *\n * // Use in Image component\n * <Image source={{ uri: `data:image/png;base64,${thumbnails[0]}` }} />\n * ```\n */\nexport async function generateThumbnails(\n options: GenerateThumbnailsOptions\n): Promise<string[]> {\n return await ExpoTwoStepVideoModule.generateThumbnails(\n options.assetId,\n options.times,\n options.size\n );\n}\n\n/**\n * Export a composition to a video file\n *\n * @param options - Export options including composition ID and quality\n * @returns Promise resolving to export result with file URI\n *\n * @example\n * ```typescript\n * const result = await TwoStepVideo.exportVideo({\n * compositionId: composition.id,\n * quality: 'high'\n * });\n * console.log(`Exported to: ${result.uri}`);\n * ```\n */\nexport async function exportVideo(options: ExportCompositionOptions): Promise<ExportResult> {\n return await ExpoTwoStepVideoModule.exportVideo(\n options.compositionId,\n options.outputUri,\n options.quality\n );\n}\n\n/**\n * Export an asset directly without creating a composition\n * Useful for re-encoding or changing quality without trimming\n *\n * @param options - Export options including asset ID and quality\n * @returns Promise resolving to export result with file URI\n *\n * @example\n * ```typescript\n * const result = await TwoStepVideo.exportAsset({\n * assetId: asset.id,\n * quality: 'medium'\n * });\n * ```\n */\nexport async function exportAsset(options: ExportAssetOptions): Promise<ExportResult> {\n return await ExpoTwoStepVideoModule.exportAsset(\n options.assetId,\n options.outputUri,\n options.quality\n );\n}\n\n/**\n * Clean up a temporary file\n * Call this after you're done with exported files in the temp directory\n *\n * @param uri - File URI to clean up\n *\n * @example\n * ```typescript\n * const result = await TwoStepVideo.exportVideo({ ... });\n * // ... do something with result.uri\n * TwoStepVideo.cleanupFile(result.uri);\n * ```\n */\nexport function cleanupFile(uri: string): void {\n ExpoTwoStepVideoModule.cleanupFile(uri);\n}\n\n/**\n * Release an asset from memory\n * Call this when you're done with an asset to free up memory\n *\n * @param assetId - ID of the asset to release\n */\nexport function releaseAsset(assetId: string): void {\n ExpoTwoStepVideoModule.releaseAsset(assetId);\n}\n\n/**\n * Release a composition from memory\n *\n * @param compositionId - ID of the composition to release\n */\nexport function releaseComposition(compositionId: string): void {\n ExpoTwoStepVideoModule.releaseComposition(compositionId);\n}\n\n/**\n * Release all cached assets and compositions\n * Useful for cleanup when unmounting screens\n */\nexport function releaseAll(): void {\n ExpoTwoStepVideoModule.releaseAll();\n}\n\n// MARK: - Event Listeners\n\n/**\n * Add a listener for export progress events\n *\n * @param listener - Callback function receiving progress events\n * @returns Subscription object with remove() method\n *\n * @example\n * ```typescript\n * const subscription = TwoStepVideo.addExportProgressListener((event) => {\n * console.log(`Export progress: ${Math.round(event.progress * 100)}%`);\n * setProgress(event.progress);\n * });\n *\n * // Later, remove the listener\n * subscription.remove();\n * ```\n */\nexport function addExportProgressListener(\n listener: (event: ExportProgressEvent) => void\n): EventSubscription {\n return ExpoTwoStepVideoModule.addListener('onExportProgress', listener);\n}\n\n// MARK: - Helper Hook (for React)\n\n/**\n * React hook for managing export progress\n * Only works in React components\n *\n * @returns Current export progress (0.0 to 1.0)\n *\n * @example\n * ```typescript\n * function VideoEditor() {\n * const progress = useExportProgress();\n *\n * return (\n * <View>\n * <Text>Export Progress: {Math.round(progress * 100)}%</Text>\n * </View>\n * );\n * }\n * ```\n */\nexport function useExportProgress(): number {\n const [progress, setProgress] = React.useState(0);\n\n React.useEffect(() => {\n const subscription = addExportProgressListener((event) => {\n setProgress(event.progress);\n });\n\n return () => subscription.remove();\n }, []);\n\n return progress;\n}\n\n// Note: React import needed for the hook\n// If React is not available, the hook won't be usable but\n// the rest of the module will work fine\nlet React: any;\ntry {\n React = require('react');\n} catch {\n // React not available, hook won't work\n}\n\n// MARK: - Exports\n\nexport default {\n // Constants\n Quality,\n Mirror,\n\n // Core functions\n loadAsset,\n loadAssetFromPhotos,\n validateVideoUri,\n trimVideo,\n trimVideoMultiple,\n generateThumbnails,\n exportVideo,\n exportAsset,\n\n // Transformation functions\n mirrorVideo,\n adjustSpeed,\n transformVideo,\n loopSegment,\n\n // Memory management\n cleanupFile,\n releaseAsset,\n releaseComposition,\n releaseAll,\n\n // Events\n addExportProgressListener,\n\n // React hook\n useExportProgress,\n};\n\n// MARK: - View Component Export\n\nexport { default as TwoStepVideoView } from './ExpoTwostepVideoView';\nexport type {\n TwoStepVideoViewProps,\n TwoStepVideoViewRef,\n PlaybackStatusEvent,\n ProgressEvent,\n ErrorEvent,\n} from './ExpoTwostepVideo.types';\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'ExpoTwostepVideo'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.description = package['description']
|
|
10
|
+
s.license = package['license']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.homepage = package['homepage']
|
|
13
|
+
s.platforms = {
|
|
14
|
+
:ios => '16.0',
|
|
15
|
+
:tvos => '16.0'
|
|
16
|
+
}
|
|
17
|
+
s.swift_version = '5.9'
|
|
18
|
+
s.source = { git: 'https://github.com/rguo123/twostep-video' }
|
|
19
|
+
s.static_framework = true
|
|
20
|
+
|
|
21
|
+
s.dependency 'ExpoModulesCore'
|
|
22
|
+
|
|
23
|
+
# Swift/Objective-C compatibility
|
|
24
|
+
s.pod_target_xcconfig = {
|
|
25
|
+
'DEFINES_MODULE' => 'YES',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
|
|
29
|
+
s.exclude_files = ["Tests/**/*", ".build/**/*", "Package.swift"]
|
|
30
|
+
end
|