import { spawnSync } from 'child_process'; import { convertDurationToSeconds, convertSecondsToDuration } from '../../duration'; const normalizeStartSeconds = (start?: number | string) => { if (typeof start === 'undefined') { return 0; } if (typeof start === 'string') { return convertDurationToSeconds(start); } return start; }; const FORMAT_DEFAULT_ARGS = [ '--youtube-skip-dash-manifest', '-f', 'bestvideo+bestaudio', ]; const constructDownloadSectionsRegex = (start?: number | string, end?: number | string) => { const startSeconds = normalizeStartSeconds(start); if (typeof end !== 'undefined') { const endSeconds = ( typeof end === 'string' ? convertDurationToSeconds(end) : end ); return `*${convertSecondsToDuration(startSeconds)}-${convertSecondsToDuration(endSeconds)}`; } if (startSeconds > 0) { return `*${convertSecondsToDuration(startSeconds)}-inf`; } return null; }; export const getFileExtension = (downloaderExecutablePath: string, url: string) => { const result = spawnSync( downloaderExecutablePath, [ ...FORMAT_DEFAULT_ARGS, '--print', 'filename', '-o', '%(ext)s', url, ], ); if (result.error) { throw result.error; } const errorMessage = result.stderr.toString('utf-8').trim(); if (errorMessage.length > 0) { throw new Error(errorMessage); } return result.stdout.toString('utf-8').trim(); }; export const constructDefaultDownloadArgs = ( outputFilename: string, url: string, start?: number | string, end?: number | string, ) => { const defaultDownloadArgs = [ ...FORMAT_DEFAULT_ARGS, '-o', outputFilename, ]; const downloadSectionsRegex = constructDownloadSectionsRegex(start, end); if (typeof downloadSectionsRegex === 'string') { return [ ...defaultDownloadArgs, '--force-keyframes-at-cuts', '--download-sections', downloadSectionsRegex, url, ]; } return [ ...defaultDownloadArgs, url, ]; };