import * as commander from 'commander'; import * as fs from 'fs'; import * as bluebird from 'bluebird'; import { config, log } from '../config'; import {IImageSegment, ISegment, ITrackPlaylists, PlaylistBuilder} from '../lib/playlist-builder'; import { SegmentLoader } from '../lib/segment-loader'; import { getCompositionDefinition } from '../lib/connect-api'; import { CacheManager } from '../lib/cache'; import { Honeycomb } from '../lib/tracing'; let fileIds: string[] = []; let options = { } as any; function compressSegments(segments: any[]): any[] { segments.sort((a, b) => a.entryPoint - b.entryPoint); const ret: any[] = []; for (const segment of segments) { if (ret.length > 0 && ret[ret.length - 1].entryPoint + ret[ret.length - 1].editUnits === segment.entryPoint) { ret[ret.length - 1].editUnits += segment.editUnits; ret[ret.length - 1].duration += segment.duration; ret[ret.length - 1].size += segment.size; } else { ret.push(segment); } } return ret; } async function checkCacheForFile(fileId: string): Promise { const response = await getCompositionDefinition(fileId, options.orgSlug); if (!response || !response.compositionDefinition) { log.info(`Nothing for file: ${fileId}`); return {}; } const playlist = PlaylistBuilder.buildPlaylist( response.compositionDefinition, fileId, 7, response.org.cacheLocation, options.orgSlug, undefined, undefined, undefined, true, ); const cachedPlaylists: Record = {}; for (const trackPlaylistId of Object.keys(playlist.trackPlaylists as ITrackPlaylists)) { const trackPlaylist = (playlist.trackPlaylists as ITrackPlaylists)[trackPlaylistId]; let allSegments: ISegment[] = []; if (trackPlaylist.type === 'image') { allSegments = []; for (const segment of trackPlaylist.segments) { allSegments.push(segment); const subSegments = SegmentLoader.generateSubsegments(segment as IImageSegment); allSegments.push(...subSegments); } } else { allSegments = trackPlaylist.segments; } let cachedSegments: any[] = (await bluebird.Promise .map(allSegments, async (segment) => { return { segment, cachedSegment: await CacheManager.getInstance().checkCache( options.orgSlug, segment.fileId as string, SegmentLoader.generateSegmentId(segment) ), }; }, { concurrency: 10 })) .filter(obj => obj.cachedSegment != null).map((obj) => { return { ...obj.segment, size: obj.cachedSegment?.size as number }; }); if (options.compress === 'true') { cachedSegments = compressSegments(cachedSegments); } cachedPlaylists[trackPlaylistId] = { cachedPlaylist: cachedSegments, trackType: trackPlaylist.type }; } return { fileId, cachedPlaylists }; } async function run(): Promise { Honeycomb.initialize(); const command = new commander.Command(); command .option('-h, --host ', 'Redis host to work with.') .option('-p, --port ', 'The port on which to connect.') .option('-d, --db ', 'The Redis db used.') .option('-o, --org-slug ', 'The organization slug.') .option('-f, --file-id ', 'The file for which to get cache') .option('-c --compress ', 'Compress segments if there are multiple consecutive') .parse(process.argv); if (!command.orgSlug) { log.info('Please specify an organization slug.'); return; } if (!command.fileId) { log.info('Please specify the file id'); } options = { host: command.host || config.cacheRedis.host, port: command.port || config.cacheRedis.port, db: command.db || config.cacheRedis.database, orgSlug: command.orgSlug, outputFile: command.outputFile, compress: command.compress, } as any; log.info(`Running with config: ${JSON.stringify(options)}`); fileIds = [command.fileId]; const fileResults: object[] = await bluebird.Promise.map(fileIds, async fileId => checkCacheForFile(fileId), { concurrency: 4 }); for (const fileResult of fileResults) { const { fileId, cachedPlaylists } = fileResult as any; fs.appendFileSync(1, `Data for file: ${fileId}\n`); let totalFileCacheSize = 0; for (const trackId of Object.keys(cachedPlaylists)) { const { cachedPlaylist, trackType } = cachedPlaylists[trackId]; fs.appendFileSync(1, `--Track ${trackId} with type ${trackType}:\n`, 'utf-8'); let totalTrackCacheSize = 0; for (const segment of cachedPlaylist) { // tslint:disable-next-line:prefer-template fs.appendFileSync(1, ` Segment first frame: ${segment.entryPoint}, last frame: ${segment.entryPoint + segment.editUnits - 1}, ` + `start time: ${segment.startTime}, duration: ${segment.duration}, size: ${segment.size}\n`, 'utf-8'); totalTrackCacheSize += segment.size; } fs.appendFileSync(1, `Total track cache size: ${totalTrackCacheSize}\n`); totalFileCacheSize += totalTrackCacheSize; } fs.appendFileSync(1, `Total file cache size: ${totalFileCacheSize}\n\n`); } console.log('Done!'); process.exit(0); } (async () => await run())();