Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add seekable attribute #2207

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/js/exports.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ goog.exportProperty(vjs.Player.prototype, 'remoteTextTracks', vjs.Player.prototy
goog.exportProperty(vjs.Player.prototype, 'addTextTrack', vjs.Player.prototype.addTextTrack);
goog.exportProperty(vjs.Player.prototype, 'addRemoteTextTrack', vjs.Player.prototype.addRemoteTextTrack);
goog.exportProperty(vjs.Player.prototype, 'removeRemoteTextTrack', vjs.Player.prototype.removeRemoteTextTrack);
goog.exportProperty(vjs.Player.prototype, 'seekable', vjs.Player.prototype.removeRemoteTextTrack);

goog.exportSymbol('videojs.MediaLoader', vjs.MediaLoader);
goog.exportSymbol('videojs.TextTrackDisplay', vjs.TextTrackDisplay);
Expand Down
12 changes: 12 additions & 0 deletions src/js/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,18 @@ vjs.round = function(num, dec) {
* @private
*/
vjs.createTimeRange = function(start, end){
if (start === undefined && end === undefined) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why we wouldn't throw an error when you try to create a time range with no start/end values, instead of creating one that throws errors later?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, apparently that's how native time ranges work.

var v = document.createElement('video').buffered.start(0);

Uncaught DOMException: Failed to execute 'start' on 'TimeRanges': The index provided (0) is greater than or equal to the maximum bound (0).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's what I was emulating.

return {
length: 0,
start: function() {
throw new Error('This TimeRanges object is empty');
},
end: function() {
throw new Error('This TimeRanges object is empty');
}
};
}

return {
length: 1,
start: function() { return start; },
Expand Down
11 changes: 10 additions & 1 deletion src/js/media/flash.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,15 @@ vjs.Flash.prototype['setPoster'] = function(){
// poster images are not handled by the Flash tech so make this a no-op
};

vjs.Flash.prototype.seekable = function() {
var duration = this.duration();
if (duration === 0) {
// The SWF reports a duration of zero when the actual duration is unknown
return vjs.createTimeRange();
}
return vjs.createTimeRange(0, this.duration());
};

vjs.Flash.prototype.buffered = function(){
return vjs.createTimeRange(0, this.el_.vjs_getProperty('buffered'));
};
Expand All @@ -180,7 +189,7 @@ vjs.Flash.prototype.enterFullScreen = function(){
// Create setters and getters for attributes
var api = vjs.Flash.prototype,
readWrite = 'rtmpConnection,rtmpStream,preload,defaultPlaybackRate,playbackRate,autoplay,loop,mediaGroup,controller,controls,volume,muted,defaultMuted'.split(','),
readOnly = 'error,networkState,readyState,seeking,initialTime,duration,startOffsetTime,paused,played,seekable,ended,videoTracks,audioTracks,videoWidth,videoHeight'.split(','),
readOnly = 'error,networkState,readyState,seeking,initialTime,duration,startOffsetTime,paused,played,ended,videoTracks,audioTracks,videoWidth,videoHeight'.split(','),
// Overridden: buffered, currentTime, currentSrc
i;

Expand Down
1 change: 1 addition & 0 deletions src/js/media/html5.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ vjs.Html5.prototype.setLoop = function(val){ this.el_.loop = val; };

vjs.Html5.prototype.error = function(){ return this.el_.error; };
vjs.Html5.prototype.seeking = function(){ return this.el_.seeking; };
vjs.Html5.prototype.seekable = function(){ return this.el_.seekable; };
vjs.Html5.prototype.ended = function(){ return this.el_.ended; };
vjs.Html5.prototype.defaultMuted = function(){ return this.el_.defaultMuted; };

Expand Down
2 changes: 1 addition & 1 deletion src/js/player.externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ videojs.Player.prototype.load = function(){};
videojs.Player.prototype.canPlayType = function(){};
videojs.Player.prototype.readyState = function(){};
videojs.Player.prototype.seeking = function(){};
videojs.Player.prototype.seekable = function(){};
videojs.Player.prototype.currentTime = function(){};
videojs.Player.prototype.remainingTime = function(){};
videojs.Player.prototype.startTime = function(){};
Expand All @@ -32,7 +33,6 @@ videojs.Player.prototype.paused = function(){};
videojs.Player.prototype.defaultPlaybackRate = function(){};
videojs.Player.prototype.playbackRate = function(){};
videojs.Player.prototype.played = function(){};
videojs.Player.prototype.seekable = function(){};
videojs.Player.prototype.ended = function(){};
videojs.Player.prototype.autoplay = function(){};
videojs.Player.prototype.loop = function(){};
Expand Down
7 changes: 7 additions & 0 deletions src/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,13 @@ vjs.Player.prototype.ended = function(){ return this.techGet('ended'); };
*/
vjs.Player.prototype.seeking = function(){ return this.techGet('seeking'); };

/**
* Returns the TimeRanges of the media that are currently available
* for seeking to.
* @return {TimeRanges} the seekable intervals of the media timeline
*/
vjs.Player.prototype.seekable = function(){ return this.techGet('seekable'); };

// When the player is first initialized, trigger activity so components
// like the control bar show themselves if needed
vjs.Player.prototype.userActivity_ = true;
Expand Down
2 changes: 1 addition & 1 deletion test/unit/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ test('should be able to access expected player API methods', function() {
ok(player.buffered, 'buffered exists');
ok(player.load, 'load exists');
ok(player.seeking, 'seeking exists');
ok(player.seekable, 'seekable exists');
ok(player.currentTime, 'currentTime exists');
ok(player.duration, 'duration exists');
ok(player.paused, 'paused exists');
Expand Down Expand Up @@ -37,7 +38,6 @@ test('should be able to access expected player API methods', function() {
// ok(player.defaultPlaybackRate, 'defaultPlaybackRate exists');
// ok(player.playbackRate, 'playbackRate exists');
// ok(player.played, 'played exists');
// ok(player.seekable, 'seekable exists');
// ok(player.videoWidth, 'videoWidth exists');
// ok(player.videoHeight, 'videoHeight exists');

Expand Down
34 changes: 34 additions & 0 deletions test/unit/flash.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,37 @@ test('ready triggering before and after disposing the tech', function() {
test('should have the source handler interface', function() {
ok(vjs.Flash.registerSourceHandler, 'has the registerSourceHandler function');
});

test('seekable should be for the length of the loaded video', function() {
var player = PlayerTest.makePlayer(),
tech = new vjs.Flash(player, {
'parentEl': player.el()
}),
duration = 23;

// mock out duration
tech.el().vjs_getProperty = function(name) {
if (name === 'duration') {
return duration;
}
};
equal(tech.seekable().length, 1, 'seekable is non-empty');
equal(tech.seekable().start(0), 0, 'starts at zero');
equal(tech.seekable().end(0), duration, 'ends at the duration');
});

test('seekable should be empty if no video is loaded', function() {
var player = PlayerTest.makePlayer(),
tech = new vjs.Flash(player, {
'parentEl': player.el()
});

// mock out duration
tech.el().vjs_getProperty = function(name) {
if (name === 'duration') {
return 0;
}
};

equal(tech.seekable().length, 0, 'seekable is empty');
});