@editframe/api 0.12.0-beta.3 → 0.12.0-beta.6

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.
Files changed (29) hide show
  1. package/dist/{index.js → api/src/index.js} +9 -4
  2. package/dist/{resources → api/src/resources}/image-file.js +25 -4
  3. package/dist/{resources → api/src/resources}/isobmff-file.js +20 -0
  4. package/dist/{resources → api/src/resources}/unprocessed-file.js +33 -8
  5. package/dist/cli/src/utils/createReadableStreamFromReadable.js +82 -0
  6. package/dist/index.d.ts +3 -3
  7. package/dist/resources/image-file.d.ts +9 -3
  8. package/dist/resources/isobmff-file.d.ts +13 -0
  9. package/dist/resources/isobmff-track.d.ts +8 -8
  10. package/dist/resources/renders.d.ts +4 -4
  11. package/dist/resources/unprocessed-file.d.ts +5 -2
  12. package/package.json +2 -2
  13. package/src/resources/image-file.test.ts +3 -6
  14. package/src/resources/image-file.ts +34 -5
  15. package/src/resources/isobmff-file.ts +32 -0
  16. package/src/resources/unprocessed-file.test.ts +5 -7
  17. package/src/resources/unprocessed-file.ts +46 -12
  18. /package/dist/{CHUNK_SIZE_BYTES.js → api/src/CHUNK_SIZE_BYTES.js} +0 -0
  19. /package/dist/{ProgressIterator.js → api/src/ProgressIterator.js} +0 -0
  20. /package/dist/{StreamEventSource.js → api/src/StreamEventSource.js} +0 -0
  21. /package/dist/{client.js → api/src/client.js} +0 -0
  22. /package/dist/{resources → api/src/resources}/caption-file.js +0 -0
  23. /package/dist/{resources → api/src/resources}/isobmff-track.js +0 -0
  24. /package/dist/{resources → api/src/resources}/process-isobmff.js +0 -0
  25. /package/dist/{resources → api/src/resources}/renders.js +0 -0
  26. /package/dist/{resources → api/src/resources}/transcriptions.js +0 -0
  27. /package/dist/{resources → api/src/resources}/url-token.js +0 -0
  28. /package/dist/{streamChunker.js → api/src/streamChunker.js} +0 -0
  29. /package/dist/{uploadChunks.js → api/src/uploadChunks.js} +0 -0
@@ -1,11 +1,11 @@
1
1
  import { CreateCaptionFilePayload, createCaptionFile, lookupCaptionFileByMd5, uploadCaptionFile } from "./resources/caption-file.js";
2
- import { CreateImageFilePayload, createImageFile, lookupImageFileByMd5, uploadImageFile } from "./resources/image-file.js";
3
- import { CreateISOBMFFFilePayload, createISOBMFFFile, getISOBMFFFileTranscription, lookupISOBMFFFileByMd5, uploadFragmentIndex } from "./resources/isobmff-file.js";
2
+ import { CreateImageFilePayload, createImageFile, createImageFileFromPath, lookupImageFileByMd5, uploadImageFile } from "./resources/image-file.js";
3
+ import { CreateISOBMFFFilePayload, TranscribeISOBMFFFilePayload, createISOBMFFFile, getISOBMFFFileTranscription, lookupISOBMFFFileByMd5, transcribeISOBMFFFile, uploadFragmentIndex } from "./resources/isobmff-file.js";
4
4
  import { CreateISOBMFFTrackPayload, createISOBMFFTrack, uploadISOBMFFTrack } from "./resources/isobmff-track.js";
5
5
  import { CreateRenderPayload, createRender, lookupRenderByMd5, uploadRender } from "./resources/renders.js";
6
6
  import { CreateTranscriptionPayload, createTranscription, getTranscriptionInfo, getTranscriptionProgress } from "./resources/transcriptions.js";
7
7
  import { createURLToken } from "./resources/url-token.js";
8
- import { CreateUnprocessedFilePayload, createUnprocessedFile, lookupUnprocessedFileByMd5, processIsobmffFile, uploadUnprocessedFile } from "./resources/unprocessed-file.js";
8
+ import { CreateUnprocessedFilePayload, createUnprocessedFile, createUnprocessedFileFromPath, lookupUnprocessedFileByMd5, processIsobmffFile, uploadUnprocessedFile, uploadUnprocessedReadableStream } from "./resources/unprocessed-file.js";
9
9
  import { getIsobmffProcessInfo, getIsobmffProcessProgress } from "./resources/process-isobmff.js";
10
10
  import { Client } from "./client.js";
