// npm import { v4 as uuid } from 'uuid'; import * as AWS from 'aws-sdk'; import * as path from 'path'; // @ownzones import * as lib from '@ownzones/lib'; import { createFFmpegCommand } from '@ownzones/meh'; // app import { config, log } from '../../config'; import { Honeycomb } from '../tracing'; import { TrackedFFmpegCommand } from '../../utils/types'; export class SegmentBuilderHelper { public static async ffmpegSetOffset(segmentPath: string, offset: number, concat: boolean, extension = '.ts'): Promise { const { ffmpegCommand, ffmpegPromise } = createFFmpegCommand({ ffmpegTimeout: 20 }) as TrackedFFmpegCommand; const segmentWithOffsetPath = path.join(config.mediaPath, `${uuid()}${extension}`); const span = Honeycomb.startSpan(path.basename(__filename), 'offsetWork'); Honeycomb.addCustomContext({ concat, segmentPath, offset, }); const videoInputOptions = [ '-copyts', '-start_at_zero', ]; const outputOptions = [ '-c:v copy', '-c:a copy', '-muxdelay 0', `-output_ts_offset ${offset}`, ]; ffmpegCommand .input(segmentPath) .inputOptions(videoInputOptions) .outputOptions(outputOptions); if (concat) { ffmpegCommand .inputOptions('-safe 0') .inputOptions('-protocol_whitelist pipe,file,http,https,tcp,tls') .inputFormat('concat'); } ffmpegCommand.save(segmentWithOffsetPath); await ffmpegPromise; Honeycomb.endSpan(span); return segmentWithOffsetPath; } private s3Client: AWS.S3; private readonly signaturePeriod: number; private signedUrls: Record; public constructor() { this.s3Client = new AWS.S3(); this.signaturePeriod = 15 * 60; // seconds this.signedUrls = {}; } public resetSignedUrlsCache(): void { this.signedUrls = {}; } public async getSignedUrl(url: string): Promise { const timestamp = Date.now(); // sign the url if it expires in the 7.5 minutes if (!this.signedUrls[url] || this.signedUrls[url].expire - timestamp < (this.signaturePeriod / 2) * 1000) { log.debug(`Signing url ${url} ...`); const signedUrl = await this.signUrl(url); this.signedUrls[url] = { signedUrl, expire: timestamp + this.signaturePeriod * 1000, }; } return this.signedUrls[url].signedUrl; } private async signUrl(url: string) { const parsedUrl = lib.s3.parseUrl(url); return this.s3Client.getSignedUrlPromise('getObject', { Bucket: parsedUrl.bucket, Key: parsedUrl.key, Expires: this.signaturePeriod, }); } } export const helper = new SegmentBuilderHelper();