/** * Get video ID. * * There are a few type of video URL formats. * - https://www.youtube.com/watch?v=VIDEO_ID * - https://m.youtube.com/watch?v=VIDEO_ID * - https://youtu.be/VIDEO_ID * - https://www.youtube.com/v/VIDEO_ID * - https://www.youtube.com/embed/VIDEO_ID * - https://music.youtube.com/watch?v=VIDEO_ID * - https://gaming.youtube.com/watch?v=VIDEO_ID * * @param {string} link * @return {string} * @throws {Error} If unable to find a id * @throws {TypeError} If videoid doesn't match specs */ const validQueryDomains = new Set([ 'youtube.com', 'www.youtube.com', 'm.youtube.com', 'music.youtube.com', 'gaming.youtube.com', ]); const validPathDomains = /^https?:\/\/(youtu\.be\/|(www\.)?youtube\.com\/(embed|v|shorts)\/)/; exports.getURLVideoID = link => { const parsed = new URL(link); let id = parsed.searchParams.get('v'); if (validPathDomains.test(link) && !id) { const paths = parsed.pathname.split('/'); id = parsed.host === 'youtu.be' ? paths[1] : paths[2]; } else if (parsed.hostname && !validQueryDomains.has(parsed.hostname)) { throw Error('Not a YouTube domain'); } if (!id) { throw Error(`No video id found: ${link}`); } id = id.substring(0, 11); if (!exports.validateID(id)) { throw TypeError(`Video id (${id}) does not match expected ` + `format (${idRegex.toString()})`); } return id; }; /** * Gets video ID either from a url or by checking if the given string * matches the video ID format. * * @param {string} str * @returns {string} * @throws {Error} If unable to find a id * @throws {TypeError} If videoid doesn't match specs */ const urlRegex = /^https?:\/\//; exports.getVideoID = str => { if (exports.validateID(str)) { return str; } else if (urlRegex.test(str)) { return exports.getURLVideoID(str); } else { throw Error(`No video id found: ${str}`); } }; /** * Returns true if given id satifies YouTube's id format. * * @param {string} id * @return {boolean} */ const idRegex = /^[a-zA-Z0-9-_]{11}$/; exports.validateID = id => idRegex.test(id); /** * Checks wether the input string includes a valid id. * * @param {string} string * @returns {boolean} */ exports.validateURL = string => { try { exports.getURLVideoID(string); return true; } catch (e) { return false; } };