11
11
  export {
@@ -17,14 +17,17 @@ export {
17
17
  CreateRenderPayload,
18
18
  CreateTranscriptionPayload,
19
19
  CreateUnprocessedFilePayload,
20
+ TranscribeISOBMFFFilePayload,
20
21
  createCaptionFile,
21
22
  createISOBMFFFile,
22
23
  createISOBMFFTrack,
23
24
  createImageFile,
25
+ createImageFileFromPath,
24
26
  createRender,
25
27
  createTranscription,
26
28
  createURLToken,
27
29
  createUnprocessedFile,
30
+ createUnprocessedFileFromPath,
28
31
  getISOBMFFFileTranscription,
29
32
  getIsobmffProcessInfo,
30
33
  getIsobmffProcessProgress,
@@ -36,10 +39,12 @@ export {
36
39
  lookupRenderByMd5,
37
40
  lookupUnprocessedFileByMd5,
38
41
  processIsobmffFile,
42
+ transcribeISOBMFFFile,
39
43
  uploadCaptionFile,
40
44
  uploadFragmentIndex,
41
45
  uploadISOBMFFTrack,
42
46
  uploadImageFile,
43
47
  uploadRender,
44
- uploadUnprocessedFile
48
+ uploadUnprocessedFile,
49
+ uploadUnprocessedReadableStream
45
50
  };
@@ -1,5 +1,9 @@
1
1
  import debug from "debug";
2
+ import mime from "mime";
2
3
  import { z } from "zod";
4
+ import { stat } from "node:fs/promises";
5
+ import { basename } from "node:path";
6
+ import { md5FilePath } from "@editframe/assets";
3
7
  import { uploadChunks } from "../uploadChunks.js";
4
8
  const log = debug("ef:api:image-file");
5
9
  const MAX_IMAGE_SIZE = 1024 * 1024 * 16;
@@ -11,6 +15,22 @@ const CreateImageFilePayload = z.object({
11
15
  filename: z.string(),
12
16
  byte_size: z.number().int().max(MAX_IMAGE_SIZE)
13
17
  });
18
+ const createImageFileFromPath = async (client, path) => {
19
+ const fileInfo = await stat(path);
20
+ const byte_size = fileInfo.size;
21
+ const md5 = await md5FilePath(path);
22
+ const mime_type = mime.getType(path);
23
+ return createImageFile(client, {
24
+ ...CreateImageFilePayload.parse({
25
+ md5,
26
+ height: 0,
27
+ width: 0,
28
+ mime_type,
29
+ filename: basename(path),
30
+ byte_size
31
+ })
32
+ });
33
+ };
14
34
  const createImageFile = async (client, payload) => {
15
35
  log("Creating image file", payload);
16
36
  CreateImageFilePayload.parse(payload);
@@ -26,11 +46,11 @@ const createImageFile = async (client, payload) => {
26
46
  `Failed to create file ${response.status} ${response.statusText}`
27
47
  );
28
48
  };
29
- const uploadImageFile = (client, fileId, fileStream, fileSize) => {
30
- log("Uploading image file", fileId);
49
+ const uploadImageFile = (client, uploadDetails, fileStream) => {
50
+ log("Uploading image file", uploadDetails.id);
31
51
  return uploadChunks(client, {
32
- url: `/api/v1/image_files/${fileId}/upload`,
33
- fileSize,
52
+ url: `/api/v1/image_files/${uploadDetails.id}/upload`,
53
+ fileSize: uploadDetails.byte_size,
34
54
  fileStream,
35
55
  maxSize: MAX_IMAGE_SIZE
36
56
  });
@@ -56,6 +76,7 @@ const lookupImageFileByMd5 = async (client, md5) => {
56
76
  export {
57
77
  CreateImageFilePayload,
58
78
  createImageFile,
79
+ createImageFileFromPath,
59
80
  lookupImageFileByMd5,
60
81
  uploadImageFile
61
82
  };
@@ -73,10 +73,30 @@ const getISOBMFFFileTranscription = async (client, id) => {
73
73
  `Failed to get isobmff file transcription ${id} ${response.status} ${response.statusText}`
74
74
  );
75
75
  };
76
+ const TranscribeISOBMFFFilePayload = z.object({
77
+ trackId: z.string().optional()
78
+ });
79
+ const transcribeISOBMFFFile = async (client, id, payload = {}) => {
80
+ const response = await client.authenticatedFetch(
81
+ `/api/v1/isobmff_files/${id}/transcribe`,
82
+ {
83
+ method: "POST",
84
+ body: JSON.stringify(payload)
85
+ }
86
+ );
87
+ if (response.ok) {
88
+ return await response.json();
89
+ }
90
+ throw new Error(
91
+ `Failed to transcribe isobmff file ${id} ${response.status} ${response.statusText}`
92
+ );
93
+ };
76
94
  export {
77
95
  CreateISOBMFFFilePayload,
96
+ TranscribeISOBMFFFilePayload,
78
97
  createISOBMFFFile,
79
98
  getISOBMFFFileTranscription,
80
99
  lookupISOBMFFFileByMd5,
100
+ transcribeISOBMFFFile,
81
101
  uploadFragmentIndex
82
102
  };
@@ -1,5 +1,10 @@
1
+ import { stat } from "node:fs/promises";
1
2
  import debug from "debug";
2
3
  import { z } from "zod";
4
+ import { createReadStream } from "node:fs";
5
+ import { basename } from "node:path";
6
+ import { md5FilePath } from "@editframe/assets";
7
+ import { createReadableStreamFromReadable } from "../../../cli/src/utils/createReadableStreamFromReadable.js";
3
8
  import { uploadChunks } from "../uploadChunks.js";
4
9
  const log = debug("ef:api:unprocessed-file");
5
10
  const MAX_FILE_SIZE = 1024 * 1024 * 1024;
@@ -9,6 +14,16 @@ const CreateUnprocessedFilePayload = z.object({
9
14
  byte_size: z.number().int().max(MAX_FILE_SIZE)
10
15
  });
11
16
  z.object({});
17
+ const createUnprocessedFileFromPath = async (client, path) => {
18
+ const fileInfo = await stat(path);
19
+ const byte_size = fileInfo.size;
20
+ const md5 = await md5FilePath(path);
21
+ return createUnprocessedFile(client, {
22
+ md5,
23
+ filename: basename(path),
24
+ byte_size
25
+ });
26
+ };
12
27
  const createUnprocessedFile = async (client, payload) => {
13
28
  log("Creating an unprocessed file", payload);
14
29
  CreateUnprocessedFilePayload.parse(payload);
@@ -32,11 +47,19 @@ const createUnprocessedFile = async (client, payload) => {
32
47
  `Failed to create unprocessed file ${response.status} ${response.statusText}`
33
48
  );
34
49
  };
35
- const uploadUnprocessedFile = (client, fileId, fileStream, fileSize) => {
36
- log("Uploading unprocessed file", fileId);
50
+ const uploadUnprocessedFile = async (client, uploadDetails, path) => {
51
+ const readStream = createReadStream(path);
52
+ return uploadUnprocessedReadableStream(
53
+ client,
54
+ uploadDetails,
55
+ createReadableStreamFromReadable(readStream)
56
+ );
57
+ };
58
+ const uploadUnprocessedReadableStream = (client, uploadDetails, fileStream) => {
59
+ log("Uploading unprocessed file", uploadDetails.id);
37
60
  return uploadChunks(client, {
38
- url: `/api/v1/unprocessed_files/${fileId}/upload`,
39
- fileSize,
61
+ url: `/api/v1/unprocessed_files/${uploadDetails.id}/upload`,
62
+ fileSize: uploadDetails.byte_size,
40
63
  fileStream,
41
64
  maxSize: MAX_FILE_SIZE
42
65
  });
@@ -58,9 +81,9 @@ const lookupUnprocessedFileByMd5 = async (client, md5) => {
58
81
  `Failed to lookup unprocessed file by md5 ${md5} ${response.status} ${response.statusText}`
59
82
  );
60
83
  };
61
- const processIsobmffFile = async (client, unprocessedFileId) => {
84
+ const processIsobmffFile = async (client, id) => {
62
85
  const response = await client.authenticatedFetch(
63
- `/api/v1/unprocessed_files/${unprocessedFileId}/isobmff`,
86
+ `/api/v1/unprocessed_files/${id}/isobmff`,
64
87
  {
65
88
  method: "POST"
66
89
  }
@@ -69,13 +92,15 @@ const processIsobmffFile = async (client, unprocessedFileId) => {
69
92
  return await response.json();
70
93
  }
71
94
  throw new Error(
72
- `Failed to process isobmff file ${response.status} ${response.statusText}`
95
+ `Failed to process isobmff file ${id} ${response.status} ${response.statusText}`
73
96
  );
74
97
  };
75
98
  export {
76
99
  CreateUnprocessedFilePayload,
77
100
  createUnprocessedFile,
101
+ createUnprocessedFileFromPath,
78
102
  lookupUnprocessedFileByMd5,
79
103
  processIsobmffFile,
80
- uploadUnprocessedFile
104
+ uploadUnprocessedFile,
105
+ uploadUnprocessedReadableStream
81
106
  };
@@ -0,0 +1,82 @@
1
+ import { Stream } from "node:stream";
2
+ const createReadableStreamFromReadable = (source) => {
3
+ const pump = new StreamPump(source);
4
+ const stream = new ReadableStream(pump, pump);
5
+ return stream;
6
+ };
7
+ class StreamPump {
8
+ constructor(stream) {
9
+ this.highWaterMark = stream.readableHighWaterMark || new Stream.Readable().readableHighWaterMark;
10
+ this.accumalatedSize = 0;
11
+ this.stream = stream;
12
+ this.enqueue = this.enqueue.bind(this);
13
+ this.error = this.error.bind(this);
14
+ this.close = this.close.bind(this);
15
+ }
16
+ size(chunk) {
17
+ return chunk?.byteLength || 0;
18
+ }
19
+ start(controller) {
20
+ this.controller = controller;
21
+ this.stream.on("data", this.enqueue);
22
+ this.stream.once("error", this.error);
23
+ this.stream.once("end", this.close);
24
+ this.stream.once("close", this.close);
25
+ }
26
+ pull() {
27
+ this.resume();
28
+ }
29
+ cancel(reason) {
30
+ if (this.stream.destroy) {
31
+ this.stream.destroy(reason);
32
+ }
33
+ this.stream.off("data", this.enqueue);
34
+ this.stream.off("error", this.error);
35
+ this.stream.off("end", this.close);
36
+ this.stream.off("close", this.close);
37
+ }
38
+ enqueue(chunk) {
39
+ if (this.controller) {
40
+ try {
41
+ const bytes = chunk instanceof Uint8Array ? chunk : Buffer.from(chunk);
42
+ const available = (this.controller.desiredSize || 0) - bytes.byteLength;
43
+ this.controller.enqueue(bytes);
44
+ if (available <= 0) {
45
+ this.pause();
46
+ }
47
+ } catch (error) {
48
+ this.controller.error(
49
+ new Error(
50
+ "Could not create Buffer, chunk must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object"
51
+ )
52
+ );
53
+ this.cancel();
54
+ }
55
+ }
56
+ }
57
+ pause() {
58
+ if (this.stream.pause) {
59
+ this.stream.pause();
60
+ }
61
+ }
62
+ resume() {
63
+ if (this.stream.readable && this.stream.resume) {
64
+ this.stream.resume();
65
+ }
66
+ }
67
+ close() {
68
+ if (this.controller) {
69
+ this.controller.close();
70
+ delete this.controller;
71
+ }
72
+ }
73
+ error(error) {
74
+ if (this.controller) {
75
+ this.controller.error(error);
76
+ delete this.controller;
77
+ }
78
+ }
79
+ }
80
+ export {
81
+ createReadableStreamFromReadable
82
+ };
package/dist/index.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export { createCaptionFile, CreateCaptionFilePayload, type CreateCaptionFileResult, uploadCaptionFile, type LookupCaptionFileByMd5Result, lookupCaptionFileByMd5, } from './resources/caption-file.ts';
2
- export { createImageFile, CreateImageFilePayload, type CreateImageFileResult, uploadImageFile, type LookupImageFileByMd5Result, lookupImageFileByMd5, } from './resources/image-file.ts';
3
- export { createISOBMFFFile, CreateISOBMFFFilePayload, type CreateISOBMFFFileResult, uploadFragmentIndex, type LookupISOBMFFFileByMd5Result, lookupISOBMFFFileByMd5, type GetISOBMFFFileTranscriptionResult, getISOBMFFFileTranscription, } from './resources/isobmff-file.ts';
2
+ export { createImageFile, createImageFileFromPath, CreateImageFilePayload, type CreateImageFileResult, uploadImageFile, type LookupImageFileByMd5Result, lookupImageFileByMd5, } from './resources/image-file.ts';
3
+ export { createISOBMFFFile, CreateISOBMFFFilePayload, type CreateISOBMFFFileResult, uploadFragmentIndex, type LookupISOBMFFFileByMd5Result, lookupISOBMFFFileByMd5, type GetISOBMFFFileTranscriptionResult, getISOBMFFFileTranscription, type TranscribeISOBMFFFileResult, transcribeISOBMFFFile, TranscribeISOBMFFFilePayload, } from './resources/isobmff-file.ts';
4
4
  export { createISOBMFFTrack, CreateISOBMFFTrackPayload, type CreateISOBMFFTrackResult, uploadISOBMFFTrack, } from './resources/isobmff-track.ts';
5
5
  export { createRender, CreateRenderPayload, type CreateRenderResult, uploadRender, type LookupRenderByMd5Result, lookupRenderByMd5, } from './resources/renders.ts';
6
6
  export { createTranscription, CreateTranscriptionPayload, type CreateTranscriptionResult, getTranscriptionInfo, getTranscriptionProgress, type TranscriptionInfoResult, } from './resources/transcriptions.ts';
7
7
  export { createURLToken, type URLTokenResult, } from './resources/url-token.ts';
8
- export { createUnprocessedFile, CreateUnprocessedFilePayload, type CreateUnprocessedFileResult, uploadUnprocessedFile, type LookupUnprocessedFileByMd5Result, lookupUnprocessedFileByMd5, processIsobmffFile, type ProcessIsobmffFileResult, } from './resources/unprocessed-file.ts';
8
+ export { createUnprocessedFile, CreateUnprocessedFilePayload, type CreateUnprocessedFileResult, createUnprocessedFileFromPath, uploadUnprocessedFile, uploadUnprocessedReadableStream, type LookupUnprocessedFileByMd5Result, lookupUnprocessedFileByMd5, processIsobmffFile, type ProcessIsobmffFileResult, } from './resources/unprocessed-file.ts';
9
9
  export { getIsobmffProcessInfo, getIsobmffProcessProgress, type IsobmffProcessInfoResult, } from './resources/process-isobmff.ts';
10
10
  export { Client } from './client.ts';
@@ -11,27 +11,33 @@ export declare const CreateImageFilePayload: z.ZodObject<{
11
11
  md5: string;
12
12
  filename: string;
13
13
  byte_size: number;
14
- height: number;
15
14
  width: number;
15
+ height: number;
16
16
  mime_type: "image/jpeg" | "image/png" | "image/jpg" | "image/webp";
17
17
  }, {
18
18
  md5: string;
19
19
  filename: string;
20
20
  byte_size: number;
21
- height: number;
22
21
  width: number;
22
+ height: number;
23
23
  mime_type: "image/jpeg" | "image/png" | "image/jpg" | "image/webp";
24
24
  }>;
25
25
  export interface CreateImageFileResult {
26
26
  complete: boolean | null;
27
+ byte_size: number;
27
28
  id: string;
28
29
  md5: string;
29
30
  }
30
31
  export interface LookupImageFileByMd5Result {
31
32
  complete: boolean | null;
33
+ byte_size: number;
32
34
  id: string;
33
35
  md5: string;
34
36
  }
37
+ export declare const createImageFileFromPath: (client: Client, path: string) => Promise<CreateImageFileResult>;
35
38
  export declare const createImageFile: (client: Client, payload: z.infer<typeof CreateImageFilePayload>) => Promise<CreateImageFileResult>;
36
- export declare const uploadImageFile: (client: Client, fileId: string, fileStream: ReadableStream, fileSize: number) => import('../uploadChunks.ts').IteratorWithPromise<import('../uploadChunks.ts').UploadChunkEvent>;
39
+ export declare const uploadImageFile: (client: Client, uploadDetails: {
40
+ id: string;
41
+ byte_size: number;
42
+ }, fileStream: ReadableStream) => import('../uploadChunks.ts').IteratorWithPromise<import('../uploadChunks.ts').UploadChunkEvent>;
37
43
  export declare const lookupImageFileByMd5: (client: Client, md5: string) => Promise<LookupImageFileByMd5Result | null>;
@@ -33,3 +33,16 @@ export declare const createISOBMFFFile: (client: Client, payload: z.infer<typeof
33
33
  export declare const uploadFragmentIndex: (client: Client, fileId: string, fileStream: ReadableStream, fileSize: number) => Promise<any>;
34
34
  export declare const lookupISOBMFFFileByMd5: (client: Client, md5: string) => Promise<LookupISOBMFFFileByMd5Result | null>;
35
35
  export declare const getISOBMFFFileTranscription: (client: Client, id: string) => Promise<GetISOBMFFFileTranscriptionResult | null>;
36
+ export declare const TranscribeISOBMFFFilePayload: z.ZodObject<{
37
+ trackId: z.ZodOptional<z.ZodString>;
38
+ }, "strip", z.ZodTypeAny, {
39
+ trackId?: string | undefined;
40
+ }, {
41
+ trackId?: string | undefined;
42
+ }>;
43
+ export interface TranscribeISOBMFFFileResult {
44
+ id: string;
45
+ file_id: string;
46
+ track_id: number;
47
+ }
48
+ export declare const transcribeISOBMFFFile: (client: Client, id: string, payload?: z.infer<typeof TranscribeISOBMFFFilePayload>) => Promise<TranscribeISOBMFFFileResult>;
@@ -159,8 +159,6 @@ export declare const CreateISOBMFFTrackPayload: z.ZodDiscriminatedUnion<"type",
159
159
  bit_rate: z.ZodOptional<z.ZodString>;
160
160
  disposition: z.ZodRecord<z.ZodString, z.ZodUnknown>;
161
161
  }, "strip", z.ZodTypeAny, {
162
- height: number;
163
- width: number;
164
162
  index: number;
165
163
  codec_name: string;
166
164
  codec_long_name: string;
@@ -171,6 +169,8 @@ export declare const CreateISOBMFFTrackPayload: z.ZodDiscriminatedUnion<"type",
171
169
  avg_frame_rate: string;
172
170
  time_base: string;
173
171
  disposition: Record<string, unknown>;
172
+ width: number;
173
+ height: number;
174
174
  coded_width: number;
175
175
  coded_height: number;
176
176
  start_pts?: number | undefined;
@@ -179,8 +179,6 @@ export declare const CreateISOBMFFTrackPayload: z.ZodDiscriminatedUnion<"type",
179
179
  duration?: number | undefined;
180
180
  bit_rate?: string | undefined;
181
181
  }, {
182
- height: number;
183
- width: number;
184
182
  index: number;
185
183
  codec_name: string;
186
184
  codec_long_name: string;
@@ -191,6 +189,8 @@ export declare const CreateISOBMFFTrackPayload: z.ZodDiscriminatedUnion<"type",
191
189
  avg_frame_rate: string;
192
190
  time_base: string;
193
191
  disposition: Record<string, unknown>;
192
+ width: number;
193
+ height: number;
194
194
  coded_width: number;
195
195
  coded_height: number;
196
196
  start_pts?: number | undefined;
@@ -209,8 +209,6 @@ export declare const CreateISOBMFFTrackPayload: z.ZodDiscriminatedUnion<"type",
209
209
  file_id: string;
210
210
  track_id: number;
211
211
  probe_info: {
212
- height: number;
213
- width: number;
214
212
  index: number;
215
213
  codec_name: string;
216
214
  codec_long_name: string;
@@ -221,6 +219,8 @@ export declare const CreateISOBMFFTrackPayload: z.ZodDiscriminatedUnion<"type",
221
219
  avg_frame_rate: string;
222
220
  time_base: string;
223
221
  disposition: Record<string, unknown>;
222
+ width: number;
223
+ height: number;
224
224
  coded_width: number;
225
225
  coded_height: number;
226
226
  start_pts?: number | undefined;
@@ -237,8 +237,6 @@ export declare const CreateISOBMFFTrackPayload: z.ZodDiscriminatedUnion<"type",
237
237
  file_id: string;
238
238
  track_id: number;
239
239
  probe_info: {
240
- height: number;
241
- width: number;
242
240
  index: number;
243
241
  codec_name: string;
244
242
  codec_long_name: string;
@@ -249,6 +247,8 @@ export declare const CreateISOBMFFTrackPayload: z.ZodDiscriminatedUnion<"type",
249
247
  avg_frame_rate: string;
250
248
  time_base: string;
251
249
  disposition: Record<string, unknown>;
250
+ width: number;
251
+ height: number;
252
252
  coded_width: number;
253
253
  coded_height: number;
254
254
  start_pts?: number | undefined;
@@ -10,20 +10,20 @@ export declare const CreateRenderPayload: z.ZodObject<{
10
10
  strategy: z.ZodEnum<["v1", "v2"]>;
11
11
  }, "strip", z.ZodTypeAny, {
12
12
  md5: string;
13
- height: number;
14
13
  width: number;
14
+ height: number;
15
+ strategy: "v1" | "v2";
15
16
  duration_ms: number;
16
17
  fps: number;
17
18
  work_slice_ms: number;
18
- strategy: "v1" | "v2";
19
19
  }, {
20
20
  md5: string;
21
- height: number;
22
21
  width: number;
22
+ height: number;
23
+ strategy: "v1" | "v2";
23
24
  duration_ms: number;
24
25
  fps: number;
25
26
  work_slice_ms: number;
26
- strategy: "v1" | "v2";
27
27
  }>;
28
28
  export interface CreateRenderResult {
29
29
  id: string;
@@ -21,6 +21,7 @@ interface UnprocessedFile {
21
21
  id: string;
22
22
  md5: string;
23
23
  }
24
+ type UnprocessedFileUploadDetails = Pick<UnprocessedFile, "id" | "byte_size">;
24
25
  export interface CreateUnprocessedFileResult extends UnprocessedFile {
25
26
  }
26
27
  export interface LookupUnprocessedFileByMd5Result extends UnprocessedFile {
@@ -30,8 +31,10 @@ export interface UpdateUnprocessedFileResult extends UnprocessedFile {
30
31
  export interface ProcessIsobmffFileResult {
31
32
  id: string;
32
33
  }
34
+ export declare const createUnprocessedFileFromPath: (client: Client, path: string) => Promise<CreateUnprocessedFileResult>;
33
35
  export declare const createUnprocessedFile: (client: Client, payload: z.infer<typeof CreateUnprocessedFilePayload>) => Promise<CreateUnprocessedFileResult>;
34
- export declare const uploadUnprocessedFile: (client: Client, fileId: string, fileStream: ReadableStream, fileSize: number) => import('../uploadChunks.ts').IteratorWithPromise<import('../uploadChunks.ts').UploadChunkEvent>;
36
+ export declare const uploadUnprocessedFile: (client: Client, uploadDetails: UnprocessedFileUploadDetails, path: string) => Promise<import('../uploadChunks.ts').IteratorWithPromise<import('../uploadChunks.ts').UploadChunkEvent>>;
37
+ export declare const uploadUnprocessedReadableStream: (client: Client, uploadDetails: UnprocessedFileUploadDetails, fileStream: ReadableStream) => import('../uploadChunks.ts').IteratorWithPromise<import('../uploadChunks.ts').UploadChunkEvent>;
35
38
  export declare const lookupUnprocessedFileByMd5: (client: Client, md5: string) => Promise<LookupUnprocessedFileByMd5Result | null>;
36
- export declare const processIsobmffFile: (client: Client, unprocessedFileId: LookupUnprocessedFileByMd5Result["id"]) => Promise<ProcessIsobmffFileResult>;
39
+ export declare const processIsobmffFile: (client: Client, id: string) => Promise<ProcessIsobmffFileResult>;
37
40
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@editframe/api",
3
- "version": "0.12.0-beta.3",
3
+ "version": "0.12.0-beta.6",
4
4
  "description": "API functions for EditFrame",
5
5
  "exports": {
6
6
  ".": {
@@ -29,7 +29,7 @@
29
29
  "vite-tsconfig-paths": "^4.3.2"
30
30
  },
31
31
  "dependencies": {
32
- "@editframe/assets": "0.12.0-beta.3",
32
+ "@editframe/assets": "0.12.0-beta.6",
33
33
  "debug": "^4.3.5",
34
34
  "jsonwebtoken": "^9.0.2",
35
35
  "node-fetch": "^3.3.2",
@@ -97,9 +97,8 @@ describe("ImageFile", () => {
97
97
  await expect(
98
98
  uploadImageFile(
99
99
  client,
100
- "test-file-id",
100
+ { id: "test-file-id", byte_size: 1024 * 1024 * 17 },
101
101
  webReadableFromBuffers(Buffer.from("test")),
102
- 1024 * 1024 * 17,
103
102
  ).whenUploaded(),
104
103
  ).rejects.toThrowError(
105
104
  "File size 17825792 bytes exceeds limit 16777216 bytes",
@@ -118,9 +117,8 @@ describe("ImageFile", () => {
118
117
  await expect(
119
118
  uploadImageFile(
120
119
  client,
121
- "test-file-id",
120
+ { id: "test-file-id", byte_size: 4 },
122
121
  webReadableFromBuffers(Buffer.from("test")),
123
- 4,
124
122
  ).whenUploaded(),
125
123
  ).rejects.toThrowError(
126
124
  "Failed to upload chunk 0 for /api/v1/image_files/test-file-id/upload 500 Internal Server Error",
@@ -139,9 +137,8 @@ describe("ImageFile", () => {
139
137
  await expect(
140
138
  uploadImageFile(
141
139
  client,
142
- "test-file-id",
140
+ { id: "test-file-id", byte_size: 4 },
143
141
  webReadableFromBuffers(Buffer.from("test")),
144
- 4,
145
142
  ).whenUploaded(),
146
143
  ).resolves.toEqual([
147
144
  { type: "progress", progress: 0 },
@@ -1,6 +1,10 @@
1
1
  import debug from "debug";
2
+ import mime from "mime";
2
3
  import { z } from "zod";
3
4
 
5
+ import { stat } from "node:fs/promises";
6
+ import { basename } from "node:path";
7
+ import { md5FilePath } from "@editframe/assets";
4
8
  import type { Client } from "../client.ts";
5
9
  import { uploadChunks } from "../uploadChunks.ts";
6
10
 
@@ -19,16 +23,39 @@ export const CreateImageFilePayload = z.object({
19
23
 
20
24
  export interface CreateImageFileResult {
21
25
  complete: boolean | null;
26
+ byte_size: number;
22
27
  id: string;
23
28
  md5: string;
24
29
  }
25
30
 
26
31
  export interface LookupImageFileByMd5Result {
27
32
  complete: boolean | null;
33
+ byte_size: number;
28
34
  id: string;
29
35
  md5: string;
30
36
  }
31
37
 
38
+ export const createImageFileFromPath = async (client: Client, path: string) => {
39
+ const fileInfo = await stat(path);
40
+
41
+ const byte_size = fileInfo.size;
42
+
43
+ const md5 = await md5FilePath(path);
44
+
45
+ const mime_type = mime.getType(path);
46
+
47
+ return createImageFile(client, {
48
+ ...CreateImageFilePayload.parse({
49
+ md5,
50
+ height: 0,
51
+ width: 0,
52
+ mime_type,
53
+ filename: basename(path),
54
+ byte_size,
55
+ }),
56
+ });
57
+ };
58
+
32
59
  export const createImageFile = async (
33
60
  client: Client,
34
61
  payload: z.infer<typeof CreateImageFilePayload>,
@@ -53,15 +80,17 @@ export const createImageFile = async (
53
80
 
54
81
  export const uploadImageFile = (
55
82
  client: Client,
56
- fileId: string,
83
+ uploadDetails: {
84
+ id: string;
85
+ byte_size: number;
86
+ },
57
87
  fileStream: ReadableStream,
58
- fileSize: number,
59
88
  ) => {
60
- log("Uploading image file", fileId);
89
+ log("Uploading image file", uploadDetails.id);
61
90
 
62
91
  return uploadChunks(client, {
63
- url: `/api/v1/image_files/${fileId}/upload`,
64
- fileSize,
92
+ url: `/api/v1/image_files/${uploadDetails.id}/upload`,
93
+ fileSize: uploadDetails.byte_size,
65
94
  fileStream,
66
95
  maxSize: MAX_IMAGE_SIZE,
67
96
  });
@@ -128,3 +128,35 @@ export const getISOBMFFFileTranscription = async (
128
128
  `Failed to get isobmff file transcription ${id} ${response.status} ${response.statusText}`,
129
129
  );
130
130
  };
131
+
132
+ export const TranscribeISOBMFFFilePayload = z.object({
133
+ trackId: z.string().optional(),
134
+ });
135
+
136
+ export interface TranscribeISOBMFFFileResult {
137
+ id: string;
138
+ file_id: string;
139
+ track_id: number;
140
+ }
141
+
142
+ export const transcribeISOBMFFFile = async (
143
+ client: Client,
144
+ id: string,
145
+ payload: z.infer<typeof TranscribeISOBMFFFilePayload> = {},
146
+ ) => {
147
+ const response = await client.authenticatedFetch(
148
+ `/api/v1/isobmff_files/${id}/transcribe`,
149
+ {
150
+ method: "POST",
151
+ body: JSON.stringify(payload),
152
+ },
153
+ );
154
+
155
+ if (response.ok) {
156
+ return (await response.json()) as TranscribeISOBMFFFileResult;
157
+ }
158
+
159
+ throw new Error(
160
+ `Failed to transcribe isobmff file ${id} ${response.status} ${response.statusText}`,
161
+ );
162
+ };
@@ -8,7 +8,7 @@ import { webReadableFromBuffers } from "../readableFromBuffers.ts";
8
8
  import {
9
9
  createUnprocessedFile,
10
10
  lookupUnprocessedFileByMd5,
11
- uploadUnprocessedFile,
11
+ uploadUnprocessedReadableStream,
12
12
  } from "./unprocessed-file.ts";
13
13
 
14
14
  const server = setupServer();
@@ -96,11 +96,10 @@ describe("Unprocessed File", () => {
96
96
  );
97
97
 
98
98
  await expect(
99
- uploadUnprocessedFile(
99
+ uploadUnprocessedReadableStream(
100
100
  client,
101
- "test-file",
101
+ { id: "test-file", byte_size: 4 },
102
102
  webReadableFromBuffers(Buffer.from("test")),
103
- 4,
104
103
  ).whenUploaded(),
105
104
  ).rejects.toThrowError(
106
105
  "Failed to upload chunk 0 for /api/v1/unprocessed_files/test-file/upload 500 Internal Server Error",
@@ -117,11 +116,10 @@ describe("Unprocessed File", () => {
117
116
  );
118
117
 
119
118
  await expect(
120
- uploadUnprocessedFile(
119
+ uploadUnprocessedReadableStream(
121
120
  client,
122
- "test-file",
121
+ { id: "test-file", byte_size: 4 },
123
122
  webReadableFromBuffers(Buffer.from("test")),
124
- 4,
125
123
  ).whenUploaded(),
126
124
  ).resolves.toEqual([
127
125
  { type: "progress", progress: 0 },
@@ -1,6 +1,11 @@
1
+ import { stat } from "node:fs/promises";
1
2
  import debug from "debug";
2
3
  import { z } from "zod";
3
4
 
5
+ import { createReadStream } from "node:fs";
6
+ import { basename } from "node:path";
7
+ import { md5FilePath } from "@editframe/assets";
8
+ import { createReadableStreamFromReadable } from "packages/cli/src/utils/createReadableStreamFromReadable.ts";
4
9
  import type { Client } from "../client.ts";
5
10
  import { uploadChunks } from "../uploadChunks.ts";
6
11
 
@@ -24,6 +29,8 @@ interface UnprocessedFile {
24
29
  md5: string;
25
30
  }
26
31
 
32
+ type UnprocessedFileUploadDetails = Pick<UnprocessedFile, "id" | "byte_size">;
33
+
27
34
  export interface CreateUnprocessedFileResult extends UnprocessedFile {}
28
35
 
29
36
  export interface LookupUnprocessedFileByMd5Result extends UnprocessedFile {}
@@ -34,6 +41,23 @@ export interface ProcessIsobmffFileResult {
34
41
  id: string;
35
42
  }
36
43
 
44
+ export const createUnprocessedFileFromPath = async (
45
+ client: Client,
46
+ path: string,
47
+ ) => {
48
+ const fileInfo = await stat(path);
49
+
50
+ const byte_size = fileInfo.size;
51
+
52
+ const md5 = await md5FilePath(path);
53
+
54
+ return createUnprocessedFile(client, {
55
+ md5,
56
+ filename: basename(path),
57
+ byte_size,
58
+ });
59
+ };
60
+
37
61
  export const createUnprocessedFile = async (
38
62
  client: Client,
39
63
  payload: z.infer<typeof CreateUnprocessedFilePayload>,
@@ -64,17 +88,30 @@ export const createUnprocessedFile = async (
64
88
  );
65
89
  };
66
90
 
67
- export const uploadUnprocessedFile = (
91
+ export const uploadUnprocessedFile = async (
68
92
  client: Client,
69
- fileId: string,
93
+ uploadDetails: UnprocessedFileUploadDetails,
94
+ path: string,
95
+ ) => {
96
+ const readStream = createReadStream(path);
97
+
98
+ return uploadUnprocessedReadableStream(
99
+ client,
100
+ uploadDetails,
101
+ createReadableStreamFromReadable(readStream),
102
+ );
103
+ };
104
+
105
+ export const uploadUnprocessedReadableStream = (
106
+ client: Client,
107
+ uploadDetails: UnprocessedFileUploadDetails,
70
108
  fileStream: ReadableStream,
71
- fileSize: number,
72
109
  ) => {
73
- log("Uploading unprocessed file", fileId);
110
+ log("Uploading unprocessed file", uploadDetails.id);
74
111
 
75
112
  return uploadChunks(client, {
76
- url: `/api/v1/unprocessed_files/${fileId}/upload`,
77
- fileSize,
113
+ url: `/api/v1/unprocessed_files/${uploadDetails.id}/upload`,
114
+ fileSize: uploadDetails.byte_size,
78
115
  fileStream,
79
116
  maxSize: MAX_FILE_SIZE,
80
117
  });
@@ -104,12 +141,9 @@ export const lookupUnprocessedFileByMd5 = async (
104
141
  );
105
142
  };
106
143
 
107
- export const processIsobmffFile = async (
108
- client: Client,
109
- unprocessedFileId: LookupUnprocessedFileByMd5Result["id"],
110
- ) => {
144
+ export const processIsobmffFile = async (client: Client, id: string) => {
111
145
  const response = await client.authenticatedFetch(
112
- `/api/v1/unprocessed_files/${unprocessedFileId}/isobmff`,
146
+ `/api/v1/unprocessed_files/${id}/isobmff`,
113
147
  {
114
148
  method: "POST",
115
149
  },
@@ -120,6 +154,6 @@ export const processIsobmffFile = async (
120
154
  }
121
155
 
122
156
  throw new Error(
123
- `Failed to process isobmff file ${response.status} ${response.statusText}`,
157
+ `Failed to process isobmff file ${id} ${response.status} ${response.statusText}`,
124
158
  );
125
159
  };
File without changes