@@ -8,6 +8,7 @@ import { | |||||
import { VIDEO_TYPE } from './common'; | import { VIDEO_TYPE } from './common'; | ||||
import { constructDefaultDownloadArgs, getFileExtension } from './downloader'; | import { constructDefaultDownloadArgs, getFileExtension } from './downloader'; | ||||
import { DownloaderFailedToStartError, DownloaderNotFoundError } from './errors'; | import { DownloaderFailedToStartError, DownloaderNotFoundError } from './errors'; | ||||
import {retrieveVideoId} from './url'; | |||||
export interface CreateClipperParams extends CreateBaseClipperParams { | export interface CreateClipperParams extends CreateBaseClipperParams { | ||||
type: typeof VIDEO_TYPE; | type: typeof VIDEO_TYPE; | ||||
@@ -24,7 +25,8 @@ export const createVideoClipper = (createClipperParams: Omit<CreateClipperParams | |||||
createClipperParams.downloaderExecutablePath, | createClipperParams.downloaderExecutablePath, | ||||
clipVideoParams.url, | clipVideoParams.url, | ||||
); | ); | ||||
const cacheFilename = `output.${fileExtension}`; // todo label this on the cache | |||||
const videoId = retrieveVideoId(clipVideoParams.url); | |||||
const cacheFilename = `output.${encodeURIComponent(videoId)}.${fileExtension}`; | |||||
const downloadArgs = constructDefaultDownloadArgs( | const downloadArgs = constructDefaultDownloadArgs( | ||||
cacheFilename, | cacheFilename, | ||||
clipVideoParams.url, | clipVideoParams.url, | ||||
@@ -51,6 +51,12 @@ export const getFileExtension = (downloaderExecutablePath: string, url: string) | |||||
throw 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(); | return result.stdout.toString('utf-8').trim(); | ||||
}; | }; | ||||
@@ -1,3 +1,5 @@ | |||||
export class DownloaderNotFoundError extends Error {} | export class DownloaderNotFoundError extends Error {} | ||||
export class DownloaderFailedToStartError extends Error {} | export class DownloaderFailedToStartError extends Error {} | ||||
export class InvalidVideoIdError extends Error {} |
@@ -0,0 +1,19 @@ | |||||
import { InvalidVideoIdError } from './errors'; | |||||
const STANDARD_YOUTUBE_VIDEO_ID_LENGTH = 11 as const; | |||||
export const RE_YOUTUBE = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v?:i?=|&v?:i?=))([^#&?]*).*/im; | |||||
export const retrieveVideoId = (videoId: string): string => { | |||||
if (typeof (videoId as unknown) !== 'string') { | |||||
throw new InvalidVideoIdError('The video ID must be a string.'); | |||||
} | |||||
if (videoId.length === STANDARD_YOUTUBE_VIDEO_ID_LENGTH) { | |||||
return videoId; | |||||
} | |||||
const matchId = videoId.match(RE_YOUTUBE); | |||||
if (matchId && matchId.length > 1) { | |||||
return matchId[1]; | |||||
} | |||||
throw new InvalidVideoIdError('Impossible to retrieve Youtube video ID.'); | |||||
}; |