Adding HTML5Video class and modifying coffee sources to use it when video sources are provided instead of YouTube IDs.

This commit is contained in:
Valera Rozuvan
2013-01-30 18:06:27 +02:00
parent 156da20c35
commit 78e9692aaa
6 changed files with 301 additions and 35 deletions

View File

@@ -1,2 +1 @@
*.js
# Please do not ignore *.js files. Some xmodules are written in JS.

View File

@@ -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

View File

@@ -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);

View File

@@ -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: ->

View File

@@ -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"

View File

@@ -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">