Skip to content

Commit f4f1919

Browse files
authored
Merge pull request #27 from apivideo/feat/maxVideoDuration
feat(video uploader): Add maxVideoDuration option
2 parents fdff6a2 + 1bbbe55 commit f4f1919

File tree

2 files changed

+37
-14
lines changed

2 files changed

+37
-14
lines changed

README.md

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,15 @@ Using delegated upload tokens for authentication is best options when uploading
178178
#### Common options
179179

180180

181-
| Option name | Mandatory | Type | Description |
182-
| ------------: | --------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
183-
| file | **yes** | File | the file you want to upload |
184-
| videoName | no | string | the name of your video (overrides the original file name for regular uploads, overrides the default "file" name for progressive uploads) |
185-
| chunkSize | no | number | number of bytes of each upload chunk (default: 50MB, min: 5MB, max: 128MB) |
186-
| apiHost | no | string | api.video host (default: ws.api.video) |
187-
| retries | no | number | number of retries when an API call fails (default: 5) |
188-
| retryStrategy | no | (retryCount: number, error: VideoUploadError) => number \| null | function that returns the number of ms to wait before retrying a failed upload. Returns null to stop retrying |
181+
| Option name | Mandatory | Type | Description |
182+
| ---------------: | --------- | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
183+
| file | **yes** | File | the file you want to upload |
184+
| videoName | no | string | the name of your video (overrides the original file name for regular uploads, overrides the default "file" name for progressive uploads) |
185+
| chunkSize | no | number | number of bytes of each upload chunk (default: 50MB, min: 5MB, max: 128MB) |
186+
| apiHost | no | string | api.video host (default: ws.api.video) |
187+
| retries | no | number | number of retries when an API call fails (default: 5) |
188+
| retryStrategy | no | (retryCount: number, error: VideoUploadError) => number \| null | function that returns the number of ms to wait before retrying a failed upload. Returns null to stop retrying |
189+
| maxVideoDuration | no | number | maximum duration allowed for the file (in seconds) |
189190

190191

191192
### Example
@@ -278,12 +279,13 @@ Using delegated upload tokens for authentication is best options when uploading
278279
#### Common options
279280

280281

281-
| Option name | Mandatory | Type | Description |
282-
| ----------------: | --------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
283-
| apiHost | no | string | api.video host (default: ws.api.video) |
284-
| retries | no | number | number of retries when an API call fails (default: 5) |
285-
| retryStrategy | no | (retryCount: number, error: VideoUploadError) => number \| null | function that returns the number of ms to wait before retrying a failed upload. Returns null to stop retrying |
286-
| preventEmptyParts | no | boolean | if true, the upload will succeed even if an empty Blob is passed to uploadLastPart(). This may alter performances a bit in some cases (default: false) |
282+
| Option name | Mandatory | Type | Description |
283+
| --------------------------: | --------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
284+
| apiHost | no | string | api.video host (default: ws.api.video) |
285+
| retries | no | number | number of retries when an API call fails (default: 5) |
286+
| retryStrategy | no | (retryCount: number, error: VideoUploadError) => number \| null | function that returns the number of ms to wait before retrying a failed upload. Returns null to stop retrying |
287+
| preventEmptyParts | no | boolean | if true, the upload will succeed even if an empty Blob is passed to uploadLastPart(). This may alter performances a bit in some cases (default: false) |
288+
| mergeSmallPartsBeforeUpload | no | boolean | if false, parts smaller than 5MB will not be merged before upload, resulting in an error (default: true) |
287289

288290

289291
### Example

src/video-uploader.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AbstractUploader, CommonOptions, DEFAULT_CHUNK_SIZE, MAX_CHUNK_SIZE, MI
33
interface UploadOptions {
44
file: File;
55
chunkSize?: number;
6+
maxVideoDuration?: number;
67
}
78

89
export interface VideoUploaderOptionsWithUploadToken extends CommonOptions, UploadOptions, WithUploadToken { }
@@ -24,6 +25,7 @@ export class VideoUploader extends AbstractUploader<UploadProgressEvent> {
2425
private chunksCount: number;
2526
private fileSize: number;
2627
private fileName: string;
28+
private maxVideoDuration?: number;
2729

2830
constructor(options: VideoUploaderOptionsWithAccessToken | VideoUploaderOptionsWithUploadToken | VideoUploaderOptionsWithApiKey) {
2931
super(options);
@@ -42,10 +44,17 @@ export class VideoUploader extends AbstractUploader<UploadProgressEvent> {
4244
this.fileName = options.videoName || this.file.name;
4345

4446
this.chunksCount = Math.ceil(this.fileSize / this.chunkSize);
47+
this.maxVideoDuration = options.maxVideoDuration;
4548
}
4649

4750

4851
public async upload(): Promise<VideoUploadResponse> {
52+
if (this.maxVideoDuration !== undefined && !document) {
53+
throw Error('document is undefined. Impossible to use the maxVideoDuration option. Remove it and try again.')
54+
}
55+
if (this.maxVideoDuration !== undefined && await this.isVideoTooLong()) {
56+
throw Error(`The video submitted is too long.`);
57+
}
4958
let res: VideoUploadResponse;
5059
for(let i = 0; i < this.chunksCount; i++) {
5160
res = await this.uploadCurrentChunk(i);
@@ -54,6 +63,18 @@ export class VideoUploader extends AbstractUploader<UploadProgressEvent> {
5463
return res!;
5564
}
5665

66+
private async isVideoTooLong(): Promise<boolean> {
67+
return new Promise(resolve => {
68+
const video = document.createElement('video');
69+
video.preload = 'metadata';
70+
video.onloadedmetadata = () => {
71+
window.URL.revokeObjectURL(video.src);
72+
resolve(video.duration > this.maxVideoDuration!)
73+
}
74+
video.src = URL.createObjectURL(this.file);
75+
})
76+
}
77+
5778
private uploadCurrentChunk(chunkNumber: number): Promise<VideoUploadResponse> {
5879
const firstByte = chunkNumber * this.chunkSize;
5980
const computedLastByte = (chunkNumber + 1) * this.chunkSize;

0 commit comments

Comments
 (0)