@ormoshe/js-video-url-parser
Version:
A parser to extract provider, video id, starttime and others from YouTube, Vimeo, ... urls
206 lines (179 loc) • 5.11 kB
JavaScript
const {
combineParams,
getTime,
} = require('../util');
function YouTube() {
this.provider = 'youtube';
this.alternatives = ['youtu', 'ytimg'];
this.defaultFormat = 'long';
this.formats = {
short: this.createShortUrl,
long: this.createLongUrl,
embed: this.createEmbedUrl,
shortImage: this.createShortImageUrl,
longImage: this.createLongImageUrl,
};
this.imageQualities = {
'0': '0',
'1': '1',
'2': '2',
'3': '3',
DEFAULT: 'default',
HQDEFAULT: 'hqdefault',
SDDEFAULT: 'sddefault',
MQDEFAULT: 'mqdefault',
MAXRESDEFAULT: 'maxresdefault',
};
this.defaultImageQuality = this.imageQualities.HQDEFAULT;
this.mediaTypes = {
VIDEO: 'video',
PLAYLIST: 'playlist',
SHARE: 'share',
CHANNEL: 'channel',
};
}
module.exports = YouTube;
YouTube.prototype.parseVideoUrl = function(url) {
var match = url.match(
/(?:(?:v|vi|be|videos|shorts|embed|live)\/(?!videoseries)|(?:v|ci)=)([\w-]{11})/i
);
return match ? match[1] : undefined;
};
YouTube.prototype.parseChannelUrl = function(url) {
// Match an opaque channel ID
var match = url.match(/\/channel\/([\w-]+)/);
if (match) {
return { id: match[1], mediaType: this.mediaTypes.CHANNEL };
}
// Match a vanity channel name or a user name. User urls are deprecated and
// currently redirect to the channel of that same name.
match = url.match(/\/(?:c|user)\/([\w-]+)/);
if (match) {
return { name: match[1], mediaType: this.mediaTypes.CHANNEL };
}
};
YouTube.prototype.parseParameters = function(params, result) {
if (params.start || params.t) {
params.start = getTime(params.start || params.t);
delete params.t;
}
if (params.v === result.id) {
delete params.v;
}
if (params.list === result.id) {
delete params.list;
}
return params;
};
YouTube.prototype.parseMediaType = function(result) {
if (result.params.list) {
result.list = result.params.list;
delete result.params.list;
}
if (result.id && !result.params.ci) {
result.mediaType = this.mediaTypes.VIDEO;
} else if (result.list) {
delete result.id;
result.mediaType = this.mediaTypes.PLAYLIST;
} else if (result.params.ci) {
delete result.params.ci;
result.mediaType = this.mediaTypes.SHARE;
} else {
return undefined;
}
return result;
};
YouTube.prototype.parse = function(url, params) {
var channelResult = this.parseChannelUrl(url);
if (channelResult) {
return channelResult;
} else {
var result = {
params: params,
id: this.parseVideoUrl(url),
};
result.params = this.parseParameters(params, result);
result = this.parseMediaType(result);
return result;
}
};
YouTube.prototype.createShortUrl = function(vi, params) {
if (!vi.id || vi.mediaType !== this.mediaTypes.VIDEO) {
return undefined;
}
var url = 'https://youtu.be/' + vi.id;
if (params.start) {
url += '#t=' + params.start;
}
return url;
};
YouTube.prototype.createLongUrl = function(vi, params) {
var url = '';
var startTime = params.start;
delete params.start;
if (vi.mediaType === this.mediaTypes.CHANNEL) {
if (vi.id) {
url += 'https://www.youtube.com/channel/' + vi.id;
} else if (vi.name) {
url += 'https://www.youtube.com/c/' + vi.name;
} else {
return undefined;
}
}
else if (vi.mediaType === this.mediaTypes.PLAYLIST && vi.list) {
params.feature = 'share';
url += 'https://www.youtube.com/playlist';
}
else if (vi.mediaType === this.mediaTypes.VIDEO && vi.id) {
params.v = vi.id;
url += 'https://www.youtube.com/watch';
}
else if (vi.mediaType === this.mediaTypes.SHARE && vi.id) {
params.ci = vi.id;
url += 'https://www.youtube.com/shared';
} else {
return undefined;
}
if (vi.list) {
params.list = vi.list;
}
url += combineParams(params);
if (vi.mediaType !== this.mediaTypes.PLAYLIST && startTime) {
url += '#t=' + startTime;
}
return url;
};
YouTube.prototype.createEmbedUrl = function(vi, params) {
var url = 'https://www.youtube.com/embed';
if (vi.mediaType === this.mediaTypes.PLAYLIST && vi.list) {
params.listType = 'playlist';
} else if (vi.mediaType === this.mediaTypes.VIDEO && vi.id) {
url += '/' + vi.id;
//loop hack
if (params.loop === '1') {
params.playlist = vi.id;
}
} else {
return undefined;
}
if (vi.list) {
params.list = vi.list;
}
url += combineParams(params);
return url;
};
YouTube.prototype.createImageUrl = function(baseUrl, vi, params) {
if (!vi.id || vi.mediaType !== this.mediaTypes.VIDEO) {
return undefined;
}
var url = baseUrl + vi.id + '/';
var quality = params.imageQuality || this.defaultImageQuality;
return url + quality + '.jpg';
};
YouTube.prototype.createShortImageUrl = function(vi, params) {
return this.createImageUrl('https://i.ytimg.com/vi/', vi, params);
};
YouTube.prototype.createLongImageUrl = function(vi, params) {
return this.createImageUrl('https://img.youtube.com/vi/', vi, params);
};
require('../base').bind(new YouTube());