@editframe/assets 0.7.0-beta.8 → 0.8.0-beta.10
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/dist/EncodedAsset.d.ts +101 -0
- package/dist/EncodedAsset.js +564 -0
- package/dist/MP4File.d.ts +31 -0
- package/dist/{packages/assets/src/Probe.d.ts → Probe.d.ts} +45 -41
- package/dist/{packages/assets/src/Probe.js → Probe.js} +54 -5
- package/dist/{packages/assets/src/VideoRenderOptions.d.ts → VideoRenderOptions.d.ts} +0 -1
- package/dist/{packages/assets/src/idempotentTask.d.ts → idempotentTask.d.ts} +0 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.js +24 -0
- package/dist/{packages/assets/src/md5.d.ts → md5.d.ts} +1 -1
- package/dist/{packages/assets/src/md5.js → md5.js} +6 -0
- package/dist/memoize.d.ts +2 -0
- package/dist/memoize.js +14 -0
- package/dist/{packages/assets/src/mp4FileWritable.d.ts → mp4FileWritable.d.ts} +1 -2
- package/dist/tasks/cacheImage.d.ts +1 -0
- package/dist/tasks/findOrCreateCaptions.d.ts +2 -0
- package/dist/tasks/findOrCreateCaptions.js +30 -0
- package/dist/tasks/generateTrack.d.ts +4 -0
- package/dist/{packages/assets/src/tasks → tasks}/generateTrack.js +26 -23
- package/dist/tasks/generateTrackFragmentIndex.d.ts +3 -0
- package/dist/{packages/assets/src/tasks → tasks}/generateTrackFragmentIndex.js +12 -6
- package/package.json +16 -12
- package/src/tasks/cacheImage.ts +1 -1
- package/src/tasks/findOrCreateCaptions.ts +18 -11
- package/src/tasks/generateTrack.ts +36 -31
- package/src/tasks/generateTrackFragmentIndex.ts +16 -9
- package/dist/lib/av/MP4File.cjs +0 -187
- package/dist/lib/util/execPromise.cjs +0 -6
- package/dist/lib/util/execPromise.js +0 -6
- package/dist/packages/assets/src/Probe.cjs +0 -224
- package/dist/packages/assets/src/VideoRenderOptions.cjs +0 -36
- package/dist/packages/assets/src/idempotentTask.cjs +0 -57
- package/dist/packages/assets/src/index.cjs +0 -20
- package/dist/packages/assets/src/index.d.ts +0 -9
- package/dist/packages/assets/src/index.js +0 -20
- package/dist/packages/assets/src/md5.cjs +0 -60
- package/dist/packages/assets/src/mp4FileWritable.cjs +0 -21
- package/dist/packages/assets/src/tasks/cacheImage.cjs +0 -22
- package/dist/packages/assets/src/tasks/cacheImage.d.ts +0 -1
- package/dist/packages/assets/src/tasks/findOrCreateCaptions.cjs +0 -26
- package/dist/packages/assets/src/tasks/findOrCreateCaptions.d.ts +0 -1
- package/dist/packages/assets/src/tasks/findOrCreateCaptions.js +0 -26
- package/dist/packages/assets/src/tasks/generateTrack.cjs +0 -52
- package/dist/packages/assets/src/tasks/generateTrack.d.ts +0 -1
- package/dist/packages/assets/src/tasks/generateTrackFragmentIndex.cjs +0 -105
- package/dist/packages/assets/src/tasks/generateTrackFragmentIndex.d.ts +0 -1
- /package/dist/{lib/av/MP4File.js → MP4File.js} +0 -0
- /package/dist/{packages/assets/src/VideoRenderOptions.js → VideoRenderOptions.js} +0 -0
- /package/dist/{packages/assets/src/idempotentTask.js → idempotentTask.js} +0 -0
- /package/dist/{packages/assets/src/mp4FileWritable.js → mp4FileWritable.js} +0 -0
- /package/dist/{packages/assets/src/tasks → tasks}/cacheImage.js +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Readable } from 'node:stream';
|
|
1
2
|
import * as z from "zod";
|
|
2
3
|
export declare const AudioStreamSchema: z.ZodObject<{
|
|
3
4
|
index: z.ZodNumber;
|
|
@@ -22,6 +23,7 @@ export declare const AudioStreamSchema: z.ZodObject<{
|
|
|
22
23
|
bit_rate: z.ZodString;
|
|
23
24
|
disposition: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
24
25
|
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
duration: number;
|
|
25
27
|
index: number;
|
|
26
28
|
codec_name: string;
|
|
27
29
|
codec_long_name: string;
|
|
@@ -39,11 +41,11 @@ export declare const AudioStreamSchema: z.ZodObject<{
|
|
|
39
41
|
start_pts: number;
|
|
40
42
|
start_time: number;
|
|
41
43
|
duration_ts: number;
|
|
42
|
-
duration: number;
|
|
43
44
|
bit_rate: string;
|
|
44
45
|
disposition: Record<string, unknown>;
|
|
45
46
|
initial_padding?: number | undefined;
|
|
46
47
|
}, {
|
|
48
|
+
duration: number;
|
|
47
49
|
index: number;
|
|
48
50
|
codec_name: string;
|
|
49
51
|
codec_long_name: string;
|
|
@@ -61,7 +63,6 @@ export declare const AudioStreamSchema: z.ZodObject<{
|
|
|
61
63
|
start_pts: number;
|
|
62
64
|
start_time: number;
|
|
63
65
|
duration_ts: number;
|
|
64
|
-
duration: number;
|
|
65
66
|
bit_rate: string;
|
|
66
67
|
disposition: Record<string, unknown>;
|
|
67
68
|
initial_padding?: number | undefined;
|
|
@@ -102,10 +103,10 @@ export declare const VideoStreamSchema: z.ZodObject<{
|
|
|
102
103
|
height: number;
|
|
103
104
|
coded_width: number;
|
|
104
105
|
coded_height: number;
|
|
106
|
+
duration?: number | undefined;
|
|
105
107
|
start_pts?: number | undefined;
|
|
106
108
|
start_time?: number | undefined;
|
|
107
109
|
duration_ts?: number | undefined;
|
|
108
|
-
duration?: number | undefined;
|
|
109
110
|
bit_rate?: string | undefined;
|
|
110
111
|
}, {
|
|
111
112
|
index: number;
|
|
@@ -122,10 +123,10 @@ export declare const VideoStreamSchema: z.ZodObject<{
|
|
|
122
123
|
height: number;
|
|
123
124
|
coded_width: number;
|
|
124
125
|
coded_height: number;
|
|
126
|
+
duration?: number | undefined;
|
|
125
127
|
start_pts?: number | undefined;
|
|
126
128
|
start_time?: number | undefined;
|
|
127
129
|
duration_ts?: number | undefined;
|
|
128
|
-
duration?: number | undefined;
|
|
129
130
|
bit_rate?: string | undefined;
|
|
130
131
|
}>;
|
|
131
132
|
export type VideoStreamSchema = z.infer<typeof VideoStreamSchema>;
|
|
@@ -152,6 +153,7 @@ declare const StreamSchema: z.ZodDiscriminatedUnion<"codec_type", [z.ZodObject<{
|
|
|
152
153
|
bit_rate: z.ZodString;
|
|
153
154
|
disposition: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
154
155
|
}, "strip", z.ZodTypeAny, {
|
|
156
|
+
duration: number;
|
|
155
157
|
index: number;
|
|
156
158
|
codec_name: string;
|
|
157
159
|
codec_long_name: string;
|
|
@@ -169,11 +171,11 @@ declare const StreamSchema: z.ZodDiscriminatedUnion<"codec_type", [z.ZodObject<{
|
|
|
169
171
|
start_pts: number;
|
|
170
172
|
start_time: number;
|
|
171
173
|
duration_ts: number;
|
|
172
|
-
duration: number;
|
|
173
174
|
bit_rate: string;
|
|
174
175
|
disposition: Record<string, unknown>;
|
|
175
176
|
initial_padding?: number | undefined;
|
|
176
177
|
}, {
|
|
178
|
+
duration: number;
|
|
177
179
|
index: number;
|
|
178
180
|
codec_name: string;
|
|
179
181
|
codec_long_name: string;
|
|
@@ -191,7 +193,6 @@ declare const StreamSchema: z.ZodDiscriminatedUnion<"codec_type", [z.ZodObject<{
|
|
|
191
193
|
start_pts: number;
|
|
192
194
|
start_time: number;
|
|
193
195
|
duration_ts: number;
|
|
194
|
-
duration: number;
|
|
195
196
|
bit_rate: string;
|
|
196
197
|
disposition: Record<string, unknown>;
|
|
197
198
|
initial_padding?: number | undefined;
|
|
@@ -230,10 +231,10 @@ declare const StreamSchema: z.ZodDiscriminatedUnion<"codec_type", [z.ZodObject<{
|
|
|
230
231
|
height: number;
|
|
231
232
|
coded_width: number;
|
|
232
233
|
coded_height: number;
|
|
234
|
+
duration?: number | undefined;
|
|
233
235
|
start_pts?: number | undefined;
|
|
234
236
|
start_time?: number | undefined;
|
|
235
237
|
duration_ts?: number | undefined;
|
|
236
|
-
duration?: number | undefined;
|
|
237
238
|
bit_rate?: string | undefined;
|
|
238
239
|
}, {
|
|
239
240
|
index: number;
|
|
@@ -250,10 +251,10 @@ declare const StreamSchema: z.ZodDiscriminatedUnion<"codec_type", [z.ZodObject<{
|
|
|
250
251
|
height: number;
|
|
251
252
|
coded_width: number;
|
|
252
253
|
coded_height: number;
|
|
254
|
+
duration?: number | undefined;
|
|
253
255
|
start_pts?: number | undefined;
|
|
254
256
|
start_time?: number | undefined;
|
|
255
257
|
duration_ts?: number | undefined;
|
|
256
|
-
duration?: number | undefined;
|
|
257
258
|
bit_rate?: string | undefined;
|
|
258
259
|
}>]>;
|
|
259
260
|
export type StreamSchema = z.infer<typeof StreamSchema>;
|
|
@@ -281,6 +282,7 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
281
282
|
bit_rate: z.ZodString;
|
|
282
283
|
disposition: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
283
284
|
}, "strip", z.ZodTypeAny, {
|
|
285
|
+
duration: number;
|
|
284
286
|
index: number;
|
|
285
287
|
codec_name: string;
|
|
286
288
|
codec_long_name: string;
|
|
@@ -298,11 +300,11 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
298
300
|
start_pts: number;
|
|
299
301
|
start_time: number;
|
|
300
302
|
duration_ts: number;
|
|
301
|
-
duration: number;
|
|
302
303
|
bit_rate: string;
|
|
303
304
|
disposition: Record<string, unknown>;
|
|
304
305
|
initial_padding?: number | undefined;
|
|
305
306
|
}, {
|
|
307
|
+
duration: number;
|
|
306
308
|
index: number;
|
|
307
309
|
codec_name: string;
|
|
308
310
|
codec_long_name: string;
|
|
@@ -320,7 +322,6 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
320
322
|
start_pts: number;
|
|
321
323
|
start_time: number;
|
|
322
324
|
duration_ts: number;
|
|
323
|
-
duration: number;
|
|
324
325
|
bit_rate: string;
|
|
325
326
|
disposition: Record<string, unknown>;
|
|
326
327
|
initial_padding?: number | undefined;
|
|
@@ -359,10 +360,10 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
359
360
|
height: number;
|
|
360
361
|
coded_width: number;
|
|
361
362
|
coded_height: number;
|
|
363
|
+
duration?: number | undefined;
|
|
362
364
|
start_pts?: number | undefined;
|
|
363
365
|
start_time?: number | undefined;
|
|
364
366
|
duration_ts?: number | undefined;
|
|
365
|
-
duration?: number | undefined;
|
|
366
367
|
bit_rate?: string | undefined;
|
|
367
368
|
}, {
|
|
368
369
|
index: number;
|
|
@@ -379,10 +380,10 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
379
380
|
height: number;
|
|
380
381
|
coded_width: number;
|
|
381
382
|
coded_height: number;
|
|
383
|
+
duration?: number | undefined;
|
|
382
384
|
start_pts?: number | undefined;
|
|
383
385
|
start_time?: number | undefined;
|
|
384
386
|
duration_ts?: number | undefined;
|
|
385
|
-
duration?: number | undefined;
|
|
386
387
|
bit_rate?: string | undefined;
|
|
387
388
|
}>]>, "many">;
|
|
388
389
|
format: z.ZodObject<{
|
|
@@ -393,7 +394,7 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
393
394
|
format_long_name: z.ZodString;
|
|
394
395
|
start_time: z.ZodOptional<z.ZodString>;
|
|
395
396
|
duration: z.ZodOptional<z.ZodString>;
|
|
396
|
-
size: z.ZodString
|
|
397
|
+
size: z.ZodOptional<z.ZodString>;
|
|
397
398
|
bit_rate: z.ZodOptional<z.ZodString>;
|
|
398
399
|
probe_score: z.ZodNumber;
|
|
399
400
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -402,25 +403,38 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
402
403
|
nb_programs: number;
|
|
403
404
|
format_name: string;
|
|
404
405
|
format_long_name: string;
|
|
405
|
-
size: string;
|
|
406
406
|
probe_score: number;
|
|
407
|
-
start_time?: string | undefined;
|
|
408
407
|
duration?: string | undefined;
|
|
408
|
+
start_time?: string | undefined;
|
|
409
409
|
bit_rate?: string | undefined;
|
|
410
|
+
size?: string | undefined;
|
|
410
411
|
}, {
|
|
411
412
|
filename: string;
|
|
412
413
|
nb_streams: number;
|
|
413
414
|
nb_programs: number;
|
|
414
415
|
format_name: string;
|
|
415
416
|
format_long_name: string;
|
|
416
|
-
size: string;
|
|
417
417
|
probe_score: number;
|
|
418
|
-
start_time?: string | undefined;
|
|
419
418
|
duration?: string | undefined;
|
|
419
|
+
start_time?: string | undefined;
|
|
420
420
|
bit_rate?: string | undefined;
|
|
421
|
+
size?: string | undefined;
|
|
421
422
|
}>;
|
|
422
423
|
}, "strip", z.ZodTypeAny, {
|
|
424
|
+
format: {
|
|
425
|
+
filename: string;
|
|
426
|
+
nb_streams: number;
|
|
427
|
+
nb_programs: number;
|
|
428
|
+
format_name: string;
|
|
429
|
+
format_long_name: string;
|
|
430
|
+
probe_score: number;
|
|
431
|
+
duration?: string | undefined;
|
|
432
|
+
start_time?: string | undefined;
|
|
433
|
+
bit_rate?: string | undefined;
|
|
434
|
+
size?: string | undefined;
|
|
435
|
+
};
|
|
423
436
|
streams: ({
|
|
437
|
+
duration: number;
|
|
424
438
|
index: number;
|
|
425
439
|
codec_name: string;
|
|
426
440
|
codec_long_name: string;
|
|
@@ -438,7 +452,6 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
438
452
|
start_pts: number;
|
|
439
453
|
start_time: number;
|
|
440
454
|
duration_ts: number;
|
|
441
|
-
duration: number;
|
|
442
455
|
bit_rate: string;
|
|
443
456
|
disposition: Record<string, unknown>;
|
|
444
457
|
initial_padding?: number | undefined;
|
|
@@ -457,26 +470,27 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
457
470
|
height: number;
|
|
458
471
|
coded_width: number;
|
|
459
472
|
coded_height: number;
|
|
473
|
+
duration?: number | undefined;
|
|
460
474
|
start_pts?: number | undefined;
|
|
461
475
|
start_time?: number | undefined;
|
|
462
476
|
duration_ts?: number | undefined;
|
|
463
|
-
duration?: number | undefined;
|
|
464
477
|
bit_rate?: string | undefined;
|
|
465
478
|
})[];
|
|
479
|
+
}, {
|
|
466
480
|
format: {
|
|
467
481
|
filename: string;
|
|
468
482
|
nb_streams: number;
|
|
469
483
|
nb_programs: number;
|
|
470
484
|
format_name: string;
|
|
471
485
|
format_long_name: string;
|
|
472
|
-
size: string;
|
|
473
486
|
probe_score: number;
|
|
474
|
-
start_time?: string | undefined;
|
|
475
487
|
duration?: string | undefined;
|
|
488
|
+
start_time?: string | undefined;
|
|
476
489
|
bit_rate?: string | undefined;
|
|
490
|
+
size?: string | undefined;
|
|
477
491
|
};
|
|
478
|
-
}, {
|
|
479
492
|
streams: ({
|
|
493
|
+
duration: number;
|
|
480
494
|
index: number;
|
|
481
495
|
codec_name: string;
|
|
482
496
|
codec_long_name: string;
|
|
@@ -494,7 +508,6 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
494
508
|
start_pts: number;
|
|
495
509
|
start_time: number;
|
|
496
510
|
duration_ts: number;
|
|
497
|
-
duration: number;
|
|
498
511
|
bit_rate: string;
|
|
499
512
|
disposition: Record<string, unknown>;
|
|
500
513
|
initial_padding?: number | undefined;
|
|
@@ -513,24 +526,12 @@ declare const ProbeSchema: z.ZodObject<{
|
|
|
513
526
|
height: number;
|
|
514
527
|
coded_width: number;
|
|
515
528
|
coded_height: number;
|
|
529
|
+
duration?: number | undefined;
|
|
516
530
|
start_pts?: number | undefined;
|
|
517
531
|
start_time?: number | undefined;
|
|
518
532
|
duration_ts?: number | undefined;
|
|
519
|
-
duration?: number | undefined;
|
|
520
533
|
bit_rate?: string | undefined;
|
|
521
534
|
})[];
|
|
522
|
-
format: {
|
|
523
|
-
filename: string;
|
|
524
|
-
nb_streams: number;
|
|
525
|
-
nb_programs: number;
|
|
526
|
-
format_name: string;
|
|
527
|
-
format_long_name: string;
|
|
528
|
-
size: string;
|
|
529
|
-
probe_score: number;
|
|
530
|
-
start_time?: string | undefined;
|
|
531
|
-
duration?: string | undefined;
|
|
532
|
-
bit_rate?: string | undefined;
|
|
533
|
-
};
|
|
534
535
|
}>;
|
|
535
536
|
export interface TrackSegment {
|
|
536
537
|
cts: number;
|
|
@@ -548,6 +549,7 @@ interface AudioTrackFragmentIndex {
|
|
|
548
549
|
sample_rate: number;
|
|
549
550
|
sample_size: number;
|
|
550
551
|
sample_count: number;
|
|
552
|
+
codec: string;
|
|
551
553
|
initSegment: {
|
|
552
554
|
offset: 0;
|
|
553
555
|
size: number;
|
|
@@ -562,6 +564,7 @@ interface VideoTrackFragmentIndex {
|
|
|
562
564
|
width: number;
|
|
563
565
|
height: number;
|
|
564
566
|
sample_count: number;
|
|
567
|
+
codec: string;
|
|
565
568
|
initSegment: {
|
|
566
569
|
offset: 0;
|
|
567
570
|
size: number;
|
|
@@ -573,10 +576,12 @@ export declare class Probe {
|
|
|
573
576
|
private absolutePath;
|
|
574
577
|
data: z.infer<typeof ProbeSchema>;
|
|
575
578
|
static probePath(absolutePath: string): Promise<Probe>;
|
|
579
|
+
static probeStream(stream: Readable): Promise<Probe>;
|
|
576
580
|
constructor(absolutePath: string, rawData: any);
|
|
577
581
|
get audioStreams(): AudioStreamSchema[];
|
|
578
582
|
get videoStreams(): VideoStreamSchema[];
|
|
579
583
|
get streams(): ({
|
|
584
|
+
duration: number;
|
|
580
585
|
index: number;
|
|
581
586
|
codec_name: string;
|
|
582
587
|
codec_long_name: string;
|
|
@@ -594,7 +599,6 @@ export declare class Probe {
|
|
|
594
599
|
start_pts: number;
|
|
595
600
|
start_time: number;
|
|
596
601
|
duration_ts: number;
|
|
597
|
-
duration: number;
|
|
598
602
|
bit_rate: string;
|
|
599
603
|
disposition: Record<string, unknown>;
|
|
600
604
|
initial_padding?: number | undefined;
|
|
@@ -613,10 +617,10 @@ export declare class Probe {
|
|
|
613
617
|
height: number;
|
|
614
618
|
coded_width: number;
|
|
615
619
|
coded_height: number;
|
|
620
|
+
duration?: number | undefined;
|
|
616
621
|
start_pts?: number | undefined;
|
|
617
622
|
start_time?: number | undefined;
|
|
618
623
|
duration_ts?: number | undefined;
|
|
619
|
-
duration?: number | undefined;
|
|
620
624
|
bit_rate?: string | undefined;
|
|
621
625
|
})[];
|
|
622
626
|
get format(): {
|
|
@@ -625,11 +629,11 @@ export declare class Probe {
|
|
|
625
629
|
nb_programs: number;
|
|
626
630
|
format_name: string;
|
|
627
631
|
format_long_name: string;
|
|
628
|
-
size: string;
|
|
629
632
|
probe_score: number;
|
|
630
|
-
start_time?: string | undefined;
|
|
631
633
|
duration?: string | undefined;
|
|
634
|
+
start_time?: string | undefined;
|
|
632
635
|
bit_rate?: string | undefined;
|
|
636
|
+
size?: string | undefined;
|
|
633
637
|
};
|
|
634
638
|
get mustReencodeAudio(): boolean;
|
|
635
639
|
get mustReencodeVideo(): boolean;
|
|
@@ -641,6 +645,6 @@ export declare class Probe {
|
|
|
641
645
|
get mustProcess(): boolean;
|
|
642
646
|
get ffmpegAudioOptions(): string[];
|
|
643
647
|
get ffmpegVideoOptions(): string[];
|
|
644
|
-
createConformingReadstream():
|
|
648
|
+
createConformingReadstream(): Readable;
|
|
645
649
|
}
|
|
646
650
|
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
1
|
+
import { exec, spawn } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
2
3
|
import { createReadStream } from "node:fs";
|
|
3
4
|
import * as z from "zod";
|
|
4
5
|
import debug from "debug";
|
|
5
|
-
|
|
6
|
+
const execPromise = promisify(exec);
|
|
6
7
|
const log = debug("ef:assets:probe");
|
|
7
8
|
const AudioStreamSchema = z.object({
|
|
8
9
|
index: z.number(),
|
|
@@ -56,7 +57,7 @@ const ProbeFormatSchema = z.object({
|
|
|
56
57
|
format_long_name: z.string(),
|
|
57
58
|
start_time: z.string().optional(),
|
|
58
59
|
duration: z.string().optional(),
|
|
59
|
-
size: z.string(),
|
|
60
|
+
size: z.string().optional(),
|
|
60
61
|
bit_rate: z.string().optional(),
|
|
61
62
|
probe_score: z.number()
|
|
62
63
|
});
|
|
@@ -82,6 +83,51 @@ class Probe {
|
|
|
82
83
|
const json = JSON.parse(probeResult.stdout);
|
|
83
84
|
return new Probe(absolutePath, json);
|
|
84
85
|
}
|
|
86
|
+
static async probeStream(stream) {
|
|
87
|
+
const probeCommand = "ffprobe -i pipe:0 -v error -show_format -show_streams -of json";
|
|
88
|
+
log("Probing", probeCommand);
|
|
89
|
+
const probe = spawn(
|
|
90
|
+
"ffprobe",
|
|
91
|
+
[
|
|
92
|
+
"-i",
|
|
93
|
+
"-",
|
|
94
|
+
"-v",
|
|
95
|
+
"error",
|
|
96
|
+
"-show_format",
|
|
97
|
+
"-show_streams",
|
|
98
|
+
"-of",
|
|
99
|
+
"json"
|
|
100
|
+
],
|
|
101
|
+
{
|
|
102
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
const chunks = [];
|
|
106
|
+
probe.stderr.on("data", (data) => {
|
|
107
|
+
log(data.toString());
|
|
108
|
+
});
|
|
109
|
+
probe.stdout.on("data", (data) => {
|
|
110
|
+
chunks.push(data);
|
|
111
|
+
});
|
|
112
|
+
stream.pipe(probe.stdin);
|
|
113
|
+
probe.stdin.on("error", (error) => {
|
|
114
|
+
log("ffprobe stdin error", error);
|
|
115
|
+
});
|
|
116
|
+
const json = await new Promise((resolve, reject) => {
|
|
117
|
+
probe.stdout.on("end", () => {
|
|
118
|
+
stream.unpipe(probe.stdin);
|
|
119
|
+
stream.destroy();
|
|
120
|
+
try {
|
|
121
|
+
const buffer = Buffer.concat(chunks).toString("utf8");
|
|
122
|
+
log("Got probe from stream", buffer);
|
|
123
|
+
resolve(JSON.parse(buffer));
|
|
124
|
+
} catch (error) {
|
|
125
|
+
reject(error);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
return new Probe("pipe:0", json);
|
|
130
|
+
}
|
|
85
131
|
get audioStreams() {
|
|
86
132
|
return this.data.streams.filter(
|
|
87
133
|
(stream) => stream.codec_type === "audio"
|
|
@@ -160,6 +206,9 @@ class Probe {
|
|
|
160
206
|
];
|
|
161
207
|
}
|
|
162
208
|
createConformingReadstream() {
|
|
209
|
+
if (this.absolutePath === "pipe:0") {
|
|
210
|
+
throw new Error("Cannot create conforming readstream from pipe");
|
|
211
|
+
}
|
|
163
212
|
if (!this.mustProcess) {
|
|
164
213
|
return createReadStream(this.absolutePath);
|
|
165
214
|
}
|
|
@@ -171,7 +220,7 @@ class Probe {
|
|
|
171
220
|
"-f",
|
|
172
221
|
"mp4",
|
|
173
222
|
"-movflags",
|
|
174
|
-
"cmaf+frag_keyframe+empty_moov",
|
|
223
|
+
"cmaf+frag_keyframe+empty_moov+delay_moov",
|
|
175
224
|
"pipe:1"
|
|
176
225
|
];
|
|
177
226
|
log("Running ffmpeg", ffmpegConformanceArgs);
|
|
@@ -189,7 +238,7 @@ class Probe {
|
|
|
189
238
|
"-f",
|
|
190
239
|
"mp4",
|
|
191
240
|
"-movflags",
|
|
192
|
-
"frag_keyframe+empty_moov",
|
|
241
|
+
"frag_keyframe+empty_moov+delay_moov",
|
|
193
242
|
"pipe:1"
|
|
194
243
|
];
|
|
195
244
|
log("Running ffmpeg", ffmpegFragmentArgs);
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { AudioStreamSchema, VideoStreamSchema, Probe } from './Probe.ts';
|
|
2
|
+
export type { StreamSchema, TrackSegment, TrackFragmentIndex, } from './Probe.ts';
|
|
3
|
+
export { md5FilePath, md5Directory, md5ReadStream, md5Buffer } from './md5.ts';
|
|
4
|
+
export { generateTrackFragmentIndex, generateTrackFragmentIndexFromPath, } from './tasks/generateTrackFragmentIndex.ts';
|
|
5
|
+
export { generateTrack, generateTrackFromPath } from './tasks/generateTrack.ts';
|
|
6
|
+
export { findOrCreateCaptions, generateCaptionDataFromPath, } from './tasks/findOrCreateCaptions.ts';
|
|
7
|
+
export { cacheImage } from './tasks/cacheImage.ts';
|
|
8
|
+
export type { TaskResult } from './idempotentTask.ts';
|
|
9
|
+
export { VideoRenderOptions } from './VideoRenderOptions.ts';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AudioStreamSchema, Probe, VideoStreamSchema } from "./Probe.js";
|
|
2
|
+
import { md5Buffer, md5Directory, md5FilePath, md5ReadStream } from "./md5.js";
|
|
3
|
+
import { generateTrackFragmentIndex, generateTrackFragmentIndexFromPath } from "./tasks/generateTrackFragmentIndex.js";
|
|
4
|
+
import { generateTrack, generateTrackFromPath } from "./tasks/generateTrack.js";
|
|
5
|
+
import { findOrCreateCaptions, generateCaptionDataFromPath } from "./tasks/findOrCreateCaptions.js";
|
|
6
|
+
import { cacheImage } from "./tasks/cacheImage.js";
|
|
7
|
+
import { VideoRenderOptions } from "./VideoRenderOptions.js";
|
|
8
|
+
export {
|
|
9
|
+
AudioStreamSchema,
|
|
10
|
+
Probe,
|
|
11
|
+
VideoRenderOptions,
|
|
12
|
+
VideoStreamSchema,
|
|
13
|
+
cacheImage,
|
|
14
|
+
findOrCreateCaptions,
|
|
15
|
+
generateCaptionDataFromPath,
|
|
16
|
+
generateTrack,
|
|
17
|
+
generateTrackFragmentIndex,
|
|
18
|
+
generateTrackFragmentIndexFromPath,
|
|
19
|
+
generateTrackFromPath,
|
|
20
|
+
md5Buffer,
|
|
21
|
+
md5Directory,
|
|
22
|
+
md5FilePath,
|
|
23
|
+
md5ReadStream
|
|
24
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReadStream } from 'node:fs';
|
|
2
2
|
import { Ora } from 'ora';
|
|
3
|
-
|
|
4
3
|
export declare function md5Directory(directory: string, spinner?: Ora): Promise<string>;
|
|
5
4
|
export declare function md5FilePath(filePath: string): Promise<string>;
|
|
6
5
|
export declare function md5ReadStream(readStream: ReadStream): Promise<string>;
|
|
6
|
+
export declare function md5Buffer(buffer: Buffer): string;
|
|
@@ -44,6 +44,11 @@ function md5ReadStream(readStream) {
|
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
|
+
function md5Buffer(buffer) {
|
|
48
|
+
const hash = crypto.createHash("md5");
|
|
49
|
+
hash.update(buffer);
|
|
50
|
+
return addDashesToUUID(hash.digest("hex"));
|
|
51
|
+
}
|
|
47
52
|
function addDashesToUUID(uuidWithoutDashes) {
|
|
48
53
|
if (uuidWithoutDashes.length !== 32) {
|
|
49
54
|
throw new Error("Invalid UUID without dashes. Expected 32 characters.");
|
|
@@ -54,6 +59,7 @@ function addDashesToUUID(uuidWithoutDashes) {
|
|
|
54
59
|
);
|
|
55
60
|
}
|
|
56
61
|
export {
|
|
62
|
+
md5Buffer,
|
|
57
63
|
md5Directory,
|
|
58
64
|
md5FilePath,
|
|
59
65
|
md5ReadStream
|
package/dist/memoize.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const memoize = (_target, _propertyKey, descriptor) => {
|
|
2
|
+
const get = descriptor.get;
|
|
3
|
+
if (!get) return;
|
|
4
|
+
const memoized = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
descriptor.get = function() {
|
|
6
|
+
if (!memoized.has(this)) {
|
|
7
|
+
memoized.set(this, get.call(this));
|
|
8
|
+
}
|
|
9
|
+
return memoized.get(this);
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
memoize
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const cacheImage: (cacheRoot: string, absolutePath: string) => Promise<import('../idempotentTask.ts').TaskResult>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { exec } from "node:child_process";
|
|
4
|
+
import debug from "debug";
|
|
5
|
+
import { idempotentTask } from "../idempotentTask.js";
|
|
6
|
+
const execPromise = promisify(exec);
|
|
7
|
+
const log = debug("ef:generateCaptions");
|
|
8
|
+
const generateCaptionDataFromPath = async (absolutePath) => {
|
|
9
|
+
const command = `whisper_timestamped --language en --efficient --output_format vtt ${absolutePath}`;
|
|
10
|
+
log(`Running command: ${command}`);
|
|
11
|
+
const { stdout } = await execPromise(command);
|
|
12
|
+
return stdout;
|
|
13
|
+
};
|
|
14
|
+
const generateCaptionDataTask = idempotentTask({
|
|
15
|
+
label: "captions",
|
|
16
|
+
filename: (absolutePath) => `${basename(absolutePath)}.captions.json`,
|
|
17
|
+
runner: generateCaptionDataFromPath
|
|
18
|
+
});
|
|
19
|
+
const findOrCreateCaptions = async (cacheRoot, absolutePath) => {
|
|
20
|
+
try {
|
|
21
|
+
return await generateCaptionDataTask(cacheRoot, absolutePath);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.trace("Error finding or creating captions", error);
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export {
|
|
28
|
+
findOrCreateCaptions,
|
|
29
|
+
generateCaptionDataFromPath
|
|
30
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { PassThrough } from 'node:stream';
|
|
2
|
+
export declare const generateTrackFromPath: (absolutePath: string, trackId: number) => Promise<PassThrough>;
|
|
3
|
+
export declare const generateTrackTask: (rootDir: string, absolutePath: string, trackId: number) => Promise<import('../idempotentTask.ts').TaskResult>;
|
|
4
|
+
export declare const generateTrack: (cacheRoot: string, absolutePath: string, url: string) => Promise<import('../idempotentTask.ts').TaskResult>;
|
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
import { idempotentTask } from "../idempotentTask.js";
|
|
2
|
-
import { MP4File } from "
|
|
2
|
+
import { MP4File } from "../MP4File.js";
|
|
3
3
|
import debug from "debug";
|
|
4
4
|
import { mp4FileWritable } from "../mp4FileWritable.js";
|
|
5
5
|
import { PassThrough } from "node:stream";
|
|
6
6
|
import { basename } from "node:path";
|
|
7
7
|
import { Probe } from "../Probe.js";
|
|
8
|
+
const generateTrackFromPath = async (absolutePath, trackId) => {
|
|
9
|
+
const log = debug("ef:generateTrackFragment");
|
|
10
|
+
const probe = await Probe.probePath(absolutePath);
|
|
11
|
+
const readStream = probe.createConformingReadstream();
|
|
12
|
+
const mp4File = new MP4File();
|
|
13
|
+
log(`Generating track for ${absolutePath}`);
|
|
14
|
+
readStream.pipe(mp4FileWritable(mp4File));
|
|
15
|
+
await new Promise((resolve, reject) => {
|
|
16
|
+
readStream.on("end", resolve);
|
|
17
|
+
readStream.on("error", reject);
|
|
18
|
+
});
|
|
19
|
+
const trackStream = new PassThrough();
|
|
20
|
+
for await (const fragment of mp4File.fragmentIterator()) {
|
|
21
|
+
if (fragment.track !== trackId) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
trackStream.write(Buffer.from(fragment.data), "binary");
|
|
25
|
+
}
|
|
26
|
+
trackStream.end();
|
|
27
|
+
return trackStream;
|
|
28
|
+
};
|
|
8
29
|
const generateTrackTask = idempotentTask({
|
|
9
30
|
label: "track",
|
|
10
31
|
filename: (absolutePath, trackId) => `${basename(absolutePath)}.track-${trackId}.mp4`,
|
|
11
|
-
runner:
|
|
12
|
-
const log = debug("ef:generateTrackFragment");
|
|
13
|
-
const probe = await Probe.probePath(absolutePath);
|
|
14
|
-
const readStream = probe.createConformingReadstream();
|
|
15
|
-
const mp4File = new MP4File();
|
|
16
|
-
log(`Generating track fragment index for ${absolutePath}`);
|
|
17
|
-
readStream.pipe(mp4FileWritable(mp4File));
|
|
18
|
-
await new Promise((resolve, reject) => {
|
|
19
|
-
readStream.on("end", resolve);
|
|
20
|
-
readStream.on("error", reject);
|
|
21
|
-
});
|
|
22
|
-
const trackStream = new PassThrough();
|
|
23
|
-
for await (const fragment of mp4File.fragmentIterator()) {
|
|
24
|
-
if (fragment.track !== trackId) {
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
trackStream.write(Buffer.from(fragment.data), "binary");
|
|
28
|
-
}
|
|
29
|
-
trackStream.end();
|
|
30
|
-
return trackStream;
|
|
31
|
-
}
|
|
32
|
+
runner: generateTrackFromPath
|
|
32
33
|
});
|
|
33
34
|
const generateTrack = async (cacheRoot, absolutePath, url) => {
|
|
34
35
|
try {
|
|
@@ -48,5 +49,7 @@ const generateTrack = async (cacheRoot, absolutePath, url) => {
|
|
|
48
49
|
}
|
|
49
50
|
};
|
|
50
51
|
export {
|
|
51
|
-
generateTrack
|
|
52
|
+
generateTrack,
|
|
53
|
+
generateTrackFromPath,
|
|
54
|
+
generateTrackTask
|
|
52
55
|
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { TrackFragmentIndex } from '../Probe.ts';
|
|
2
|
+
export declare const generateTrackFragmentIndexFromPath: (absolutePath: string) => Promise<Record<number, TrackFragmentIndex>>;
|
|
3
|
+
export declare const generateTrackFragmentIndex: (cacheRoot: string, absolutePath: string) => Promise<import('../idempotentTask.ts').TaskResult>;
|