@editframe/api 0.8.0-beta.9 → 0.9.0-beta.3
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/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/resources/caption-file.d.ts +1 -0
- package/dist/resources/image-file.d.ts +1 -0
- package/dist/resources/isobmff-file.d.ts +1 -0
- package/dist/resources/unprocessed-file.d.ts +11 -7
- package/dist/resources/unprocessed-file.js +61 -46
- package/package.json +2 -2
- package/src/resources/caption-file.ts +1 -0
- package/src/resources/image-file.ts +1 -0
- package/src/resources/isobmff-file.ts +1 -0
- package/src/resources/unprocessed-file.test.ts +144 -0
- package/src/resources/unprocessed-file.ts +81 -69
package/dist/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ export { createISOBMFFFile, CreateISOBMFFFilePayload, type CreateISOBMFFFileResu
|
|
|
4
4
|
export { createISOBMFFTrack, CreateISOBMFFTrackPayload, type CreateISOBMFFTrackResult, uploadISOBMFFTrack, } from './resources/isobmff-track.ts';
|
|
5
5
|
export { createRender, CreateRenderPayload, type CreateRenderResult, uploadRender, } from './resources/renders.ts';
|
|
6
6
|
export { createURLToken, type URLTokenResult, } from './resources/url-token.ts';
|
|
7
|
-
export { createUnprocessedFile, CreateUnprocessedFilePayload, type CreateUnprocessedFileResult, updateUnprocessedFile, UpdateUnprocessedFilePayload, type UpdateUnprocessedFileResult, uploadUnprocessedFile, processAVFile, processAVFileBuffer, } from './resources/unprocessed-file.ts';
|
|
7
|
+
export { createUnprocessedFile, CreateUnprocessedFilePayload, type CreateUnprocessedFileResult, updateUnprocessedFile, UpdateUnprocessedFilePayload, type UpdateUnprocessedFileResult, uploadUnprocessedFile, processAVFile, processAVFileBuffer, processImageFile, processImageFileBuffer, } from './resources/unprocessed-file.ts';
|
|
8
8
|
export { Client } from './client.ts';
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { CreateISOBMFFFilePayload, createISOBMFFFile, uploadFragmentIndex } from
|
|
|
4
4
|
import { CreateISOBMFFTrackPayload, createISOBMFFTrack, uploadISOBMFFTrack } from "./resources/isobmff-track.js";
|
|
5
5
|
import { CreateRenderPayload, createRender, uploadRender } from "./resources/renders.js";
|
|
6
6
|
import { createURLToken } from "./resources/url-token.js";
|
|
7
|
-
import { CreateUnprocessedFilePayload, UpdateUnprocessedFilePayload, createUnprocessedFile, processAVFile, processAVFileBuffer, updateUnprocessedFile, uploadUnprocessedFile } from "./resources/unprocessed-file.js";
|
|
7
|
+
import { CreateUnprocessedFilePayload, UpdateUnprocessedFilePayload, createUnprocessedFile, processAVFile, processAVFileBuffer, processImageFile, processImageFileBuffer, updateUnprocessedFile, uploadUnprocessedFile } from "./resources/unprocessed-file.js";
|
|
8
8
|
import { Client } from "./client.js";
|
|
9
9
|
export {
|
|
10
10
|
Client,
|
|
@@ -24,6 +24,8 @@ export {
|
|
|
24
24
|
createUnprocessedFile,
|
|
25
25
|
processAVFile,
|
|
26
26
|
processAVFileBuffer,
|
|
27
|
+
processImageFile,
|
|
28
|
+
processImageFileBuffer,
|
|
27
29
|
updateUnprocessedFile,
|
|
28
30
|
uploadCaptionFile,
|
|
29
31
|
uploadFragmentIndex,
|
|
@@ -26,6 +26,7 @@ export declare const CreateImageFilePayload: z.ZodObject<{
|
|
|
26
26
|
export interface CreateImageFileResult {
|
|
27
27
|
complete: boolean | null;
|
|
28
28
|
id: string;
|
|
29
|
+
asset_id: string;
|
|
29
30
|
}
|
|
30
31
|
export declare const createImageFile: (client: Client, payload: z.infer<typeof CreateImageFilePayload>) => Promise<CreateImageFileResult>;
|
|
31
32
|
export declare const uploadImageFile: (client: Client, fileId: string, fileStream: Readable, fileSize: number) => Promise<void>;
|
|
@@ -14,6 +14,7 @@ export declare const CreateISOBMFFFilePayload: z.ZodObject<{
|
|
|
14
14
|
export interface CreateISOBMFFFileResult {
|
|
15
15
|
fragment_index_complete: boolean;
|
|
16
16
|
id: string;
|
|
17
|
+
asset_id: string;
|
|
17
18
|
}
|
|
18
19
|
export declare const createISOBMFFFile: (client: Client, payload: z.infer<typeof CreateISOBMFFFilePayload>) => Promise<CreateISOBMFFFileResult>;
|
|
19
20
|
export declare const uploadFragmentIndex: (client: Client, fileId: string, fileStream: Readable, fileSize: number) => Promise<unknown>;
|
|
@@ -1,45 +1,49 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { Client } from '../client.ts';
|
|
4
|
-
declare const FileProcessors: z.ZodEffects<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"isobmff">, z.ZodLiteral<"captions">]>, "many">, ("captions" | "isobmff")[], ("captions" | "isobmff")[]>;
|
|
4
|
+
declare const FileProcessors: z.ZodEffects<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"isobmff">, z.ZodLiteral<"image">, z.ZodLiteral<"captions">]>, "many">, ("captions" | "image" | "isobmff")[], ("captions" | "image" | "isobmff")[]>;
|
|
5
5
|
export declare const CreateUnprocessedFilePayload: z.ZodObject<{
|
|
6
6
|
id: z.ZodString;
|
|
7
7
|
filename: z.ZodString;
|
|
8
|
-
processes: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"isobmff">, z.ZodLiteral<"captions">]>, "many">, ("captions" | "isobmff")[], ("captions" | "isobmff")[]>>;
|
|
8
|
+
processes: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"isobmff">, z.ZodLiteral<"image">, z.ZodLiteral<"captions">]>, "many">, ("captions" | "image" | "isobmff")[], ("captions" | "image" | "isobmff")[]>>;
|
|
9
9
|
byte_size: z.ZodNumber;
|
|
10
10
|
}, "strip", z.ZodTypeAny, {
|
|
11
11
|
id: string;
|
|
12
12
|
filename: string;
|
|
13
13
|
byte_size: number;
|
|
14
|
-
processes?: ("captions" | "isobmff")[] | undefined;
|
|
14
|
+
processes?: ("captions" | "image" | "isobmff")[] | undefined;
|
|
15
15
|
}, {
|
|
16
16
|
id: string;
|
|
17
17
|
filename: string;
|
|
18
18
|
byte_size: number;
|
|
19
|
-
processes?: ("captions" | "isobmff")[] | undefined;
|
|
19
|
+
processes?: ("captions" | "image" | "isobmff")[] | undefined;
|
|
20
20
|
}>;
|
|
21
21
|
export declare const UpdateUnprocessedFilePayload: z.ZodObject<{
|
|
22
|
-
processes: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"isobmff">, z.ZodLiteral<"captions">]>, "many">, ("captions" | "isobmff")[], ("captions" | "isobmff")[]>>;
|
|
22
|
+
processes: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodUnion<[z.ZodLiteral<"isobmff">, z.ZodLiteral<"image">, z.ZodLiteral<"captions">]>, "many">, ("captions" | "image" | "isobmff")[], ("captions" | "image" | "isobmff")[]>>;
|
|
23
23
|
}, "strip", z.ZodTypeAny, {
|
|
24
|
-
processes?: ("captions" | "isobmff")[] | undefined;
|
|
24
|
+
processes?: ("captions" | "image" | "isobmff")[] | undefined;
|
|
25
25
|
}, {
|
|
26
|
-
processes?: ("captions" | "isobmff")[] | undefined;
|
|
26
|
+
processes?: ("captions" | "image" | "isobmff")[] | undefined;
|
|
27
27
|
}>;
|
|
28
28
|
export interface CreateUnprocessedFileResult {
|
|
29
29
|
byte_size: number;
|
|
30
30
|
next_byte: number;
|
|
31
31
|
id: string;
|
|
32
32
|
processes: z.infer<typeof FileProcessors>;
|
|
33
|
+
asset_id: string;
|
|
33
34
|
}
|
|
34
35
|
export interface UpdateUnprocessedFileResult {
|
|
35
36
|
byte_size?: number;
|
|
36
37
|
next_byte: number;
|
|
37
38
|
id: string;
|
|
38
39
|
processes: z.infer<typeof FileProcessors>;
|
|
40
|
+
asset_id: string;
|
|
39
41
|
}
|
|
40
42
|
export declare const createUnprocessedFile: (client: Client, payload: z.infer<typeof CreateUnprocessedFilePayload>) => Promise<CreateUnprocessedFileResult>;
|
|
41
43
|
export declare const updateUnprocessedFile: (client: Client, fileId: string, payload: Partial<z.infer<typeof UpdateUnprocessedFilePayload>>) => Promise<UpdateUnprocessedFileResult>;
|
|
42
44
|
export declare const uploadUnprocessedFile: (client: Client, fileId: string, fileStream: Readable, fileSize: number) => Promise<void>;
|
|
43
45
|
export declare const processAVFileBuffer: (client: Client, buffer: Buffer, filename?: string) => Promise<UpdateUnprocessedFileResult>;
|
|
44
46
|
export declare const processAVFile: (client: Client, filePath: string) => Promise<UpdateUnprocessedFileResult>;
|
|
47
|
+
export declare const processImageFileBuffer: (client: Client, buffer: Buffer, filename?: string) => Promise<UpdateUnprocessedFileResult>;
|
|
48
|
+
export declare const processImageFile: (client: Client, filePath: string) => Promise<UpdateUnprocessedFileResult>;
|
|
45
49
|
export {};
|
|
@@ -7,7 +7,12 @@ import debug from "debug";
|
|
|
7
7
|
import { md5Buffer, md5FilePath } from "@editframe/assets";
|
|
8
8
|
import { uploadChunks } from "../uploadChunks.js";
|
|
9
9
|
const log = debug("ef:api:unprocessed-file");
|
|
10
|
-
const
|
|
10
|
+
const FileProcessor = z.union([
|
|
11
|
+
z.literal("isobmff"),
|
|
12
|
+
z.literal("image"),
|
|
13
|
+
z.literal("captions")
|
|
14
|
+
]);
|
|
15
|
+
const FileProcessors = z.array(FileProcessor).refine(
|
|
11
16
|
(value) => {
|
|
12
17
|
return new Set(value).size === value.length;
|
|
13
18
|
},
|
|
@@ -75,59 +80,69 @@ const uploadUnprocessedFile = async (client, fileId, fileStream, fileSize) => {
|
|
|
75
80
|
});
|
|
76
81
|
log("Unprocessed file upload complete");
|
|
77
82
|
};
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
83
|
+
const buildBufferProcessor = (processor) => {
|
|
84
|
+
return async (client, buffer, filename = "buffer") => {
|
|
85
|
+
log(`Processing file buffer: ${processor}`, filename);
|
|
86
|
+
const fileId = md5Buffer(buffer);
|
|
87
|
+
log("File ID", fileId);
|
|
88
|
+
log(`File size: ${buffer.byteLength} bytes`);
|
|
89
|
+
await createUnprocessedFile(client, {
|
|
90
|
+
id: fileId,
|
|
91
|
+
processes: [],
|
|
92
|
+
filename,
|
|
93
|
+
byte_size: buffer.byteLength
|
|
94
|
+
});
|
|
95
|
+
const readStream = new Readable({
|
|
96
|
+
read() {
|
|
97
|
+
readStream.push(buffer);
|
|
98
|
+
readStream.push(null);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
await uploadUnprocessedFile(client, fileId, readStream, buffer.byteLength);
|
|
102
|
+
const fileInformation = await updateUnprocessedFile(client, fileId, {
|
|
103
|
+
processes: [processor]
|
|
104
|
+
});
|
|
105
|
+
log("File processed", fileInformation);
|
|
106
|
+
return fileInformation;
|
|
107
|
+
};
|
|
101
108
|
};
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
109
|
+
const buildFileProcessor = (processor) => {
|
|
110
|
+
return async (client, filePath) => {
|
|
111
|
+
log(`Processing file ${processor}`, filePath);
|
|
112
|
+
const fileId = await md5FilePath(filePath);
|
|
113
|
+
log("File ID", fileId);
|
|
114
|
+
await createUnprocessedFile(client, {
|
|
115
|
+
id: fileId,
|
|
116
|
+
processes: [],
|
|
117
|
+
filename: basename(filePath),
|
|
118
|
+
byte_size: (await stat(filePath)).size
|
|
119
|
+
});
|
|
120
|
+
const readStream = createReadStream(filePath);
|
|
121
|
+
await uploadUnprocessedFile(
|
|
122
|
+
client,
|
|
123
|
+
fileId,
|
|
124
|
+
readStream,
|
|
125
|
+
(await stat(filePath)).size
|
|
126
|
+
);
|
|
127
|
+
const fileInformation = await updateUnprocessedFile(client, fileId, {
|
|
128
|
+
processes: [processor]
|
|
129
|
+
});
|
|
130
|
+
log("File processed", fileInformation);
|
|
131
|
+
return fileInformation;
|
|
132
|
+
};
|
|
124
133
|
};
|
|
134
|
+
const processAVFileBuffer = buildBufferProcessor("isobmff");
|
|
135
|
+
const processAVFile = buildFileProcessor("isobmff");
|
|
136
|
+
const processImageFileBuffer = buildBufferProcessor("image");
|
|
137
|
+
const processImageFile = buildFileProcessor("image");
|
|
125
138
|
export {
|
|
126
139
|
CreateUnprocessedFilePayload,
|
|
127
140
|
UpdateUnprocessedFilePayload,
|
|
128
141
|
createUnprocessedFile,
|
|
129
142
|
processAVFile,
|
|
130
143
|
processAVFileBuffer,
|
|
144
|
+
processImageFile,
|
|
145
|
+
processImageFileBuffer,
|
|
131
146
|
updateUnprocessedFile,
|
|
132
147
|
uploadUnprocessedFile
|
|
133
148
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editframe/api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0-beta.3",
|
|
4
4
|
"description": "API functions for EditFrame",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"vite-tsconfig-paths": "^4.3.2"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@editframe/assets": "0.
|
|
31
|
+
"@editframe/assets": "0.9.0-beta.3",
|
|
32
32
|
"debug": "^4.3.5",
|
|
33
33
|
"jsonwebtoken": "^9.0.2",
|
|
34
34
|
"node-fetch": "^3.3.2",
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
createUnprocessedFile,
|
|
11
11
|
processAVFile,
|
|
12
12
|
processAVFileBuffer,
|
|
13
|
+
processImageFile,
|
|
14
|
+
processImageFileBuffer,
|
|
13
15
|
updateUnprocessedFile,
|
|
14
16
|
uploadUnprocessedFile,
|
|
15
17
|
} from "./unprocessed-file.ts";
|
|
@@ -309,4 +311,146 @@ describe("Unprocessed File", () => {
|
|
|
309
311
|
});
|
|
310
312
|
});
|
|
311
313
|
});
|
|
314
|
+
|
|
315
|
+
describe("processImageFileBuffer", () => {
|
|
316
|
+
test("Throws when server responds with an error when creating file", async () => {
|
|
317
|
+
server.use(
|
|
318
|
+
http.post("http://localhost/api/v1/unprocessed_files", () =>
|
|
319
|
+
HttpResponse.text("Internal Server Error", { status: 500 }),
|
|
320
|
+
),
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
await expect(
|
|
324
|
+
processImageFileBuffer(client, Buffer.from("test"), "test-file"),
|
|
325
|
+
).rejects.toThrowError(
|
|
326
|
+
"Failed to create unprocessed file 500 Internal Server Error",
|
|
327
|
+
);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test("Throws when server responds with an error when uploading file", async () => {
|
|
331
|
+
server.use(
|
|
332
|
+
http.post("http://localhost/api/v1/unprocessed_files", () =>
|
|
333
|
+
HttpResponse.json({}, { status: 200 }),
|
|
334
|
+
),
|
|
335
|
+
http.post(
|
|
336
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6/upload",
|
|
337
|
+
() => HttpResponse.text("Internal Server Error", { status: 500 }),
|
|
338
|
+
),
|
|
339
|
+
);
|
|
340
|
+
|
|
341
|
+
await expect(
|
|
342
|
+
processImageFileBuffer(client, Buffer.from("test"), "test-file"),
|
|
343
|
+
).rejects.toThrowError(
|
|
344
|
+
"Failed to upload chunk 0 for /api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6/upload 500 Internal Server Error",
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test("Throws when server responds with an error when updating file", async () => {
|
|
349
|
+
server.use(
|
|
350
|
+
http.post("http://localhost/api/v1/unprocessed_files", () =>
|
|
351
|
+
HttpResponse.json({}, { status: 200 }),
|
|
352
|
+
),
|
|
353
|
+
http.post(
|
|
354
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6/upload",
|
|
355
|
+
() => HttpResponse.json({ test }, { status: 201 }),
|
|
356
|
+
),
|
|
357
|
+
http.post(
|
|
358
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6",
|
|
359
|
+
() => HttpResponse.text("Internal Server Error", { status: 500 }),
|
|
360
|
+
),
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
await expect(
|
|
364
|
+
processImageFileBuffer(client, Buffer.from("test"), "test-file"),
|
|
365
|
+
).rejects.toThrowError(
|
|
366
|
+
"Failed to update unprocessed file 500 Internal Server Error",
|
|
367
|
+
);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test("Returns json data when upload is successful", async () => {
|
|
371
|
+
server.use(
|
|
372
|
+
http.post("http://localhost/api/v1/unprocessed_files", () =>
|
|
373
|
+
HttpResponse.json({}, { status: 200 }),
|
|
374
|
+
),
|
|
375
|
+
http.post(
|
|
376
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6/upload",
|
|
377
|
+
() => HttpResponse.json({}, { status: 201 }),
|
|
378
|
+
),
|
|
379
|
+
http.post(
|
|
380
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6",
|
|
381
|
+
() => HttpResponse.json({ test: "response" }, { status: 200 }),
|
|
382
|
+
),
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
await expect(
|
|
386
|
+
processImageFileBuffer(client, Buffer.from("test"), "test-file"),
|
|
387
|
+
).resolves.toEqual({ test: "response" });
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
describe("ProcessImageFile", () => {
|
|
392
|
+
test("Throws when server responds with an error when creating file", async () => {
|
|
393
|
+
server.use(
|
|
394
|
+
http.post("http://localhost/api/v1/unprocessed_files", () =>
|
|
395
|
+
HttpResponse.text("Internal Server Error", { status: 500 }),
|
|
396
|
+
),
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
await expect(processImageFile(client, TEST_AV_FILE)).rejects.toThrowError(
|
|
400
|
+
"Failed to create unprocessed file 500 Internal Server Error",
|
|
401
|
+
);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
test("Throws when server responds with an error when uploading file", async () => {
|
|
405
|
+
server.use(
|
|
406
|
+
http.post("http://localhost/api/v1/unprocessed_files", () =>
|
|
407
|
+
HttpResponse.json({}, { status: 200 }),
|
|
408
|
+
),
|
|
409
|
+
http.post(
|
|
410
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6/upload",
|
|
411
|
+
() => HttpResponse.text("Internal Server Error", { status: 500 }),
|
|
412
|
+
),
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
await expect(processImageFile(client, TEST_AV_FILE)).rejects.toThrowError(
|
|
416
|
+
"Failed to upload chunk 0 for /api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6/upload 500 Internal Server Error",
|
|
417
|
+
);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
test("Throws when server responds with an error when updating file", async () => {
|
|
421
|
+
server.use(
|
|
422
|
+
http.post("http://localhost/api/v1/unprocessed_files", () =>
|
|
423
|
+
HttpResponse.json({}, { status: 200 }),
|
|
424
|
+
),
|
|
425
|
+
http.post(
|
|
426
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6/upload",
|
|
427
|
+
() => HttpResponse.json({ test }, { status: 201 }),
|
|
428
|
+
),
|
|
429
|
+
http.post(
|
|
430
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6",
|
|
431
|
+
() => HttpResponse.text("Internal Server Error", { status: 500 }),
|
|
432
|
+
),
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
await expect(processImageFile(client, TEST_AV_FILE)).rejects.toThrowError(
|
|
436
|
+
"Failed to update unprocessed file 500 Internal Server Error",
|
|
437
|
+
);
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
test("Returns json data when upload is successful", async () => {
|
|
441
|
+
server.use(
|
|
442
|
+
http.post("http://localhost/api/v1/unprocessed_files", () =>
|
|
443
|
+
HttpResponse.json({}, { status: 200 }),
|
|
444
|
+
),
|
|
445
|
+
http.post(
|
|
446
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6/upload",
|
|
447
|
+
() => HttpResponse.json({}, { status: 201 }),
|
|
448
|
+
),
|
|
449
|
+
http.post(
|
|
450
|
+
"http://localhost/api/v1/unprocessed_files/098f6bcd-4621-d373-cade-4e832627b4f6",
|
|
451
|
+
() => HttpResponse.json({ test: "response" }, { status: 200 }),
|
|
452
|
+
),
|
|
453
|
+
);
|
|
454
|
+
});
|
|
455
|
+
});
|
|
312
456
|
});
|
|
@@ -13,16 +13,20 @@ import { uploadChunks } from "../uploadChunks.ts";
|
|
|
13
13
|
|
|
14
14
|
const log = debug("ef:api:unprocessed-file");
|
|
15
15
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
const FileProcessor = z.union([
|
|
17
|
+
z.literal("isobmff"),
|
|
18
|
+
z.literal("image"),
|
|
19
|
+
z.literal("captions"),
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
const FileProcessors = z.array(FileProcessor).refine(
|
|
23
|
+
(value) => {
|
|
24
|
+
return new Set(value).size === value.length;
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
message: "Processors list must not include duplicates",
|
|
28
|
+
},
|
|
29
|
+
);
|
|
26
30
|
|
|
27
31
|
const MAX_FILE_SIZE = 1024 * 1024 * 1024; // 1GiB
|
|
28
32
|
|
|
@@ -42,6 +46,7 @@ export interface CreateUnprocessedFileResult {
|
|
|
42
46
|
next_byte: number;
|
|
43
47
|
id: string;
|
|
44
48
|
processes: z.infer<typeof FileProcessors>;
|
|
49
|
+
asset_id: string;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
export interface UpdateUnprocessedFileResult {
|
|
@@ -49,6 +54,7 @@ export interface UpdateUnprocessedFileResult {
|
|
|
49
54
|
next_byte: number;
|
|
50
55
|
id: string;
|
|
51
56
|
processes: z.infer<typeof FileProcessors>;
|
|
57
|
+
asset_id: string;
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
export const createUnprocessedFile = async (
|
|
@@ -124,66 +130,72 @@ export const uploadUnprocessedFile = async (
|
|
|
124
130
|
log("Unprocessed file upload complete");
|
|
125
131
|
};
|
|
126
132
|
|
|
127
|
-
|
|
128
|
-
client: Client,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
log("File processed", fileInformation);
|
|
159
|
-
return fileInformation;
|
|
133
|
+
const buildBufferProcessor = (processor: z.infer<typeof FileProcessor>) => {
|
|
134
|
+
return async (client: Client, buffer: Buffer, filename = "buffer") => {
|
|
135
|
+
log(`Processing file buffer: ${processor}`, filename);
|
|
136
|
+
const fileId = md5Buffer(buffer);
|
|
137
|
+
|
|
138
|
+
log("File ID", fileId);
|
|
139
|
+
log(`File size: ${buffer.byteLength} bytes`);
|
|
140
|
+
|
|
141
|
+
await createUnprocessedFile(client, {
|
|
142
|
+
id: fileId,
|
|
143
|
+
processes: [],
|
|
144
|
+
filename,
|
|
145
|
+
byte_size: buffer.byteLength,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const readStream = new Readable({
|
|
149
|
+
read() {
|
|
150
|
+
readStream.push(buffer);
|
|
151
|
+
readStream.push(null);
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
await uploadUnprocessedFile(client, fileId, readStream, buffer.byteLength);
|
|
156
|
+
|
|
157
|
+
const fileInformation = await updateUnprocessedFile(client, fileId, {
|
|
158
|
+
processes: [processor],
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
log("File processed", fileInformation);
|
|
162
|
+
return fileInformation;
|
|
163
|
+
};
|
|
160
164
|
};
|
|
161
165
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
166
|
+
const buildFileProcessor = (processor: z.infer<typeof FileProcessor>) => {
|
|
167
|
+
return async (client: Client, filePath: string) => {
|
|
168
|
+
log(`Processing file ${processor}`, filePath);
|
|
169
|
+
const fileId = await md5FilePath(filePath);
|
|
170
|
+
|
|
171
|
+
log("File ID", fileId);
|
|
172
|
+
await createUnprocessedFile(client, {
|
|
173
|
+
id: fileId,
|
|
174
|
+
processes: [],
|
|
175
|
+
filename: basename(filePath),
|
|
176
|
+
byte_size: (await stat(filePath)).size,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const readStream = createReadStream(filePath);
|
|
180
|
+
|
|
181
|
+
await uploadUnprocessedFile(
|
|
182
|
+
client,
|
|
183
|
+
fileId,
|
|
184
|
+
readStream,
|
|
185
|
+
(await stat(filePath)).size,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const fileInformation = await updateUnprocessedFile(client, fileId, {
|
|
189
|
+
processes: [processor],
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
log("File processed", fileInformation);
|
|
193
|
+
return fileInformation;
|
|
194
|
+
};
|
|
195
|
+
};
|
|
182
196
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
});
|
|
197
|
+
export const processAVFileBuffer = buildBufferProcessor("isobmff");
|
|
198
|
+
export const processAVFile = buildFileProcessor("isobmff");
|
|
186
199
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
};
|
|
200
|
+
export const processImageFileBuffer = buildBufferProcessor("image");
|
|
201
|
+
export const processImageFile = buildFileProcessor("image");
|