@maravilla-labs/platform 0.12.0 → 0.14.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/CHANGELOG.md +24 -0
- package/dist/config.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/{transforms-DwCPOVTn.d.ts → transforms-BHWez32E.d.ts} +99 -1
- package/package.json +1 -1
- package/src/remote-client.ts +9 -1
- package/src/transforms.ts +105 -0
|
@@ -32,6 +32,15 @@ interface TranscodeOpts {
|
|
|
32
32
|
max_height?: number;
|
|
33
33
|
audio_codec?: string;
|
|
34
34
|
bitrate_kbps?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Force a constant output frame rate (fps). Pass this for variable-frame-rate
|
|
37
|
+
* sources (e.g. MediaRecorder WebM) so the MP4 stays frame-accurately
|
|
38
|
+
* seekable for the frames pipeline — without it, a near-static VFR segment
|
|
39
|
+
* can collapse to a handful of frames that a fixed-rate renderer stalls on.
|
|
40
|
+
* When omitted, the worker auto-applies CFR only if it probes the source as
|
|
41
|
+
* VFR; a determinate-rate source is left untouched.
|
|
42
|
+
*/
|
|
43
|
+
fps?: number;
|
|
35
44
|
}
|
|
36
45
|
/** Options for `transforms.thumbnail` — extract a single video frame. */
|
|
37
46
|
interface ThumbnailOpts {
|
|
@@ -43,6 +52,80 @@ interface ThumbnailOpts {
|
|
|
43
52
|
format?: ImageFormat;
|
|
44
53
|
quality?: number;
|
|
45
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Options for `transforms.extractFrames` — decode a video into a sequence of
|
|
57
|
+
* still images at a fixed fps. General capability (any MP4 → frames); the
|
|
58
|
+
* frames renderer consumes the result to swap `<video>`→`<img>` per frame, and
|
|
59
|
+
* it's reusable for thumbnails/scrubbing.
|
|
60
|
+
*/
|
|
61
|
+
interface ExtractFramesOpts {
|
|
62
|
+
/** Frames per second to sample the source at. */
|
|
63
|
+
fps: number;
|
|
64
|
+
/** Optional max width (height auto, aspect preserved, no upscaling). */
|
|
65
|
+
width?: number;
|
|
66
|
+
/** Output image format. Defaults to `"jpg"` server-side when omitted. */
|
|
67
|
+
format?: ImageFormat;
|
|
68
|
+
/** JPEG/WebP quality 1..=100 (higher = better). Ignored for PNG. */
|
|
69
|
+
quality?: number;
|
|
70
|
+
/** Start offset into the clip, ms (default 0). */
|
|
71
|
+
seek_ms?: number;
|
|
72
|
+
/** How much of the clip to extract from `seek_ms`, ms (default: to end). */
|
|
73
|
+
duration_ms?: number;
|
|
74
|
+
/**
|
|
75
|
+
* Also extract the source's audio track to `detach_audio.target` in the SAME
|
|
76
|
+
* job — one call yields both the frame set and a detachable audio asset
|
|
77
|
+
* (folds the upload-time "detach audio" step into frame extraction). The
|
|
78
|
+
* frame-set manifest is still the job's primary output; the audio is written
|
|
79
|
+
* to the caller-chosen `target` key.
|
|
80
|
+
*/
|
|
81
|
+
detach_audio?: DetachAudioOpts;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Bundle a detached-audio side-output into an {@link ExtractFramesOpts} job.
|
|
85
|
+
* The worker runs one extra audio-extraction pass on the same source and writes
|
|
86
|
+
* the AAC/m4a result to `target` (a caller-chosen, tenant-scoped storage key).
|
|
87
|
+
*/
|
|
88
|
+
interface DetachAudioOpts {
|
|
89
|
+
/** Storage key to write the extracted audio (AAC/m4a) to. */
|
|
90
|
+
target: string;
|
|
91
|
+
/** Output bitrate, kbps. Server picks a sensible AAC bitrate when omitted. */
|
|
92
|
+
bitrate_kbps?: number;
|
|
93
|
+
/** Start offset into the source, ms (default 0). */
|
|
94
|
+
seek_ms?: number;
|
|
95
|
+
/** How much of the source to extract from `seek_ms`, ms (default: to end). */
|
|
96
|
+
duration_ms?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Options for `transforms.extractAudio` — split a video's audio track off into
|
|
100
|
+
* a standalone AAC/m4a asset. Used to detach the mic/system audio recorded
|
|
101
|
+
* alongside a camera/screen clip so it can be placed + ducked independently on
|
|
102
|
+
* the frames timeline.
|
|
103
|
+
*/
|
|
104
|
+
interface ExtractAudioOpts {
|
|
105
|
+
/** Output bitrate, kbps. Server picks a sensible AAC bitrate when omitted. */
|
|
106
|
+
bitrate_kbps?: number;
|
|
107
|
+
/** Start offset into the source, ms (default 0). */
|
|
108
|
+
seek_ms?: number;
|
|
109
|
+
/** How much of the source to extract from `seek_ms`, ms (default: to end). */
|
|
110
|
+
duration_ms?: number;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Result of an `extractFrames` job: a JSON manifest stored at the job's
|
|
114
|
+
* `output_key` describing the frame set. Frame `i` (0-based) lives at
|
|
115
|
+
* `${prefix}/frame_${i padded to 6}.${ext}`.
|
|
116
|
+
*/
|
|
117
|
+
interface FramesetManifest {
|
|
118
|
+
/** Storage key prefix the frame images live under (no trailing slash). */
|
|
119
|
+
prefix: string;
|
|
120
|
+
/** Number of frames written. */
|
|
121
|
+
count: number;
|
|
122
|
+
/** Sampling fps the frames were extracted at. */
|
|
123
|
+
fps: number;
|
|
124
|
+
/** Frame image format. */
|
|
125
|
+
format: ImageFormat;
|
|
126
|
+
width?: number;
|
|
127
|
+
height?: number;
|
|
128
|
+
}
|
|
46
129
|
/** Options for `transforms.resize`. */
|
|
47
130
|
interface ResizeOpts {
|
|
48
131
|
width?: number;
|
|
@@ -174,6 +257,10 @@ type TransformSpec = ({
|
|
|
174
257
|
} & TranscodeOpts) | ({
|
|
175
258
|
kind: 'thumbnail';
|
|
176
259
|
} & ThumbnailOpts) | ({
|
|
260
|
+
kind: 'extract_frames';
|
|
261
|
+
} & ExtractFramesOpts) | ({
|
|
262
|
+
kind: 'extract_audio';
|
|
263
|
+
} & ExtractAudioOpts) | ({
|
|
177
264
|
kind: 'resize';
|
|
178
265
|
} & ResizeOpts) | ({
|
|
179
266
|
kind: 'ocr';
|
|
@@ -219,6 +306,17 @@ interface JobStatusResponse {
|
|
|
219
306
|
interface TransformsService {
|
|
220
307
|
transcode(srcKey: string, opts: TranscodeOpts): Promise<JobHandle>;
|
|
221
308
|
thumbnail(srcKey: string, opts: ThumbnailOpts): Promise<JobHandle>;
|
|
309
|
+
/**
|
|
310
|
+
* Decode a video into a sequence of frame images at a fixed fps. Resolves to
|
|
311
|
+
* a `JobHandle` whose `output_key` holds a `FramesetManifest` (JSON) once
|
|
312
|
+
* complete; frames live under `${manifest.prefix}/frame_NNNNNN.<ext>`.
|
|
313
|
+
*/
|
|
314
|
+
extractFrames(srcKey: string, opts: ExtractFramesOpts): Promise<JobHandle>;
|
|
315
|
+
/**
|
|
316
|
+
* Extract a video's audio track to a standalone AAC/m4a asset. Resolves to a
|
|
317
|
+
* `JobHandle` whose `output_key` holds the audio file once complete.
|
|
318
|
+
*/
|
|
319
|
+
extractAudio(srcKey: string, opts?: ExtractAudioOpts | null): Promise<JobHandle>;
|
|
222
320
|
resize(srcKey: string, opts: ResizeOpts): Promise<JobHandle>;
|
|
223
321
|
probe(srcKey: string): Promise<MediaInfo>;
|
|
224
322
|
ocr(srcKey: string, opts?: OcrOpts | null): Promise<JobHandle>;
|
|
@@ -298,4 +396,4 @@ interface TransformsPatternSpec {
|
|
|
298
396
|
*/
|
|
299
397
|
type TransformsConfig = Record<string, TransformsPatternSpec>;
|
|
300
398
|
|
|
301
|
-
export { type
|
|
399
|
+
export { type DetachAudioOpts as D, type ExtractFramesOpts as E, type FramesetManifest as F, type ImageFormat as I, type JobStatus as J, type MediaInfo as M, type OcrOpts as O, type QrCodeSpec as Q, type ResizeOpts as R, type TransformsConfig as T, type VideoFormat as V, type TransformsPatternSpec as a, type TranscodeOpts as b, type ThumbnailOpts as c, type ExtractAudioOpts as d, type DocFormat as e, type DocToPdfOpts as f, type DocThumbnailOpts as g, type DocConvertOpts as h, type DocToMarkdownOpts as i, type DocToHtmlOpts as j, type ImageRef as k, type DocReplaceImagesOpts as l, type DocInsertQrCodeOpts as m, type QrPayload as n, type DocTemplateMergeOpts as o, type TransformSpec as p, type JobHandle as q, type JobStatusResponse as r, type TransformsService as s, keyFor as t, transforms as u };
|
package/package.json
CHANGED
package/src/remote-client.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { KvNamespace, KvListResult, Database, DbDocument, DbFindOptions, Storage, RealtimeService, PresenceService, AuthService, AuthCaller, AuthUser, AuthSession, AuthField, RegisterOptions, LoginOptions, CreateManagedUserOptions, UserListFilter, UserListResponse, UpdateUserOptions, Relation, AddRelationOptions, ListRelationsOptions, PolicyExplain, CanCheck, ConnectedClient, ApiKeyInfo, LoginSession, PolicyService, VectorIndexSpec, VectorIndexDescriptor, VectorQueryWithFilter, VectorSearchHit, IndexSpec, IndexDescriptor, Workflows, WorkflowHandle, WorkflowRun, WorkflowStepRecord, BrowserClient, FramesClient, BrowserJobHandle, ScreenshotRequest, PdfRequest, FramesRenderRequest } from './types.js';
|
|
2
|
-
import type { TransformsService, TranscodeOpts, ThumbnailOpts, ResizeOpts, OcrOpts, DocToPdfOpts, DocThumbnailOpts, DocConvertOpts, DocToMarkdownOpts, DocToHtmlOpts, DocReplaceImagesOpts, DocInsertQrCodeOpts, DocTemplateMergeOpts, JobHandle, JobStatusResponse, MediaInfo } from './transforms.js';
|
|
2
|
+
import type { TransformsService, TranscodeOpts, ExtractFramesOpts, ExtractAudioOpts, ThumbnailOpts, ResizeOpts, OcrOpts, DocToPdfOpts, DocThumbnailOpts, DocConvertOpts, DocToMarkdownOpts, DocToHtmlOpts, DocReplaceImagesOpts, DocInsertQrCodeOpts, DocTemplateMergeOpts, JobHandle, JobStatusResponse, MediaInfo } from './transforms.js';
|
|
3
3
|
import { RemoteMediaService } from './media.js';
|
|
4
4
|
import { getRequestAuthHeader } from './request-scope.js';
|
|
5
5
|
|
|
@@ -1280,6 +1280,14 @@ class RemoteTransformsService implements TransformsService {
|
|
|
1280
1280
|
return this.post<JobHandle>('/transcode', { srcKey, opts });
|
|
1281
1281
|
}
|
|
1282
1282
|
|
|
1283
|
+
extractFrames(srcKey: string, opts: ExtractFramesOpts): Promise<JobHandle> {
|
|
1284
|
+
return this.post<JobHandle>('/extract_frames', { srcKey, opts });
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
extractAudio(srcKey: string, opts?: ExtractAudioOpts | null): Promise<JobHandle> {
|
|
1288
|
+
return this.post<JobHandle>('/extract_audio', { srcKey, opts: opts ?? {} });
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1283
1291
|
thumbnail(srcKey: string, opts: ThumbnailOpts): Promise<JobHandle> {
|
|
1284
1292
|
return this.post<JobHandle>('/thumbnail', { srcKey, opts });
|
|
1285
1293
|
}
|
package/src/transforms.ts
CHANGED
|
@@ -80,6 +80,15 @@ export interface TranscodeOpts {
|
|
|
80
80
|
max_height?: number;
|
|
81
81
|
audio_codec?: string;
|
|
82
82
|
bitrate_kbps?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Force a constant output frame rate (fps). Pass this for variable-frame-rate
|
|
85
|
+
* sources (e.g. MediaRecorder WebM) so the MP4 stays frame-accurately
|
|
86
|
+
* seekable for the frames pipeline — without it, a near-static VFR segment
|
|
87
|
+
* can collapse to a handful of frames that a fixed-rate renderer stalls on.
|
|
88
|
+
* When omitted, the worker auto-applies CFR only if it probes the source as
|
|
89
|
+
* VFR; a determinate-rate source is left untouched.
|
|
90
|
+
*/
|
|
91
|
+
fps?: number;
|
|
83
92
|
}
|
|
84
93
|
|
|
85
94
|
/** Options for `transforms.thumbnail` — extract a single video frame. */
|
|
@@ -93,6 +102,84 @@ export interface ThumbnailOpts {
|
|
|
93
102
|
quality?: number;
|
|
94
103
|
}
|
|
95
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Options for `transforms.extractFrames` — decode a video into a sequence of
|
|
107
|
+
* still images at a fixed fps. General capability (any MP4 → frames); the
|
|
108
|
+
* frames renderer consumes the result to swap `<video>`→`<img>` per frame, and
|
|
109
|
+
* it's reusable for thumbnails/scrubbing.
|
|
110
|
+
*/
|
|
111
|
+
export interface ExtractFramesOpts {
|
|
112
|
+
/** Frames per second to sample the source at. */
|
|
113
|
+
fps: number;
|
|
114
|
+
/** Optional max width (height auto, aspect preserved, no upscaling). */
|
|
115
|
+
width?: number;
|
|
116
|
+
/** Output image format. Defaults to `"jpg"` server-side when omitted. */
|
|
117
|
+
format?: ImageFormat;
|
|
118
|
+
/** JPEG/WebP quality 1..=100 (higher = better). Ignored for PNG. */
|
|
119
|
+
quality?: number;
|
|
120
|
+
/** Start offset into the clip, ms (default 0). */
|
|
121
|
+
seek_ms?: number;
|
|
122
|
+
/** How much of the clip to extract from `seek_ms`, ms (default: to end). */
|
|
123
|
+
duration_ms?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Also extract the source's audio track to `detach_audio.target` in the SAME
|
|
126
|
+
* job — one call yields both the frame set and a detachable audio asset
|
|
127
|
+
* (folds the upload-time "detach audio" step into frame extraction). The
|
|
128
|
+
* frame-set manifest is still the job's primary output; the audio is written
|
|
129
|
+
* to the caller-chosen `target` key.
|
|
130
|
+
*/
|
|
131
|
+
detach_audio?: DetachAudioOpts;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Bundle a detached-audio side-output into an {@link ExtractFramesOpts} job.
|
|
136
|
+
* The worker runs one extra audio-extraction pass on the same source and writes
|
|
137
|
+
* the AAC/m4a result to `target` (a caller-chosen, tenant-scoped storage key).
|
|
138
|
+
*/
|
|
139
|
+
export interface DetachAudioOpts {
|
|
140
|
+
/** Storage key to write the extracted audio (AAC/m4a) to. */
|
|
141
|
+
target: string;
|
|
142
|
+
/** Output bitrate, kbps. Server picks a sensible AAC bitrate when omitted. */
|
|
143
|
+
bitrate_kbps?: number;
|
|
144
|
+
/** Start offset into the source, ms (default 0). */
|
|
145
|
+
seek_ms?: number;
|
|
146
|
+
/** How much of the source to extract from `seek_ms`, ms (default: to end). */
|
|
147
|
+
duration_ms?: number;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Options for `transforms.extractAudio` — split a video's audio track off into
|
|
152
|
+
* a standalone AAC/m4a asset. Used to detach the mic/system audio recorded
|
|
153
|
+
* alongside a camera/screen clip so it can be placed + ducked independently on
|
|
154
|
+
* the frames timeline.
|
|
155
|
+
*/
|
|
156
|
+
export interface ExtractAudioOpts {
|
|
157
|
+
/** Output bitrate, kbps. Server picks a sensible AAC bitrate when omitted. */
|
|
158
|
+
bitrate_kbps?: number;
|
|
159
|
+
/** Start offset into the source, ms (default 0). */
|
|
160
|
+
seek_ms?: number;
|
|
161
|
+
/** How much of the source to extract from `seek_ms`, ms (default: to end). */
|
|
162
|
+
duration_ms?: number;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Result of an `extractFrames` job: a JSON manifest stored at the job's
|
|
167
|
+
* `output_key` describing the frame set. Frame `i` (0-based) lives at
|
|
168
|
+
* `${prefix}/frame_${i padded to 6}.${ext}`.
|
|
169
|
+
*/
|
|
170
|
+
export interface FramesetManifest {
|
|
171
|
+
/** Storage key prefix the frame images live under (no trailing slash). */
|
|
172
|
+
prefix: string;
|
|
173
|
+
/** Number of frames written. */
|
|
174
|
+
count: number;
|
|
175
|
+
/** Sampling fps the frames were extracted at. */
|
|
176
|
+
fps: number;
|
|
177
|
+
/** Frame image format. */
|
|
178
|
+
format: ImageFormat;
|
|
179
|
+
width?: number;
|
|
180
|
+
height?: number;
|
|
181
|
+
}
|
|
182
|
+
|
|
96
183
|
/** Options for `transforms.resize`. */
|
|
97
184
|
export interface ResizeOpts {
|
|
98
185
|
width?: number;
|
|
@@ -236,6 +323,8 @@ export interface DocTemplateMergeOpts {
|
|
|
236
323
|
export type TransformSpec =
|
|
237
324
|
| ({ kind: 'transcode' } & TranscodeOpts)
|
|
238
325
|
| ({ kind: 'thumbnail' } & ThumbnailOpts)
|
|
326
|
+
| ({ kind: 'extract_frames' } & ExtractFramesOpts)
|
|
327
|
+
| ({ kind: 'extract_audio' } & ExtractAudioOpts)
|
|
239
328
|
| ({ kind: 'resize' } & ResizeOpts)
|
|
240
329
|
| ({ kind: 'ocr' } & OcrOpts)
|
|
241
330
|
| ({ kind: 'doc_to_pdf' } & DocToPdfOpts)
|
|
@@ -277,6 +366,17 @@ export interface JobStatusResponse {
|
|
|
277
366
|
export interface TransformsService {
|
|
278
367
|
transcode(srcKey: string, opts: TranscodeOpts): Promise<JobHandle>;
|
|
279
368
|
thumbnail(srcKey: string, opts: ThumbnailOpts): Promise<JobHandle>;
|
|
369
|
+
/**
|
|
370
|
+
* Decode a video into a sequence of frame images at a fixed fps. Resolves to
|
|
371
|
+
* a `JobHandle` whose `output_key` holds a `FramesetManifest` (JSON) once
|
|
372
|
+
* complete; frames live under `${manifest.prefix}/frame_NNNNNN.<ext>`.
|
|
373
|
+
*/
|
|
374
|
+
extractFrames(srcKey: string, opts: ExtractFramesOpts): Promise<JobHandle>;
|
|
375
|
+
/**
|
|
376
|
+
* Extract a video's audio track to a standalone AAC/m4a asset. Resolves to a
|
|
377
|
+
* `JobHandle` whose `output_key` holds the audio file once complete.
|
|
378
|
+
*/
|
|
379
|
+
extractAudio(srcKey: string, opts?: ExtractAudioOpts | null): Promise<JobHandle>;
|
|
280
380
|
resize(srcKey: string, opts: ResizeOpts): Promise<JobHandle>;
|
|
281
381
|
probe(srcKey: string): Promise<MediaInfo>;
|
|
282
382
|
ocr(srcKey: string, opts?: OcrOpts | null): Promise<JobHandle>;
|
|
@@ -340,6 +440,11 @@ function outputExtension(spec: TransformSpec): string {
|
|
|
340
440
|
switch (spec.kind) {
|
|
341
441
|
case 'transcode':
|
|
342
442
|
return spec.format; // 'mp4' | 'webm'
|
|
443
|
+
case 'extract_frames':
|
|
444
|
+
// Output key is the JSON frameset manifest; frames live under its base.
|
|
445
|
+
return 'json';
|
|
446
|
+
case 'extract_audio':
|
|
447
|
+
return 'm4a';
|
|
343
448
|
case 'thumbnail':
|
|
344
449
|
case 'resize': {
|
|
345
450
|
// thumbnail's `format` is optional in TS (defaults to jpg server-side);
|