Commit baf6bbe3 by Valera Rozuvan

Finalized HTML5 YouTube player inbrowser speed changes.

parent 143217d6
......@@ -25,7 +25,7 @@ class @VideoAlpha
"1.0": sub
"1.25": sub
"1.5": sub
@setSpeed($.cookie('video_speed'))
@setSpeed $.cookie('video_speed')
$("#video_#{@id}").data('video', this).addClass('video-load-complete')
if @show_captions is true
@hide_captions = $.cookie('hide_captions') == 'true'
......@@ -47,7 +47,7 @@ class @VideoAlpha
youtubeId: (speed)->
@videos[speed || @speed]
VideoAlpha::parseVideos = (videos) ->
parseVideos: (videos)->
return false if (typeof videos isnt "string") or (videos.length is 0)
@videos = {}
_this = this
......@@ -58,7 +58,7 @@ class @VideoAlpha
_this.videos[speed] = video[1]
true
VideoAlpha::parseVideoSources = (mp4Source, webmSource, oggSource) ->
parseVideoSources: (mp4Source, webmSource, oggSource)->
@html5Sources =
mp4: null
webm: null
......@@ -69,9 +69,9 @@ class @VideoAlpha
parseSpeed: ->
@speeds = ($.map @videos, (url, speed) -> speed).sort()
@setSpeed($.cookie('video_speed'))
@setSpeed $.cookie('video_speed')
VideoAlpha::setSpeed = (newSpeed) ->
setSpeed: (newSpeed)->
if @speeds.indexOf(newSpeed) isnt -1
@speed = newSpeed
$.cookie "video_speed", "" + newSpeed,
......@@ -91,7 +91,7 @@ class @VideoAlpha
getDuration: ->
@metadata[@youtubeId()].duration
VideoAlpha::log = (eventName) ->
log: (eventName)->
logInfo =
id: @id
code: @youtubeId()
......
this.HTML5Video = (function () {
var HTML5Video = {};
var HTML5Video;
HTML5Video = {};
HTML5Video.Player = (function () {
Player.prototype.callStateChangeCallback = function () {
if ($.isFunction(this.config.events.onStateChange) === true) {
this.config.events.onStateChange({
'data': this.playerState
});
}
};
Player.prototype.pauseVideo = function () {
this.video.pause();
};
Player.prototype.seekTo = function (value) {
if ((typeof value === 'number') && (value <= this.video.duration) && (value >= 0)) {
this.start = 0;
this.end = this.video.duration;
this.video.currentTime = value;
}
};
Player.prototype.setVolume = function (value) {
if ((typeof value === 'number') && (value <= 100) && (value >= 0)) {
this.video.volume = value * 0.01;
}
};
Player.prototype.getCurrentTime = function () {
return this.video.currentTime;
};
Player.prototype.playVideo = function () {
this.video.play();
};
Player.prototype.getPlayerState = function () {
return this.playerState;
};
Player.prototype.getVolume = function () {
return this.video.volume;
};
Player.prototype.getDuration = function () {
return this.video.duration;
};
Player.prototype.setPlaybackRate = function (value) {
var newSpeed;
newSpeed = parseFloat(value);
if (isFinite(newSpeed) === true) {
this.video.playbackRate = value;
}
};
Player.prototype.getAvailablePlaybackRates = function () {
return [0.75, 1.0, 1.25, 1.5];
};
return Player;
/*
* Constructor function for HTML5 Video player.
......@@ -16,17 +80,14 @@ this.HTML5Video = (function () {
*
* config = {
*
* 'videoSources': {}, // An object of with properties being video sources. The property name is the
* 'videoSources': {}, // An object 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.
* // 'ogg'.
*
* 'playerVars': { // Object's properties identify player parameters. *
* '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.
* 'playerVars': { // Object's properties identify player parameters.
* 'start': 0, // Possible values: positive integer. Position from which to start playing the
* // video. Measured in seconds. If value is non-numeric, 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
......@@ -47,51 +108,44 @@ this.HTML5Video = (function () {
function Player(el, config) {
var sourceStr, _this;
// If el is string, we assume it is an ID of a DOM element. Get the element, and check that the ID
// really belongs to an element. If we didn't get a DOM element, return. At this stage, nothing will
// break because other parts of the video player are waiting for 'onReady' callback to be called.
if (typeof el === 'string') {
this.el = $(el);
if (this.el.length === 0) {
return;
}
} else if (el instanceof jQuery) {
this.el = el;
} else {
// Error. Parameter el does not have a recognized type.
// TODO: Make sure that nothing breaks if one of the methods available via this object's prototype
// is called after we return.
return;
}
// A simple test to see that the 'config' is a normal object.
if ($.isPlainObject(config) === true) {
this.config = config;
} else {
// Error. Parameter config does not have a recognized type.
// TODO: Make sure that nothing breaks if one of the methods available via this object's prototype
// is called after we return.
return;
}
this.start = 0;
this.end = null;
if (config.hasOwnProperty('playerVars') === true) {
this.start = parseFloat(config.playerVars.start);
if ((isFinite(this.start) !== true) || (this.start < 0)) {
this.start = 0;
}
this.end = parseFloat(config.playerVars.end);
if ((isFinite(this.end) !== true) || (this.end < this.start)) {
this.end = null;
}
// We should have at least one video source. Otherwise there is no point to continue.
if (config.hasOwnProperty('videoSources') === false) {
return;
}
// From the start, all sources are empty. We will populate this object below.
sourceStr = {
'mp4': ' ',
'webm': ' ',
'ogg': ' '
};
// Will be used in inner functions to point to the current object.
_this = this;
// Create HTML markup for individual sources of the HTML5 <video> element.
$.each(sourceStr, function (videoType, videoSource) {
if (
(_this.config.videoSources.hasOwnProperty(videoType) === true) &&
......@@ -106,8 +160,27 @@ this.HTML5Video = (function () {
}
});
this.playerState = HTML5Video.PlayerState.UNSTARTED;
// We should have at least one video source. Otherwise there is no point to continue.
if ((sourceStr.mp4 === ' ') && (sourceStr.webm === ' ') && (sourceStr.ogg === ' ')) {
return;
}
// Determine the starting and ending time for the video.
this.start = 0;
this.end = null;
if (config.hasOwnProperty('playerVars') === true) {
this.start = parseFloat(config.playerVars.start);
if ((isFinite(this.start) !== true) || (this.start < 0)) {
this.start = 0;
}
this.end = parseFloat(config.playerVars.end);
if ((isFinite(this.end) !== true) || (this.end < this.start)) {
this.end = null;
}
}
// Create HTML markup for the <video> element, populating it with sources from previous step.
this.videoEl = $(
'<video style="width: 100%;">' +
sourceStr.mp4 +
......@@ -116,30 +189,32 @@ this.HTML5Video = (function () {
'</video>'
);
// Get the DOM element (to access the HTML5 video API), and set the player state to UNSTARTED.
// The player state is used by other parts of the VideoPlayer to detrermine what the video is
// currently doing.
this.video = this.videoEl[0];
this.playerState = HTML5Video.PlayerState.UNSTARTED;
// Attach a 'click' event on the <video> element. It will cause the video to pause/play.
this.videoEl.on('click', function (event) {
if (_this.playerState === HTML5Video.PlayerState.PAUSED) {
_this.video.play();
_this.playerState = HTML5Video.PlayerState.PLAYING;
if ($.isFunction(_this.config.events.onStateChange) === true) {
_this.config.events.onStateChange({
'data': _this.playerState
});
}
_this.callStateChangeCallback();
} else if (_this.playerState === HTML5Video.PlayerState.PLAYING) {
_this.video.pause();
_this.playerState = HTML5Video.PlayerState.PAUSED;
if ($.isFunction(_this.config.events.onStateChange) === true) {
_this.config.events.onStateChange({
'data': _this.playerState
});
}
_this.callStateChangeCallback();
}
});
// When the <video> tag has been processed by the browser, and it is ready for playback,
// notify other parts of the VideoPlayer, and initially pause the video.
//
// Also, at this time we can get the real duration of the video. Update the starting end ending
// points of the video. Note that first time, the video will start playing at the specified start time,
// and end playing at the specified end time. After it was paused, or when a seek operation happeded,
// the starting time and ending time will reset to the beginning and the end of the video respectively.
this.video.addEventListener('canplay', function () {
_this.playerState = HTML5Video.PlayerState.PAUSED;
......@@ -155,96 +230,41 @@ this.HTML5Video = (function () {
_this.config.events.onReady({});
}
}, false);
// Register the 'play' event.
this.video.addEventListener('play', function () {
_this.playerState = HTML5Video.PlayerState.PLAYING;
if ($.isFunction(_this.config.events.onStateChange) === true) {
_this.config.events.onStateChange({
'data': _this.playerState
});
}
_this.callStateChangeCallback();
}, false);
// Register the 'pause' event.
this.video.addEventListener('pause', function () {
_this.playerState = HTML5Video.PlayerState.PAUSED;
if ($.isFunction(_this.config.events.onStateChange) === true) {
_this.config.events.onStateChange({
'data': _this.playerState
});
}
_this.callStateChangeCallback();
}, false);
// Register the 'ended' event.
this.video.addEventListener('ended', function () {
_this.playerState = HTML5Video.PlayerState.ENDED;
if ($.isFunction(_this.config.events.onStateChange) === true) {
_this.config.events.onStateChange({
'data': _this.playerState
});
}
_this.callStateChangeCallback();
}, false);
// Register the 'timeupdate' event. This is the place where we control when the video ends.
// If an ending time was specified, then after the video plays through to this spot, pauses, we
// must make sure to update the ending time to the end of the video. This way, the user can watch
// any parts of it afterwards.
this.video.addEventListener('timeupdate', function (data) {
if (_this.end < _this.video.currentTime) {
// When we call video.pause(), a 'pause' event will be formed, and we will catch it
// in another handler (see above).
_this.video.pause();
_this.end = _this.video.duration;
}
}, false);
// Place the <video> element on the page.
this.videoEl.appendTo(this.el.find('.video-player div'));
}
Player.prototype.pauseVideo = function () {
this.video.pause();
};
Player.prototype.seekTo = function (value) {
if ((typeof value === 'number') && (value <= this.video.duration) && (value >= 0)) {
this.start = 0;
this.end = this.video.duration;
this.video.currentTime = value;
}
};
Player.prototype.setVolume = function (value) {
if ((typeof value === 'number') && (value <= 100) && (value >= 0)) {
this.video.volume = value * 0.01;
}
};
Player.prototype.getCurrentTime = function () {
return this.video.currentTime;
};
Player.prototype.playVideo = function () {
this.video.play();
};
Player.prototype.getPlayerState = function () {
return this.playerState;
};
Player.prototype.getVolume = function () {
return this.video.volume;
};
Player.prototype.getDuration = function () {
return this.video.duration;
};
Player.prototype.setSpeed = function (value) {
var newSpeed;
newSpeed = parseFloat(value);
if (isFinite(newSpeed) === true) {
this.video.playbackRate = value;
}
};
Player.prototype.getAvailablePlaybackRates = function () {
return [0.75, 1.0, 1.25, 1.5];
};
return Player;
}());
HTML5Video.PlayerState = {
......
......@@ -94,19 +94,16 @@ class @VideoPlayerAlpha extends SubviewAlpha
when @PlayerState.UNSTARTED
if @video.videoType is "youtube"
availableSpeeds = @player.getAvailablePlaybackRates()
console.log @video.videos
if availableSpeeds.length > 1
baseSpeedSubs = @video.videos["1.0"]
$.each @video.videos, (index, value) ->
delete _this.video.videos[index]
@video.speeds = []
$.each availableSpeeds, (index, value) ->
_this.video.videos[value.toFixed(2).replace(/\.00$/, ".0")] = baseSpeedSubs
@speedControl.reRender()
console.log "UNSTARTED. available speeds = "
console.log availableSpeeds
_this.video.speeds.push value.toFixed(2).replace(/\.00$/, ".0")
@speedControl.reRender @video.speeds
@video.videoType = 'html5'
@onUnstarted()
when @PlayerState.PLAYING
@onPlay()
......@@ -162,12 +159,12 @@ class @VideoPlayerAlpha extends SubviewAlpha
if @video.videoType is 'youtube'
@currentTime = Time.convert(@currentTime, parseFloat(@currentSpeed()), newSpeed)
newSpeed = parseFloat(newSpeed).toFixed(2).replace /\.00$/, '.0'
@video.setSpeed(newSpeed)
@video.setSpeed newSpeed
if @video.videoType is 'youtube'
if @video.show_captions is true
@caption.currentSpeed = newSpeed
if @video.videoType is 'html5'
@player.setSpeed(newSpeed)
@player.setPlaybackRate newSpeed
else if @video.videoType is 'youtube'
if @isPlaying()
@player.loadVideoById(@video.youtubeId(), @currentTime)
......
......@@ -24,20 +24,14 @@ class @VideoSpeedControlAlpha extends SubviewAlpha
<ol class="video_speeds"></ol>
</div>
"""
$.each @speeds, (index, speed) =>
link = $('<a>').attr(href: "#").html("#{speed}x")
@$('.video_speeds').prepend($('<li>').attr('data-speed', speed).html(link))
@setSpeed(@currentSpeed)
@setSpeed @currentSpeed
reRender: (newSpeeds) ->
@$('.video_speeds').empty()
@speeds newSpeeds
console.log "Changing speeds"
console.log @speeds
@speeds = newSpeeds
$.each @speeds, (index, speed) =>
link = $('<a>').attr(href: "#").html("#{speed}x")
@$('.video_speeds').prepend($('<li>').attr('data-speed', speed).html(link))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment