Adding HTML5Video class and modifying coffee sources to use it when video sources are provided instead of YouTube IDs.
This commit is contained in:
3
common/lib/xmodule/xmodule/js/src/.gitignore
vendored
3
common/lib/xmodule/xmodule/js/src/.gitignore
vendored
@@ -1,2 +1 @@
|
||||
*.js
|
||||
|
||||
# Please do not ignore *.js files. Some xmodules are written in JS.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class @Video
|
||||
class @VideoAlpha
|
||||
constructor: (element) ->
|
||||
@el = $(element).find('.video')
|
||||
@id = @el.attr('id').replace(/video_/, '')
|
||||
@@ -9,40 +9,77 @@ class @Video
|
||||
@show_captions = @el.data('show-captions') == "true"
|
||||
window.player = null
|
||||
@el = $("#video_#{@id}")
|
||||
@parseVideos @el.data('streams')
|
||||
@fetchMetadata()
|
||||
@parseSpeed()
|
||||
|
||||
if @parseVideos(@el.data("streams")) is true
|
||||
@videoType = "youtube"
|
||||
@fetchMetadata()
|
||||
@parseSpeed()
|
||||
else
|
||||
@videoType = "html5"
|
||||
@parseVideoSources @el.data("mp4-source"), @el.data("webm-source"), @el.data("ogg-source")
|
||||
@speeds = ["0.75", "1.0", "1.25", "1.5"]
|
||||
@setSpeed($.cookie('video_speed'))
|
||||
|
||||
$("#video_#{@id}").data('video', this).addClass('video-load-complete')
|
||||
|
||||
@hide_captions = $.cookie('hide_captions') == 'true'
|
||||
|
||||
if YT.Player
|
||||
if ((@videoType is "youtube") and (YT.Player)) or ((@videoType is "html5") and (HTML5Video.Player))
|
||||
console.log 'one'
|
||||
@embed()
|
||||
else
|
||||
window.onYouTubePlayerAPIReady = =>
|
||||
@el.each ->
|
||||
$(this).data('video').embed()
|
||||
console.log 'two'
|
||||
if @videoType is "youtube"
|
||||
console.log 'three'
|
||||
window.onYouTubePlayerAPIReady = ->
|
||||
_this.embed()
|
||||
else if @videoType is "html5"
|
||||
console.log 'four'
|
||||
console.log @videoType
|
||||
console.log HTML5Video.Player
|
||||
window.onHTML5PlayerAPIReady = ->
|
||||
_this.embed()
|
||||
|
||||
youtubeId: (speed)->
|
||||
@videos[speed || @speed]
|
||||
|
||||
parseVideos: (videos) ->
|
||||
VideoAlpha::parseVideos = (videos) ->
|
||||
return false if (typeof videos isnt "string") or (videos.length is 0)
|
||||
|
||||
console.log 'We got this far'
|
||||
console.log videos
|
||||
|
||||
@videos = {}
|
||||
$.each videos.split(/,/), (index, video) =>
|
||||
_this = this
|
||||
$.each videos.split(/,/), (index, video) ->
|
||||
speed = undefined
|
||||
video = video.split(/:/)
|
||||
speed = parseFloat(video[0]).toFixed(2).replace /\.00$/, '.0'
|
||||
@videos[speed] = video[1]
|
||||
speed = parseFloat(video[0]).toFixed(2).replace(/\.00$/, ".0")
|
||||
_this.videos[speed] = video[1]
|
||||
true
|
||||
|
||||
VideoAlpha::parseVideoSources = (mp4Source, webmSource, oggSource) ->
|
||||
@html5Sources =
|
||||
mp4: null
|
||||
webm: null
|
||||
ogg: null
|
||||
|
||||
@html5Sources.mp4 = mp4Source if (typeof mp4Source is "string") and (mp4Source.length > 0)
|
||||
@html5Sources.webm = webmSource if (typeof webmSource is "string") and (webmSource.length > 0)
|
||||
@html5Sources.ogg = oggSource if (typeof oggSource is "string") and (oggSource.length > 0)
|
||||
|
||||
parseSpeed: ->
|
||||
@setSpeed($.cookie('video_speed'))
|
||||
@speeds = ($.map @videos, (url, speed) -> speed).sort()
|
||||
@setSpeed($.cookie('video_speed'))
|
||||
|
||||
setSpeed: (newSpeed) ->
|
||||
if @videos[newSpeed] != undefined
|
||||
VideoAlpha::setSpeed = (newSpeed) ->
|
||||
if @speeds.indexOf(newSpeed) isnt -1
|
||||
@speed = newSpeed
|
||||
$.cookie('video_speed', "#{newSpeed}", expires: 3650, path: '/')
|
||||
$.cookie "video_speed", "" + newSpeed,
|
||||
expires: 3650
|
||||
path: "/"
|
||||
else
|
||||
@speed = '1.0'
|
||||
@speed = "1.0"
|
||||
|
||||
embed: ->
|
||||
@player = new VideoPlayer video: this
|
||||
@@ -55,9 +92,14 @@ class @Video
|
||||
getDuration: ->
|
||||
@metadata[@youtubeId()].duration
|
||||
|
||||
log: (eventName) ->
|
||||
Logger.log eventName,
|
||||
VideoAlpha::log = (eventName) ->
|
||||
logInfo =
|
||||
id: @id
|
||||
code: @youtubeId()
|
||||
currentTime: @player.currentTime
|
||||
speed: @speed
|
||||
|
||||
if @videoType is "youtube"
|
||||
logInfo.code = @youtubeId()
|
||||
else logInfo.code = "html5" if @videoType is "html5"
|
||||
Logger.log eventName, logInfo
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
console.log('We are in "html5_video.js" script.');
|
||||
|
||||
this.HTML5Video = (function () {
|
||||
var HTML5Video = {};
|
||||
|
||||
HTML5Video.Player = (function () {
|
||||
|
||||
/*
|
||||
* Constructor function for HTML5 Video player.
|
||||
*
|
||||
* @el - A DOM element where the HTML5 player will be inserted (as returned by jQuery(selector) function),
|
||||
* or a selector string which will be used to select an element. This is a required parameter.
|
||||
*
|
||||
* @config - An object whose properties will be used as configuration options for the HTML5 video
|
||||
* player. This is an optional parameter. In the case if this parameter is missing, or some of the config
|
||||
* object's properties are missing, defaults will be used. The available options (and their defaults) are as
|
||||
* follows:
|
||||
*
|
||||
* config = {
|
||||
* 'width': 640,
|
||||
*
|
||||
* 'height': 390,
|
||||
*
|
||||
* 'videoSources': null, // An object of with properties being video sources. The property name is the
|
||||
* // video format of the source. Supported video formats are: 'mp4', 'webm', and
|
||||
* // 'ogg'. By default videoSources property is null. This means that the
|
||||
* // player will initialize, and not play anything. If you do not provide a
|
||||
* // 'videoSource' option, you can later call loadVideoBySource() method to load
|
||||
* // a video and start playing it.
|
||||
*
|
||||
* 'playerVars': { // Object's properties identify player parameters.
|
||||
*
|
||||
* 'controls': 1, // Possible values: 0, or 1. Value of 1 will enable the default browser video
|
||||
* // controls.
|
||||
*
|
||||
* 'start': null, // Possible values: positive integer. Position from which to start playing the
|
||||
* // video. Measured in seconds. If value is null, or 'start' property is not
|
||||
* // specified, the video will start playing from the beginning.
|
||||
*
|
||||
* 'end': null // Possible values: positive integer. Position when to stop playing the
|
||||
* // video. Measured in seconds. If value is null, or 'end' property is not
|
||||
* // specified, the video will end playing at the end.
|
||||
*
|
||||
* },
|
||||
*
|
||||
* 'events': { // Object's properties identify the events that the API fires, and the
|
||||
* // functions (event listeners) that the API will call when those events occur.
|
||||
* // If value is null, or property is not specified, then no callback will be
|
||||
* // called for that event.
|
||||
*
|
||||
* 'onReady': null,
|
||||
* 'onStateChange': null,
|
||||
* 'onPlaybackQualityChange': null
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
function Player(el, config) {
|
||||
console.log('We are inside HTML5Video.Player constructor.');
|
||||
|
||||
if (typeof el === 'string') {
|
||||
this.el = $(el);
|
||||
} else if ($.isPlainObject(el) === true) {
|
||||
this.el = el;
|
||||
} else {
|
||||
// Error. el parameter is required.
|
||||
|
||||
// TODO: Make sure that nothing breaks if one of the methods available via this object's prototype
|
||||
// is called after we return.
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('We got a proper DOM element.');
|
||||
|
||||
if ($.isPlainObject(config) === true) {
|
||||
this.config = config;
|
||||
} else {
|
||||
this.config = {
|
||||
'width': 640,
|
||||
'height': 390,
|
||||
'videoSource': '',
|
||||
'playerVars': {
|
||||
'controls': 1,
|
||||
'start': null,
|
||||
'end': null
|
||||
},
|
||||
'events': {
|
||||
'onReady': null,
|
||||
'onStateChange': null,
|
||||
'onPlaybackQualityChange': null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
console.log('The config is:');
|
||||
console.log(this.config);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the quality of the video. Possible return values are (type String)
|
||||
*
|
||||
* highres
|
||||
* hd1080
|
||||
* hd720
|
||||
* large
|
||||
* medium
|
||||
* small
|
||||
*
|
||||
* It returns undefined if there is no current video.
|
||||
*
|
||||
* If there is a current video, but it is impossible to determine it's quality, the function will return
|
||||
* 'medium'.
|
||||
*/
|
||||
Player.prototype.getPlayBackQuality = function () {
|
||||
if (this.config.videoSource === '') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// TODO: Figure out if we can get the quality of a video from a source (when it is loaded by the browser).
|
||||
|
||||
return 'medium';
|
||||
};
|
||||
|
||||
/*
|
||||
* The original YouTube API function player.setPlayBackQuality changed (if it was possible) the quality of the
|
||||
* played video. In our case, this function will not do anything because we can't change the quality of HTML5
|
||||
* video since we only get one source of video with one quality.
|
||||
*/
|
||||
Player.prototype.setPlayBackQuality = function (value) {
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.pauseVideo = function () {
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.sekkTo = function () {
|
||||
|
||||
};
|
||||
|
||||
// YouTube API has player.loadVideoById, but since we are working with a video source, we will rename this
|
||||
// function accordingly.
|
||||
Player.prototype.loadVideoBySource = function () {
|
||||
|
||||
};
|
||||
|
||||
// YouTube API has player.cueVideoById, but since we are working with a video source, we will rename this
|
||||
// function accordingly.
|
||||
Player.prototype.cueVideoBySource = function () {
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.setVolume = function () {
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.getCurrentTime = function () {
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.playVideo = function () {
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.getPlayerState = function () {
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.pauseVideo = function () {
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.setVolume = function () {
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.getVolume = function () {
|
||||
|
||||
};
|
||||
|
||||
return Player;
|
||||
}());
|
||||
|
||||
HTML5Video.PlayerState = {
|
||||
'UNSTARTED': -1,
|
||||
'ENDED': 0,
|
||||
'PLAYING': 1,
|
||||
'PAUSED': 2,
|
||||
'BUFFERING': 3,
|
||||
'CUED': 5
|
||||
};
|
||||
|
||||
return HTML5Video;
|
||||
}());
|
||||
|
||||
console.log(HTML5Video);
|
||||
@@ -1,7 +1,8 @@
|
||||
class @VideoPlayer extends Subview
|
||||
initialize: ->
|
||||
# Define a missing constant of Youtube API
|
||||
YT.PlayerState.UNSTARTED = -1
|
||||
if @video.videoType is 'youtube'
|
||||
# Define a missing constant of Youtube API
|
||||
YT.PlayerState.UNSTARTED = -1
|
||||
|
||||
@currentTime = 0
|
||||
@el = $("#video_#{@video.id}")
|
||||
@@ -25,6 +26,7 @@ class @VideoPlayer extends Subview
|
||||
@toggleFullScreen(event)
|
||||
|
||||
render: ->
|
||||
console.log '1.1'
|
||||
@control = new VideoControl el: @$('.video-controls')
|
||||
@qualityControl = new VideoQualityControl el: @$('.secondary-controls')
|
||||
@caption = new VideoCaption
|
||||
@@ -34,6 +36,7 @@ class @VideoPlayer extends Subview
|
||||
captionAssetPath: @video.caption_asset_path
|
||||
unless onTouchBasedDevice()
|
||||
@volumeControl = new VideoVolumeControl el: @$('.secondary-controls')
|
||||
console.log '1.2'
|
||||
@speedControl = new VideoSpeedControl el: @$('.secondary-controls'), speeds: @video.speeds, currentSpeed: @currentSpeed()
|
||||
@progressSlider = new VideoProgressSlider el: @$('.slider')
|
||||
@playerVars =
|
||||
@@ -43,20 +46,31 @@ class @VideoPlayer extends Subview
|
||||
showinfo: 0
|
||||
enablejsapi: 1
|
||||
modestbranding: 1
|
||||
console.log '1.3'
|
||||
if @video.start
|
||||
@playerVars.start = @video.start
|
||||
@playerVars.wmode = 'window'
|
||||
if @video.end
|
||||
# work in AS3, not HMLT5. but iframe use AS3
|
||||
@playerVars.end = @video.end
|
||||
console.log '1.4'
|
||||
|
||||
@player = new YT.Player @video.id,
|
||||
playerVars: @playerVars
|
||||
videoId: @video.youtubeId()
|
||||
events:
|
||||
onReady: @onReady
|
||||
onStateChange: @onStateChange
|
||||
onPlaybackQualityChange: @onPlaybackQualityChange
|
||||
if @video.videoType is 'html5'
|
||||
@player = new HTML5Video.Player @video.id,
|
||||
playerVars: @playerVars,
|
||||
videoSources: @video.html5Sources,
|
||||
events:
|
||||
onReady: @onReady
|
||||
onStateChange: @onStateChange
|
||||
onPlaybackQualityChange: @onPlaybackQualityChange
|
||||
else if @video.videoType is 'youtube'
|
||||
@player = new YT.Player @video.id,
|
||||
playerVars: @playerVars
|
||||
videoId: @video.youtubeId()
|
||||
events:
|
||||
onReady: @onReady
|
||||
onStateChange: @onStateChange
|
||||
onPlaybackQualityChange: @onPlaybackQualityChange
|
||||
@caption.hideCaptions(@['video'].hide_captions)
|
||||
|
||||
addToolTip: ->
|
||||
|
||||
@@ -19,11 +19,13 @@ import time
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VideoModule(XModule):
|
||||
class VideoAlphaModule(XModule):
|
||||
video_time = 0
|
||||
icon_class = 'video'
|
||||
|
||||
js = {'coffee':
|
||||
js = {
|
||||
'js': [resource_string(__name__, 'js/src/videoalpha/display/html5_video.js')],
|
||||
'coffee':
|
||||
[resource_string(__name__, 'js/src/time.coffee'),
|
||||
resource_string(__name__, 'js/src/videoalpha/display.coffee')] +
|
||||
[resource_string(__name__, 'js/src/videoalpha/display/' + filename)
|
||||
@@ -31,7 +33,7 @@ class VideoModule(XModule):
|
||||
in sorted(resource_listdir(__name__, 'js/src/videoalpha/display'))
|
||||
if filename.endswith('.coffee')]}
|
||||
css = {'scss': [resource_string(__name__, 'css/videoalpha/display.scss')]}
|
||||
js_module_name = "Video"
|
||||
js_module_name = "VideoAlpha"
|
||||
|
||||
def __init__(self, system, location, definition, descriptor,
|
||||
instance_state=None, shared_state=None, **kwargs):
|
||||
@@ -145,6 +147,6 @@ class VideoModule(XModule):
|
||||
|
||||
|
||||
class VideoAlphaDescriptor(RawDescriptor):
|
||||
module_class = VideoModule
|
||||
module_class = VideoAlphaModule
|
||||
stores_state = True
|
||||
template_dir_name = "videoalpha"
|
||||
|
||||
@@ -2,11 +2,24 @@
|
||||
<h2> ${display_name} </h2>
|
||||
% endif
|
||||
|
||||
<!-- data-streams="0.75:WL7anegEjsU,1.0:NUmLa2vBBLo,1.25:TygItMr4wY4,1.5:kctQ6liQdAE"-->
|
||||
|
||||
%if settings.MITX_FEATURES['STUB_VIDEO_FOR_TESTING']:
|
||||
<div id="stub_out_video_for_testing"></div>
|
||||
%else:
|
||||
<div id="video_${id}" class="video" data-streams="${streams}" data-caption-data-dir="${data_dir}" data-show-captions="${show_captions}" data-start="${start}" data-end="${end}" data-caption-asset-path="${caption_asset_path}">
|
||||
<div
|
||||
id="video_${id}"
|
||||
class="video"
|
||||
data-streams=""
|
||||
data-mp4-source="http://clips.vorwaerts-gmbh.de/VfE_html5.mp4"
|
||||
data-webm-source="http://clips.vorwaerts-gmbh.de/VfE_html5.webm"
|
||||
data-ogg-source="http://clips.vorwaerts-gmbh.de/VfE_html5.ogv"
|
||||
data-caption-data-dir="${data_dir}"
|
||||
data-show-captions="${show_captions}"
|
||||
data-start="${start}"
|
||||
data-end="${end}"
|
||||
data-caption-asset-path="${caption_asset_path}"
|
||||
>
|
||||
<div class="tc-wrapper">
|
||||
<article class="video-wrapper">
|
||||
<section class="video-player">
|
||||
|
||||
Reference in New Issue
Block a user