scrptly
Version:
Scrptly is a Video Development Kit (VDK) for programmatically generating AI-powered videos.
95 lines (90 loc) • 2.47 kB
text/typescript
import fs from 'fs';
import crypto from 'crypto';
import type Scrptly from './index';
export default class AssetUploader {
$: Scrptly;
path: string;
type: string;
constructor($: Scrptly, path: string, type: string) {
this.$ = $;
this.path = path;
this.type = type;
}
async hashFile(): Promise<string> {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('md5');
const stream = fs.createReadStream(this.path);
stream.on('error', reject);
stream.on('data', chunk => {
hash.update(chunk);
});
stream.on('end', () => {
resolve(hash.digest('base64'));
});
});
}
async uploadAsset() {
// Calculate hash of the file
const { size } = await fs.promises.stat(this.path);
const hash = await this.hashFile();
const fileName = this.path.split('/').pop();
const extension = fileName?.split('.').pop();
if(!fileName || !extension)
throw new Error('Invalid file name or extension');
const prepare = await this.$.apiCall('prepareAsset', {
method: 'POST',
body: JSON.stringify({
fileName,
hash,
type: this.type,
extension,
size
}),
});
if(prepare.success) {
if(prepare.found) {
return {assetId: prepare.assetId, url: prepare.url};
} else if(prepare.presignedUrl) {
const fileStream = fs.createReadStream(this.path);
const res = await fetch(prepare.presignedUrl, {
method: 'PUT',
headers: {
'Content-Type': prepare.contentType,
'Content-Length': size.toString(),
'Content-MD5': hash,
},
body: fileStream as any,
// @ts-expect-error
duplex: 'half'
});
if (res.ok) {
const successUpload = await this.$.apiCall('completeAssetUpload', {
method: 'POST',
body: JSON.stringify({
assetId: prepare.assetId,
result: 'success',
}),
});
if(successUpload.success) {
return {assetId: successUpload.assetId, url: successUpload.url};
} else {
throw new Error(`Could not complete upload: ${successUpload.error}`);
}
} else {
await this.$.apiCall('completeAssetUpload', {
method: 'POST',
body: JSON.stringify({
assetId: prepare.assetId,
result: 'error',
}),
});
throw new Error(`Upload failed [${res.status}]\n> ${await res.text()}`);
}
} else {
throw new Error('Invalid response from server');
}
} else {
throw new Error(`Error uploading asset: ${prepare.error}`);
}
}
}