UNPKG

js-video-url-parser-arts

Version:

A parser to extract provider, video id, starttime and others from YouTube, Vimeo, ... urls

490 lines (436 loc) 11.2 kB
function URLParser() { "use strict"; this.plugins = {}; } URLParser.prototype.parse = function (url) { "use strict"; var th = this, match = url.match(/(?:(?:https?:)?\/\/)?(?:[^\.]+\.)?(\w+)\./i), provider = match ? match[1] : undefined, result; if (match && provider && th.plugins[provider] && th.plugins[provider].parse) { result = th.plugins[provider].parse.call(this, url, getQueryParams(url)); if (result) { if (result.params && Object.keys(result.params).length === 0) { delete result.params; } result.provider = th.plugins[provider].provider; return result; } } return undefined; }; URLParser.prototype.bind = function (plugin) { "use strict"; var th = this; th.plugins[plugin.provider] = plugin; if (plugin.alternatives) { for (var i = 0; i < plugin.alternatives.length; i += 1) { th.plugins[plugin.alternatives[i]] = plugin; } } }; URLParser.prototype.create = function (op) { "use strict"; var th = this, vi = op.videoInfo, params = op.params, plugin = th.plugins[vi.provider]; params = (params === 'internal') ? vi.params : params || {}; if (plugin) { op.format = op.format || plugin.defaultFormat; if (plugin.formats.hasOwnProperty(op.format)) { return plugin.formats[op.format](vi, cloneObject(params)); } } return undefined; }; var urlParser = new URLParser(); if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { module.exports = urlParser; } /*jshint unused:false */ function cloneObject(obj) { /*jshint unused:true */ "use strict"; if (obj === null || typeof obj !== 'object') { return obj; } var temp = obj.constructor(); // give temp the original obj's constructor for (var key in obj) { temp[key] = cloneObject(obj[key]); } return temp; } /*jshint unused:false */ function getQueryParams(qs) { /*jshint unused:true */ "use strict"; if (typeof qs !== 'string') { return {}; } qs = qs.split('+').join(' '); var params = {}, match = qs.match( /(?:[\?](?:[^=]+)=(?:[^&#]*)(?:[&](?:[^=]+)=(?:[^&#]*))*(?:[#].*)?)|(?:[#].*)/ ), split; if (match === null) { return {}; } split = match[0].substr(1).split(/[&#=]/); for (var i = 0; i < split.length; i += 2) { params[decodeURIComponent(split[i])] = decodeURIComponent(split[i + 1] || ''); } return params; } /*jshint unused:false */ function combineParams(op) { /*jshint unused:true */ "use strict"; if (typeof op !== 'object') { return ''; } op.params = op.params || {}; var combined = '', i = 0, keys = Object.keys(op.params); if (keys.length === 0) { return ''; } //always have parameters in the same order keys.sort(); if (!op.hasParams) { combined += '?' + keys[0] + '=' + op.params[keys[0]]; i += 1; } for (; i < keys.length; i += 1) { combined += '&' + keys[i] + '=' + op.params[keys[i]]; } return combined; } //parses strings like 1h30m20s to seconds /*jshint unused:false */ function getTime(timeString) { /*jshint unused:true */ "use strict"; var totalSeconds = 0, timeValues = { 's': 1, 'm': 1 * 60, 'h': 1 * 60 * 60, 'd': 1 * 60 * 60 * 24, 'w': 1 * 60 * 60 * 24 * 7 }, timePairs; //is the format 1h30m20s etc if (!timeString.match(/^(\d+[smhdw]?)+$/)) { return 0; } //expand to "1 h 30 m 20 s" and split timeString = timeString.replace(/([smhdw])/g, ' $1 ').trim(); timePairs = timeString.split(' '); for (var i = 0; i < timePairs.length; i += 2) { totalSeconds += parseInt(timePairs[i], 10) * timeValues[timePairs[i + 1] || 's']; } return totalSeconds; } urlParser.bind({ provider: 'coub', parse: function (url, params) { "use strict"; var match; var result = { mediaType: 'video', params: params }; match = url.match( /coub\.com\/view\/([a-zA-Z\d]+)/i ); result.id = match ? match[1] : undefined; if (!result.id) { return undefined; } if (params.hasOwnProperty('t')) { params.start = getTime(params.t); delete params.t; } return result; }, defaultFormat: 'long', formats: { long: function (vi, params) { "use strict"; var url = 'https://coub.com/view/' + vi.id; var startTime = params.start; delete params.start; url += combineParams({ params: params }); if (startTime) { url += '#t=' + startTime; } return url; }, embed: function (vi, params) { "use strict"; var url = '//coub.com/embed/' + vi.id; var startTime = params.start; delete params.start; url += combineParams({ params: params }); if (startTime) { url += '#t=' + startTime; } return url; } } }); urlParser.bind({ 'provider': 'dailymotion', 'alternatives': ['dai'], 'parse': function (url, params) { "use strict"; var match, id, result = { params: params }; match = url.match(/(?:\/video|ly)\/([A-Za-z0-9]+)/i); id = match ? match[1] : undefined; if (params.hasOwnProperty('start')) { params.start = getTime(params.start); } if (!id) { return undefined; } result.mediaType = 'video'; result.id = id; return result; }, defaultFormat: 'long', formats: { short: function (vi) { "use strict"; return 'https://dai.ly/' + vi.id; }, long: function (vi, params) { "use strict"; return 'https://dailymotion.com/video/' + vi.id + combineParams({ params: params }); }, embed: function (vi, params) { "use strict"; return '//www.dailymotion.com/embed/video/' + vi.id + combineParams({ params: params }); } } // }); urlParser.bind({ 'provider': 'twitch', 'parse': function (url, params) { "use strict"; var match, id, channel, idPrefix, result = {}; match = url.match(/twitch\.tv\/(\w+)(?:\/(.)\/(\d+))?/i); channel = match ? match[1] : undefined; idPrefix = match ? match[2] : undefined; id = match ? match[3] : undefined; channel = params.channel || params.utm_content || channel; if (!channel) { return undefined; } if (id) { result.mediaType = 'video'; result.id = id; result.idPrefix = idPrefix; } else { result.mediaType = 'stream'; } result.channel = channel; return result; }, defaultFormat: 'long', formats: { long: function (vi, params) { "use strict"; var url = ''; if (vi.mediaType === 'stream') { url = 'https://twitch.tv/' + vi.channel; } else if (vi.mediaType === 'video') { url = 'https://twitch.tv/' + vi.channel + '/' + vi.idPrefix + '/' + vi.id; } url += combineParams({ params: params }); return url; }, embed: function (vi, params) { "use strict"; return '//www.twitch.tv/' + vi.channel + '/embed' + combineParams({ params: params }); }, } }); urlParser.bind({ provider: 'vimeo', alternatives: ['vimeopro'], parse: function (url, params) { "use strict"; var match; var result = { mediaType: 'video', params: params }; match = url.match( /(?:\/(?:channels\/[\w]+|(?:(?:album\/\d+|groups\/[\w]+)\/)?videos?))?\/(\d+)/i ); result.id = match ? match[1] : undefined; if (!result.id) { return undefined; } if (params.hasOwnProperty('t')) { params.start = getTime(params.t); delete params.t; } return result; }, defaultFormat: 'long', formats: { long: function (vi, params) { "use strict"; var url = 'https://vimeo.com/' + vi.id; var startTime = params.start; delete params.start; url += combineParams({ params: params }); if (startTime) { url += '#t=' + startTime; } return url; }, embed: function (vi, params) { "use strict"; var url = '//player.vimeo.com/video/' + vi.id; var startTime = params.start; delete params.start; url += combineParams({ params: params }); if (startTime) { url += '#t=' + startTime; } return url; } } }); urlParser.bind({ 'provider': 'youtube', 'alternatives': ['youtu'], 'parse': function (url, params) { "use strict"; var match, id, list, result = { params: params }; match = url.match(/(?:(?:v|be|videos|embed)\/(?!videoseries)|v=)([\w\-]{11})/i); id = match ? match[1] : undefined; if (params.v === id) { delete params.v; } if (params.list === id) { delete params.list; } else { list = params.list; } if (params.hasOwnProperty('start')) { params.start = getTime(params.start); } if (params.hasOwnProperty('t')) { params.start = getTime(params.t); delete params.t; } if (id) { result.mediaType = 'video'; result.id = id; if (list) { result.list = list; } } else if (list) { result.mediaType = 'playlist'; result.list = list; } else { return undefined; } return result; }, defaultFormat: 'long', formats: { short: function (vi, params) { "use strict"; var url = 'https://youtu.be/' + vi.id; if (params.start) { url += '#t=' + params.start; } return url; }, embed: function (vi, params) { "use strict"; var url = '//youtube.com/embed'; if (vi.mediaType === 'playlist') { params.listType = 'playlist'; } else { url += '/' + vi.id; //loop hack if (params.loop == 1) { params.playlist = vi.id; } } url += combineParams({ params: params }); return url; }, long: function (vi, params) { "use strict"; var url = '', startTime = params.start; delete params.start; if (vi.mediaType === 'playlist') { params.feature = 'share'; url += 'https://youtube.com/playlist'; } else { params.v = vi.id; url += 'https://youtube.com/watch'; } url += combineParams({ params: params }); if (vi.mediaType !== 'playlist' && startTime) { url += '#t=' + startTime; } return url; }, 'default': 'long' } });