Merge pull request #3883 from edx/anton/fix-youtube-regexp
Fix youtube regular expression in video player editor
This commit is contained in:
@@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes,
|
||||
in roughly chronological order, most recent first. Add your entries at or near
|
||||
the top. Include a label indicating the component affected.
|
||||
|
||||
Blades: Fix Youtube regular expression in video player editor. BLD-967.
|
||||
|
||||
Blades: Fix displaying transcripts on touch devices. BLD-1033.
|
||||
|
||||
Blades: Tolerance expressed in percentage now computes correctly. BLD-522.
|
||||
|
||||
@@ -1,264 +1,266 @@
|
||||
define(
|
||||
[
|
||||
"jquery", "underscore",
|
||||
"js/views/video/transcripts/utils",
|
||||
"underscore.string", "xmodule", "jasmine-jquery"
|
||||
'jquery', 'underscore',
|
||||
'js/views/video/transcripts/utils',
|
||||
'underscore.string', 'xmodule', 'jasmine-jquery'
|
||||
],
|
||||
function ($, _, Utils, _str) {
|
||||
describe('Transcripts.Utils', function () {
|
||||
var videoId = 'OEoXaMPEzfM',
|
||||
ytLinksList = (function (id) {
|
||||
var links = [
|
||||
'http://www.youtube.com/watch?v=%s&feature=feedrec_grec_index',
|
||||
'http://www.youtube.com/user/IngridMichaelsonVEVO#p/a/u/1/%s',
|
||||
'http://www.youtube.com/v/%s?fs=1&hl=en_US&rel=0',
|
||||
'http://www.youtube.com/watch?v=%s#t=0m10s',
|
||||
'http://www.youtube.com/embed/%s?rel=0',
|
||||
'http://www.youtube.com/watch?v=%s',
|
||||
'http://youtu.be/%s'
|
||||
];
|
||||
|
||||
return $.map(links, function (link) {
|
||||
return _str.sprintf(link, id);
|
||||
});
|
||||
|
||||
} (videoId)),
|
||||
html5FileName = 'file_name',
|
||||
html5LinksList = (function (videoName) {
|
||||
var videoTypes = ['mp4', 'webm'],
|
||||
links = [
|
||||
'http://somelink.com/%s.%s?param=1¶m=2#hash',
|
||||
'http://somelink.com/%s.%s#hash',
|
||||
'http://somelink.com/%s.%s?param=1¶m=2',
|
||||
'http://somelink.com/%s.%s',
|
||||
'ftp://somelink.com/%s.%s',
|
||||
'https://somelink.com/%s.%s',
|
||||
'somelink.com/%s.%s',
|
||||
'%s.%s'
|
||||
],
|
||||
data = {};
|
||||
|
||||
$.each(videoTypes, function (index, type) {
|
||||
data[type] = $.map(links, function (link) {
|
||||
return _str.sprintf(link, videoName, type);
|
||||
});
|
||||
});
|
||||
|
||||
return data;
|
||||
|
||||
} (html5FileName));
|
||||
|
||||
describe('Method: getField', function (){
|
||||
var collection,
|
||||
testFieldName = 'test_field';
|
||||
|
||||
beforeEach(function() {
|
||||
collection = jasmine.createSpyObj(
|
||||
'Collection',
|
||||
[
|
||||
'findWhere'
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('All works okay if all arguments are passed', function () {
|
||||
Utils.getField(collection, testFieldName);
|
||||
|
||||
expect(collection.findWhere).toHaveBeenCalledWith({
|
||||
field_name: testFieldName
|
||||
});
|
||||
});
|
||||
|
||||
var wrongArgumentLists = [
|
||||
{
|
||||
argName: 'collection',
|
||||
list: [undefined, testFieldName]
|
||||
},
|
||||
{
|
||||
argName: 'field name',
|
||||
list: [collection, undefined]
|
||||
},
|
||||
{
|
||||
argName: 'both',
|
||||
list: [undefined, undefined]
|
||||
}
|
||||
'use strict';
|
||||
describe('Transcripts.Utils', function () {
|
||||
var videoId = 'OEoXaMPEzfM',
|
||||
ytLinksList = (function (id) {
|
||||
var links = [
|
||||
'http://www.youtube.com/watch?v=%s&feature=feedrec_grec_index',
|
||||
'http://www.youtube.com/user/IngridMichaelsonVEVO#p/a/u/1/%s',
|
||||
'http://www.youtube.com/v/%s?fs=1&hl=en_US&rel=0',
|
||||
'http://www.youtube.com/watch?v=%s#t=0m10s',
|
||||
'http://www.youtube.com/embed/%s?rel=0',
|
||||
'http://www.youtube.com/watch?v=%s',
|
||||
'http://youtu.be/%s'
|
||||
];
|
||||
|
||||
$.each(wrongArgumentLists, function (index, element) {
|
||||
it(element.argName + ' argument(s) is/are absent', function () {
|
||||
var result = Utils.getField.apply(this, element.list);
|
||||
return $.map(links, function (link) {
|
||||
return _str.sprintf(link, id);
|
||||
});
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
} (videoId)),
|
||||
html5FileName = 'file_name',
|
||||
html5LinksList = (function (videoName) {
|
||||
var videoTypes = ['mp4', 'webm'],
|
||||
links = [
|
||||
'http://somelink.com/%s.%s?param=1¶m=2#hash',
|
||||
'http://somelink.com/%s.%s#hash',
|
||||
'http://somelink.com/%s.%s?param=1¶m=2',
|
||||
'http://somelink.com/%s.%s',
|
||||
'ftp://somelink.com/%s.%s',
|
||||
'https://somelink.com/%s.%s',
|
||||
'http://cdn.somecdn.net/v/%s.%s',
|
||||
'somelink.com/%s.%s',
|
||||
'%s.%s'
|
||||
],
|
||||
data = {};
|
||||
|
||||
$.each(videoTypes, function (index, type) {
|
||||
data[type] = $.map(links, function (link) {
|
||||
return _str.sprintf(link, videoName, type);
|
||||
});
|
||||
});
|
||||
|
||||
return data;
|
||||
|
||||
} (html5FileName));
|
||||
|
||||
describe('Method: getField', function (){
|
||||
var collection,
|
||||
testFieldName = 'test_field';
|
||||
|
||||
beforeEach(function() {
|
||||
collection = jasmine.createSpyObj(
|
||||
'Collection',
|
||||
[
|
||||
'findWhere'
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
it('All works okay if all arguments are passed', function () {
|
||||
Utils.getField(collection, testFieldName);
|
||||
|
||||
expect(collection.findWhere).toHaveBeenCalledWith({
|
||||
field_name: testFieldName
|
||||
});
|
||||
});
|
||||
|
||||
var wrongArgumentLists = [
|
||||
{
|
||||
argName: 'collection',
|
||||
list: [undefined, testFieldName]
|
||||
},
|
||||
{
|
||||
argName: 'field name',
|
||||
list: [collection, undefined]
|
||||
},
|
||||
{
|
||||
argName: 'both',
|
||||
list: [undefined, undefined]
|
||||
}
|
||||
];
|
||||
|
||||
$.each(wrongArgumentLists, function (index, element) {
|
||||
it(element.argName + ' argument(s) is/are absent', function () {
|
||||
var result = Utils.getField.apply(this, element.list);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Method: parseYoutubeLink', function () {
|
||||
describe('Supported urls', function () {
|
||||
$.each(ytLinksList, function (index, link) {
|
||||
it(link, function () {
|
||||
var result = Utils.parseYoutubeLink(link);
|
||||
|
||||
expect(result).toBe(videoId);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Method: parseYoutubeLink', function () {
|
||||
describe('Supported urls', function () {
|
||||
$.each(ytLinksList, function (index, link) {
|
||||
it(link, function () {
|
||||
var result = Utils.parseYoutubeLink(link);
|
||||
describe('Wrong arguments ', function () {
|
||||
|
||||
expect(result).toBe(videoId);
|
||||
});
|
||||
});
|
||||
beforeEach(function(){
|
||||
spyOn(console, 'log');
|
||||
});
|
||||
|
||||
describe('Wrong arguments ', function () {
|
||||
it('no arguments', function () {
|
||||
var result = Utils.parseYoutubeLink();
|
||||
|
||||
beforeEach(function(){
|
||||
spyOn(console, 'log');
|
||||
});
|
||||
|
||||
it('no arguments', function () {
|
||||
var result = Utils.parseYoutubeLink();
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('wrong data type', function () {
|
||||
var result = Utils.parseYoutubeLink(1);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('videoId is wrong', function () {
|
||||
var videoId = 'wrong_id',
|
||||
link = 'http://youtu.be/' + videoId,
|
||||
result = Utils.parseYoutubeLink(link);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
var wrongUrls = [
|
||||
'http://youtu.bee/' + videoId,
|
||||
'http://youtu.be/',
|
||||
'example.com',
|
||||
'http://google.com/somevideo.mp4'
|
||||
];
|
||||
|
||||
$.each(wrongUrls, function (index, link) {
|
||||
it(link, function () {
|
||||
var result = Utils.parseYoutubeLink(link);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Method: parseHTML5Link', function () {
|
||||
describe('Supported urls', function () {
|
||||
$.each(html5LinksList, function (format, linksList) {
|
||||
$.each(linksList, function (index, link) {
|
||||
it(link, function () {
|
||||
var result = Utils.parseHTML5Link(link);
|
||||
|
||||
expect(result).toEqual({
|
||||
video: html5FileName,
|
||||
type: format
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('Wrong arguments ', function () {
|
||||
it('wrong data type', function () {
|
||||
var result = Utils.parseYoutubeLink(1);
|
||||
|
||||
beforeEach(function(){
|
||||
spyOn(console, 'log');
|
||||
});
|
||||
|
||||
it('no arguments', function () {
|
||||
var result = Utils.parseHTML5Link();
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('wrong data type', function () {
|
||||
var result = Utils.parseHTML5Link(1);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
var html5WrongUrls = [
|
||||
'http://youtu.bee/' + videoId,
|
||||
'http://youtu.be/',
|
||||
'example.com',
|
||||
'http://google.com/somevideo.mp1',
|
||||
'http://google.com/somevideomp4',
|
||||
'http://google.com/somevideo_mp4',
|
||||
'http://google.com/somevideo:mp4',
|
||||
'http://google.com/somevideo',
|
||||
'http://google.com/somevideo.webm_'
|
||||
];
|
||||
|
||||
$.each(html5WrongUrls, function (index, link) {
|
||||
it(link, function () {
|
||||
var result = Utils.parseHTML5Link(link);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Method: getYoutubeLink', function () {
|
||||
var videoId = 'video_id',
|
||||
result = Utils.getYoutubeLink(videoId),
|
||||
expectedResult = 'http://youtu.be/' + videoId;
|
||||
|
||||
expect(result).toBe(expectedResult);
|
||||
});
|
||||
|
||||
describe('Method: parseLink', function () {
|
||||
var resultDataDict = {
|
||||
'html5': {
|
||||
link: html5LinksList['mp4'][0],
|
||||
resp: {
|
||||
mode: 'html5',
|
||||
video: html5FileName,
|
||||
type: 'mp4'
|
||||
}
|
||||
},
|
||||
'youtube': {
|
||||
link: ytLinksList[0],
|
||||
resp: {
|
||||
mode: 'youtube',
|
||||
video: videoId,
|
||||
type: 'youtube'
|
||||
}
|
||||
},
|
||||
'incorrect': {
|
||||
link: 'http://example.com',
|
||||
resp: {
|
||||
mode: 'incorrect'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.each(resultDataDict, function (mode, data) {
|
||||
it(mode, function () {
|
||||
var result = Utils.parseLink(data.link);
|
||||
|
||||
expect(result).toEqual(data.resp);
|
||||
});
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
describe('Wrong arguments ', function () {
|
||||
it('videoId is wrong', function () {
|
||||
var videoId = 'wrong_id',
|
||||
link = 'http://youtu.be/' + videoId,
|
||||
result = Utils.parseYoutubeLink(link);
|
||||
|
||||
it('no arguments', function () {
|
||||
var result = Utils.parseLink();
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
var wrongUrls = [
|
||||
'http://youtu.bee/' + videoId,
|
||||
'http://youtu.be/',
|
||||
'example.com',
|
||||
'http://google.com/somevideo.mp4'
|
||||
];
|
||||
|
||||
it('wrong data type', function () {
|
||||
var result = Utils.parseLink(1);
|
||||
$.each(wrongUrls, function (index, link) {
|
||||
it(link, function () {
|
||||
var result = Utils.parseYoutubeLink(link);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Method: parseHTML5Link', function () {
|
||||
describe('Supported urls', function () {
|
||||
$.each(html5LinksList, function (format, linksList) {
|
||||
$.each(linksList, function (index, link) {
|
||||
it(link, function () {
|
||||
var result = Utils.parseHTML5Link(link);
|
||||
|
||||
expect(result).toEqual({
|
||||
video: html5FileName,
|
||||
type: format
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Wrong arguments ', function () {
|
||||
|
||||
beforeEach(function(){
|
||||
spyOn(console, 'log');
|
||||
});
|
||||
|
||||
it('no arguments', function () {
|
||||
var result = Utils.parseHTML5Link();
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('wrong data type', function () {
|
||||
var result = Utils.parseHTML5Link(1);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
var html5WrongUrls = [
|
||||
'http://youtu.bee/' + videoId,
|
||||
'http://youtu.be/',
|
||||
'example.com',
|
||||
'http://google.com/somevideo.mp1',
|
||||
'http://google.com/somevideomp4',
|
||||
'http://google.com/somevideo_mp4',
|
||||
'http://google.com/somevideo:mp4',
|
||||
'http://google.com/somevideo',
|
||||
'http://google.com/somevideo.webm_'
|
||||
];
|
||||
|
||||
$.each(html5WrongUrls, function (index, link) {
|
||||
it(link, function () {
|
||||
var result = Utils.parseHTML5Link(link);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Method: getYoutubeLink', function () {
|
||||
var videoId = 'video_id',
|
||||
result = Utils.getYoutubeLink(videoId),
|
||||
expectedResult = 'http://youtu.be/' + videoId;
|
||||
|
||||
expect(result).toBe(expectedResult);
|
||||
});
|
||||
|
||||
describe('Method: parseLink', function () {
|
||||
var resultDataDict = {
|
||||
'html5': {
|
||||
link: html5LinksList.mp4[0],
|
||||
resp: {
|
||||
mode: 'html5',
|
||||
video: html5FileName,
|
||||
type: 'mp4'
|
||||
}
|
||||
},
|
||||
'youtube': {
|
||||
link: ytLinksList[0],
|
||||
resp: {
|
||||
mode: 'youtube',
|
||||
video: videoId,
|
||||
type: 'youtube'
|
||||
}
|
||||
},
|
||||
'incorrect': {
|
||||
link: 'http://example.com',
|
||||
resp: {
|
||||
mode: 'incorrect'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.each(resultDataDict, function (mode, data) {
|
||||
it(mode, function () {
|
||||
var result = Utils.parseLink(data.link);
|
||||
|
||||
expect(result).toEqual(data.resp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Wrong arguments ', function () {
|
||||
|
||||
it('no arguments', function () {
|
||||
var result = Utils.parseLink();
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('wrong data type', function () {
|
||||
var result = Utils.parseLink(1);
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,363 +1,332 @@
|
||||
define(["jquery", "underscore", "jquery.ajaxQueue"], function($, _) {
|
||||
var Utils = (function () {
|
||||
var Storage = {};
|
||||
define(['jquery', 'underscore', 'jquery.ajaxQueue'], function($) {
|
||||
'use strict';
|
||||
return (function () {
|
||||
var Storage = {};
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Adds some data to the Storage object. If data with existent `data_id`
|
||||
* is added, nothing happens.
|
||||
*
|
||||
* @param {string} data_id Unique identifier for the data.
|
||||
* @param {any} data Data that should be stored.
|
||||
*
|
||||
* @returns {object} Object itself for chaining.
|
||||
*/
|
||||
Storage.set = function (data_id, data) {
|
||||
Storage[data_id] = data;
|
||||
/**
|
||||
* Adds some data to the Storage object. If data with existent `data_id`
|
||||
* is added, nothing happens.
|
||||
* @function
|
||||
* @param {String} data_id Unique identifier for the data.
|
||||
* @param {Any} data Data that should be stored.
|
||||
* @return {Object} Object itself for chaining.
|
||||
*/
|
||||
Storage.set = function (data_id, data) {
|
||||
Storage[data_id] = data;
|
||||
|
||||
return this;
|
||||
};
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Return data from the Storage object by identifier.
|
||||
*
|
||||
* @param {string} data_id Unique identifier of the data.
|
||||
*
|
||||
* @returns {any} Stored data.
|
||||
*/
|
||||
Storage.get= function (data_id) {
|
||||
/**
|
||||
* Return data from the Storage object by identifier.
|
||||
* @function
|
||||
* @param {String} data_id Unique identifier of the data.
|
||||
* @return {Any} Stored data.
|
||||
*/
|
||||
Storage.get= function (data_id) {
|
||||
|
||||
return Storage[data_id];
|
||||
};
|
||||
return Storage[data_id];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Deletes data from the Storage object by identifier.
|
||||
*
|
||||
* @param {string} data_id Unique identifier of the data.
|
||||
*
|
||||
* @returns {boolean} Boolean value that indicate if data is removed.
|
||||
*/
|
||||
Storage.remove = function (data_id) {
|
||||
/**
|
||||
* Deletes data from the Storage object by identifier.
|
||||
* @function
|
||||
* @param {String} data_id Unique identifier of the data.
|
||||
* @return {Boolean} Boolean value that indicate if data is removed.
|
||||
*/
|
||||
Storage.remove = function (data_id) {
|
||||
|
||||
return (delete Storage[data_id]);
|
||||
};
|
||||
return (delete Storage[data_id]);
|
||||
};
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Returns model from collection by 'field_name' property.
|
||||
*
|
||||
* @param {object} collection The model (CMS.Models.Metadata) containing
|
||||
* information about metadata setting editors.
|
||||
* @param {string} field_name Name of field that should be found.
|
||||
*
|
||||
* @returns {
|
||||
* object: when model exist,
|
||||
* undefined: when model doesn't exist.
|
||||
* }
|
||||
*/
|
||||
var _getField = function (collection, field_name) {
|
||||
var model;
|
||||
/**
|
||||
* Returns model from collection by 'field_name' property.
|
||||
* @function
|
||||
* @param {Object} collection The model (CMS.Models.Metadata) information
|
||||
* about metadata setting editors.
|
||||
* @param {String} field_name Name of field that should be found.
|
||||
* @return {
|
||||
* Object: When model exist.
|
||||
* Undefined: When model doesn't exist.
|
||||
* }
|
||||
*/
|
||||
var _getField = function (collection, field_name) {
|
||||
var model;
|
||||
|
||||
if (collection && field_name) {
|
||||
model = collection.findWhere({
|
||||
field_name: field_name
|
||||
});
|
||||
}
|
||||
if (collection && field_name) {
|
||||
model = collection.findWhere({
|
||||
field_name: field_name
|
||||
});
|
||||
}
|
||||
|
||||
return model;
|
||||
};
|
||||
return model;
|
||||
};
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Parses Youtube link and return video id.
|
||||
*
|
||||
* These are the types of URLs supported:
|
||||
* http://www.youtube.com/watch?v=OEoXaMPEzfM&feature=feedrec_grec_index
|
||||
* http://www.youtube.com/user/IngridMichaelsonVEVO#p/a/u/1/OEoXaMPEzfM
|
||||
* http://www.youtube.com/v/OEoXaMPEzfM?fs=1&hl=en_US&rel=0
|
||||
* http://www.youtube.com/watch?v=OEoXaMPEzfM#t=0m10s
|
||||
* http://www.youtube.com/embed/OEoXaMPEzfM?rel=0
|
||||
* http://www.youtube.com/watch?v=OEoXaMPEzfM
|
||||
* http://youtu.be/OEoXaMPEzfM
|
||||
*
|
||||
* @param {string} url Url that should be parsed.
|
||||
*
|
||||
* @returns {
|
||||
* string: Video Id,
|
||||
* undefined: when url has incorrect format or argument is
|
||||
* non-string, video id's length is not equal 11.
|
||||
* }
|
||||
*/
|
||||
var _youtubeParser = (function () {
|
||||
var cache = {};
|
||||
|
||||
return function (url) {
|
||||
if (typeof url !== 'string') {
|
||||
|
||||
return void(0);
|
||||
}
|
||||
|
||||
if (cache[url]) {
|
||||
return cache[url];
|
||||
}
|
||||
|
||||
var regExp = /.*(?:youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=)([^#\&\?]*).*/;
|
||||
var match = url.match(regExp);
|
||||
cache[url] = (match && match[1].length === 11) ? match[1] : void(0);
|
||||
|
||||
return cache[url];
|
||||
};
|
||||
}());
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Parses links with html5 video sources in mp4 or webm formats.
|
||||
*
|
||||
* @param {string} url Url that should be parsed.
|
||||
*
|
||||
* @returns {
|
||||
* object: Object with information about the video
|
||||
* (file name, video type),
|
||||
* undefined: when url has incorrect format or argument is
|
||||
* non-string.
|
||||
* }
|
||||
*/
|
||||
var _videoLinkParser = (function () {
|
||||
var cache = {};
|
||||
|
||||
return function (url) {
|
||||
if (typeof url !== 'string') {
|
||||
|
||||
return void(0);
|
||||
}
|
||||
|
||||
if (cache[url]) {
|
||||
return cache[url];
|
||||
}
|
||||
|
||||
var link = document.createElement('a'),
|
||||
match;
|
||||
|
||||
link.href = url;
|
||||
match = link.pathname
|
||||
.split('/')
|
||||
.pop()
|
||||
.match(/(.+)\.(mp4|webm)$/);
|
||||
|
||||
if (match) {
|
||||
cache[url] = {
|
||||
video: match[1],
|
||||
type: match[2]
|
||||
};
|
||||
}
|
||||
|
||||
return cache[url];
|
||||
};
|
||||
}());
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Facade function that parses html5 and youtube links.
|
||||
*
|
||||
* @param {string} url Url that should be parsed.
|
||||
*
|
||||
* @returns {
|
||||
* object: Object with information about the video:
|
||||
* {
|
||||
* mode: "youtube|html5|incorrect",
|
||||
* video: "file_name|youtube_id",
|
||||
* type: "youtube|mp4|webm"
|
||||
* },
|
||||
* undefined: when argument is non-string.
|
||||
* }
|
||||
*/
|
||||
var _linkParser = function (url) {
|
||||
var result;
|
||||
/**
|
||||
* Parses Youtube link and return video id.
|
||||
* @function
|
||||
* These are the types of URLs supported:
|
||||
* http://www.youtube.com/watch?v=OEoXaMPEzfM&feature=feedrec_grec_index
|
||||
* http://www.youtube.com/user/IngridMichaelsonVEVO#p/a/u/1/OEoXaMPEzfM
|
||||
* http://www.youtube.com/v/OEoXaMPEzfM?fs=1&hl=en_US&rel=0
|
||||
* http://www.youtube.com/watch?v=OEoXaMPEzfM#t=0m10s
|
||||
* http://www.youtube.com/embed/OEoXaMPEzfM?rel=0
|
||||
* http://www.youtube.com/watch?v=OEoXaMPEzfM
|
||||
* http://youtu.be/OEoXaMPEzfM
|
||||
* @param {String} url Url that should be parsed.
|
||||
* @return {
|
||||
* String: Video Id.
|
||||
* Undefined: When url has incorrect format or argument is
|
||||
* non-string, video id's length is not equal 11.
|
||||
* }
|
||||
*/
|
||||
var _youtubeParser = (function () {
|
||||
var cache = {},
|
||||
regExp = /(?:http|https|)(?:\:\/\/|)(?:www.|)(?:youtu\.be\/|youtube\.com(?:\/embed\/|\/v\/|\/watch\?v=|\/ytscreeningroom\?v=|\/feeds\/api\/videos\/|\/user\S*[^\w\-\s]|\S*[^\w\-\s]))([\w\-]{11})[a-z0-9;:@#?&%=+\/\$_.-]*/i;
|
||||
|
||||
return function (url) {
|
||||
if (typeof url !== 'string') {
|
||||
|
||||
return void(0);
|
||||
}
|
||||
|
||||
if (_youtubeParser(url)) {
|
||||
result = {
|
||||
mode: 'youtube',
|
||||
video: _youtubeParser(url),
|
||||
type: 'youtube'
|
||||
};
|
||||
} else if (_videoLinkParser(url)) {
|
||||
result = $.extend({mode: 'html5'}, _videoLinkParser(url));
|
||||
} else {
|
||||
result = {
|
||||
mode: 'incorrect'
|
||||
};
|
||||
if (cache[url]) {
|
||||
return cache[url];
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
var match = url.match(regExp);
|
||||
cache[url] = (match && match[1].length === 11) ?
|
||||
match[1] :
|
||||
void(0);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Returns short-hand youtube url.
|
||||
*
|
||||
* @param {string} video_id Youtube Video Id that will be added to the link.
|
||||
*
|
||||
* @returns {string} Short-hand Youtube url.
|
||||
*
|
||||
* @example
|
||||
* _getYoutubeLink('OEoXaMPEzfM'); => 'http://youtu.be/OEoXaMPEzfM'
|
||||
*/
|
||||
var _getYoutubeLink = function (video_id) {
|
||||
return 'http://youtu.be/' + video_id;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Returns list of objects with information about the passed links.
|
||||
*
|
||||
* @param {array} links List of links that will be processed.
|
||||
*
|
||||
* @returns {array} List of objects.
|
||||
*
|
||||
* @examples
|
||||
* var links = [
|
||||
* 'http://youtu.be/OEoXaMPEzfM',
|
||||
* 'video_name.mp4',
|
||||
* 'video_name.webm'
|
||||
* ]
|
||||
*
|
||||
* _getVideoList(links); // =>
|
||||
* [
|
||||
* {mode: `youtube`, type: `youtube`, ...},
|
||||
* {mode: `html5`, type: `mp4`, ...},
|
||||
* {mode: `html5`, type: `webm`, ...}
|
||||
* ]
|
||||
*
|
||||
*/
|
||||
var _getVideoList = function (links) {
|
||||
if ($.isArray(links)) {
|
||||
var arr = [],
|
||||
data;
|
||||
|
||||
for (var i = 0, len = links.length; i < len; i += 1) {
|
||||
data = _linkParser(links[i]);
|
||||
|
||||
if (data.mode !== 'incorrect') {
|
||||
arr.push(data);
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Synchronizes 2 Backbone collections by 'field_name' property.
|
||||
*
|
||||
* @param {object} fromCollection Collection with which synchronization
|
||||
* will happens.
|
||||
* @param {object} toCollection Collection which will synchronized.
|
||||
*
|
||||
*/
|
||||
var _syncCollections = function (fromCollection, toCollection) {
|
||||
fromCollection.each(function (m) {
|
||||
var model = toCollection.findWhere({
|
||||
field_name: m.getFieldName()
|
||||
});
|
||||
|
||||
if (model) {
|
||||
model.setValue(m.getDisplayValue());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Sends Ajax requests in appropriate format.
|
||||
*
|
||||
* @param {string} action Action that will be invoked on server. Is a part
|
||||
* of url.
|
||||
* @param {string} component_locator the locator of component.
|
||||
* @param {array} videoList List of object with information about inserted
|
||||
* urls.
|
||||
* @param {object} extraParams Extra parameters that can be send to the
|
||||
* server
|
||||
*
|
||||
* @returns {object} XMLHttpRequest object. Using this object, we can attach
|
||||
* callbacks to AJAX request events (for example on 'done', 'fail',
|
||||
* etc.).
|
||||
*/
|
||||
var _command = (function () {
|
||||
// We will store the XMLHttpRequest object that $.ajax() function
|
||||
// returns, to abort an ongoing AJAX request (if necessary) upon
|
||||
// subsequent invocations of _command() function.
|
||||
//
|
||||
// A new AJAX request will be made on each invocation of the
|
||||
// _command() function.
|
||||
var xhr = null;
|
||||
|
||||
return function (action, component_locator, videoList, extraParams) {
|
||||
var params, data;
|
||||
|
||||
if (extraParams) {
|
||||
if ($.isPlainObject(extraParams)) {
|
||||
params = extraParams;
|
||||
} else {
|
||||
params = {params: extraParams};
|
||||
}
|
||||
}
|
||||
|
||||
data = $.extend(
|
||||
{ locator: component_locator },
|
||||
{ videos: videoList },
|
||||
params
|
||||
);
|
||||
|
||||
xhr = $.ajaxQueue({
|
||||
url: '/transcripts/' + action,
|
||||
data: { data: JSON.stringify(data) },
|
||||
notifyOnError: false,
|
||||
type: 'get'
|
||||
});
|
||||
|
||||
return xhr;
|
||||
};
|
||||
}());
|
||||
|
||||
return {
|
||||
getField: _getField,
|
||||
parseYoutubeLink: _youtubeParser,
|
||||
parseHTML5Link: _videoLinkParser,
|
||||
parseLink: _linkParser,
|
||||
getYoutubeLink: _getYoutubeLink,
|
||||
syncCollections: _syncCollections,
|
||||
command: _command,
|
||||
getVideoList: _getVideoList,
|
||||
Storage: {
|
||||
set: Storage.set,
|
||||
get: Storage.get,
|
||||
remove: Storage.remove
|
||||
}
|
||||
return cache[url];
|
||||
};
|
||||
}());
|
||||
|
||||
return Utils;
|
||||
/**
|
||||
* Parses links with html5 video sources in mp4 or webm formats.
|
||||
* @function
|
||||
* @param {String} url Url that should be parsed.
|
||||
* @return {
|
||||
* object: Object with information about the video
|
||||
* (file name, video type),
|
||||
* undefined: when url has incorrect format or argument is
|
||||
* non-string.
|
||||
* }
|
||||
*/
|
||||
var _videoLinkParser = (function () {
|
||||
var cache = {};
|
||||
|
||||
return function (url) {
|
||||
if (typeof url !== 'string') {
|
||||
|
||||
return void(0);
|
||||
}
|
||||
|
||||
if (cache[url]) {
|
||||
return cache[url];
|
||||
}
|
||||
|
||||
var link = document.createElement('a'),
|
||||
match;
|
||||
|
||||
link.href = url;
|
||||
match = link.pathname
|
||||
.split('/')
|
||||
.pop()
|
||||
.match(/(.+)\.(mp?4v?|webm)$/);
|
||||
|
||||
if (match) {
|
||||
cache[url] = {
|
||||
video: match[1],
|
||||
type: match[2]
|
||||
};
|
||||
} /*else {
|
||||
cache[url] = {
|
||||
video: link.pathname
|
||||
.split('/')
|
||||
.pop(),
|
||||
type: 'other'
|
||||
};
|
||||
}*/
|
||||
|
||||
return cache[url];
|
||||
};
|
||||
}());
|
||||
|
||||
/**
|
||||
* Facade function that parses html5 and youtube links.
|
||||
* @function
|
||||
* @param {String} url Url that should be parsed.
|
||||
* @return {
|
||||
* object: Object with information about the video:
|
||||
* {
|
||||
* mode: "youtube|html5|incorrect",
|
||||
* video: "file_name|youtube_id",
|
||||
* type: "youtube|mp4|webm"
|
||||
* },
|
||||
* undefined: when argument is non-string.
|
||||
* }
|
||||
*/
|
||||
var _linkParser = function (url) {
|
||||
var result;
|
||||
|
||||
if (typeof url !== 'string') {
|
||||
|
||||
return void(0);
|
||||
}
|
||||
|
||||
if (_youtubeParser(url)) {
|
||||
result = {
|
||||
mode: 'youtube',
|
||||
video: _youtubeParser(url),
|
||||
type: 'youtube'
|
||||
};
|
||||
} else if (_videoLinkParser(url)) {
|
||||
result = $.extend({mode: 'html5'}, _videoLinkParser(url));
|
||||
} else {
|
||||
result = {
|
||||
mode: 'incorrect'
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns short-hand youtube url.
|
||||
* @function
|
||||
* @param {string} video_id Youtube Video Id that will be added to the
|
||||
* link.
|
||||
* @return {string} Short-hand Youtube url.
|
||||
* @examples
|
||||
* _getYoutubeLink('OEoXaMPEzfM'); => 'http://youtu.be/OEoXaMPEzfM'
|
||||
*/
|
||||
var _getYoutubeLink = function (video_id) {
|
||||
return 'http://youtu.be/' + video_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns list of objects with information about the passed links.
|
||||
* @function
|
||||
* @param {array} links List of links that will be processed.
|
||||
* @returns {array} List of objects.
|
||||
* @examples
|
||||
* var links = [
|
||||
* 'http://youtu.be/OEoXaMPEzfM',
|
||||
* 'video_name.mp4',
|
||||
* 'video_name.webm'
|
||||
* ]
|
||||
*
|
||||
* _getVideoList(links); // =>
|
||||
* [
|
||||
* {mode: `youtube`, type: `youtube`, ...},
|
||||
* {mode: `html5`, type: `mp4`, ...},
|
||||
* {mode: `html5`, type: `webm`, ...}
|
||||
* ]
|
||||
*/
|
||||
var _getVideoList = function (links) {
|
||||
if ($.isArray(links)) {
|
||||
var arr = [],
|
||||
data;
|
||||
|
||||
for (var i = 0, len = links.length; i < len; i += 1) {
|
||||
data = _linkParser(links[i]);
|
||||
|
||||
if (data.mode !== 'incorrect') {
|
||||
arr.push(data);
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Synchronizes 2 Backbone collections by 'field_name' property.
|
||||
* @function
|
||||
* @param {Object} fromCollection Collection with which synchronization will
|
||||
* happens.
|
||||
* @param {Object} toCollection Collection which will synchronized.
|
||||
*/
|
||||
var _syncCollections = function (fromCollection, toCollection) {
|
||||
fromCollection.each(function (m) {
|
||||
var model = toCollection.findWhere({
|
||||
field_name: m.getFieldName()
|
||||
});
|
||||
|
||||
if (model) {
|
||||
model.setValue(m.getDisplayValue());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends Ajax requests in appropriate format.
|
||||
* @function
|
||||
* @param {String} action Action that will be invoked on server.
|
||||
* @param {String} component_locator the locator of component.
|
||||
* @param {Array} videoList List of object with information about inserted
|
||||
* urls.
|
||||
* @param {Object} extraParams Extra parameters that can be send to the
|
||||
* server.
|
||||
* @return {Object} XMLHttpRequest object. Using this object, we can
|
||||
* attach callbacks to AJAX request events (for example on 'done',
|
||||
* 'fail', etc.).
|
||||
*/
|
||||
var _command = (function () {
|
||||
// We will store the XMLHttpRequest object that $.ajax() function
|
||||
// returns, to abort an ongoing AJAX request (if necessary) upon
|
||||
// subsequent invocations of _command() function.
|
||||
//
|
||||
// A new AJAX request will be made on each invocation of the
|
||||
// _command() function.
|
||||
var xhr = null;
|
||||
|
||||
return function (action, locator, videoList, extraParams) {
|
||||
var params, data;
|
||||
|
||||
if (extraParams) {
|
||||
if ($.isPlainObject(extraParams)) {
|
||||
params = extraParams;
|
||||
} else {
|
||||
params = {params: extraParams};
|
||||
}
|
||||
}
|
||||
|
||||
data = $.extend(
|
||||
{ locator: locator },
|
||||
{ videos: videoList },
|
||||
params
|
||||
);
|
||||
|
||||
xhr = $.ajaxQueue({
|
||||
url: '/transcripts/' + action,
|
||||
data: { data: JSON.stringify(data) },
|
||||
notifyOnError: false,
|
||||
type: 'get'
|
||||
});
|
||||
|
||||
return xhr;
|
||||
};
|
||||
}());
|
||||
|
||||
return {
|
||||
getField: _getField,
|
||||
parseYoutubeLink: _youtubeParser,
|
||||
parseHTML5Link: _videoLinkParser,
|
||||
parseLink: _linkParser,
|
||||
getYoutubeLink: _getYoutubeLink,
|
||||
syncCollections: _syncCollections,
|
||||
command: _command,
|
||||
getVideoList: _getVideoList,
|
||||
Storage: {
|
||||
set: Storage.set,
|
||||
get: Storage.get,
|
||||
remove: Storage.remove
|
||||
}
|
||||
};
|
||||
}());
|
||||
});
|
||||
|
||||
@@ -37,6 +37,7 @@ from .video_handlers import VideoStudentViewHandlers, VideoStudioViewHandlers
|
||||
|
||||
from urlparse import urlparse
|
||||
|
||||
|
||||
def get_ext(filename):
|
||||
# Prevent incorrectly parsing urls like 'http://abc.com/path/video.mp4?xxxx'.
|
||||
path = urlparse(filename).path
|
||||
|
||||
Reference in New Issue
Block a user