зеркало из https://github.com/mozilla/popcorn-js.git
Merge pull request #52 from ScottDowne/t1023
[#1023] added player queue to easily allow player authors to fire play a...
This commit is contained in:
Коммит
863da326ea
|
@ -301,23 +301,6 @@
|
|||
basePlayer.dispatchEvent( "error" );
|
||||
}
|
||||
|
||||
// when a custom player is loaded, load basePlayer state into custom player
|
||||
basePlayer.addEventListener( "loadedmetadata", function() {
|
||||
|
||||
// if a player is not ready before currentTime is called, this will set it after it is ready
|
||||
basePlayer.currentTime = currentTime;
|
||||
|
||||
// same as above with volume and muted
|
||||
basePlayer.volume = volume;
|
||||
basePlayer.muted = muted;
|
||||
});
|
||||
|
||||
basePlayer.addEventListener( "loadeddata", function() {
|
||||
|
||||
// if play was called before player ready, start playing video
|
||||
!basePlayer.paused && basePlayer.play();
|
||||
});
|
||||
|
||||
popcorn = new Popcorn.p.init( basePlayer, options );
|
||||
|
||||
if ( player._teardown ) {
|
||||
|
@ -344,6 +327,36 @@
|
|||
object.__defineSetter__( description, options.set || Popcorn.nop );
|
||||
};
|
||||
|
||||
// player queue is to help players queue things like play and pause
|
||||
// HTML5 video's play and pause are asynch, but do fire in sequence
|
||||
// play() should really mean "requestPlay()" or "queuePlay()" and
|
||||
// stash a callback that will play the media resource when it's ready to be played
|
||||
Popcorn.player.playerQueue = function() {
|
||||
|
||||
var _queue = [],
|
||||
_running = false;
|
||||
|
||||
return {
|
||||
next: function() {
|
||||
|
||||
_running = false;
|
||||
_queue.shift();
|
||||
_queue[ 0 ] && _queue[ 0 ]();
|
||||
},
|
||||
add: function( callback ) {
|
||||
|
||||
_queue.push(function() {
|
||||
|
||||
_running = true;
|
||||
callback && callback();
|
||||
});
|
||||
|
||||
// if there is only one item on the queue, start it
|
||||
!_running && _queue[ 0 ]();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// smart will attempt to find you a match, if it does not find a match,
|
||||
// it will attempt to create a video element with the source,
|
||||
// if that failed, it will throw.
|
||||
|
|
|
@ -13,32 +13,43 @@
|
|||
container = document.createElement( "iframe" ),
|
||||
lastVolume = 1,
|
||||
currentTime = 0,
|
||||
paused = true,
|
||||
realPaused = true,
|
||||
widget,
|
||||
duration = 0,
|
||||
muted = false;
|
||||
muted = false,
|
||||
playerQueue = Popcorn.player.playerQueue();
|
||||
|
||||
options._container = container;
|
||||
media.style.visibility = "hidden";
|
||||
|
||||
media.play = function() {
|
||||
|
||||
if ( media.paused ) {
|
||||
paused = false;
|
||||
playerQueue.add(function() {
|
||||
|
||||
media.paused = false;
|
||||
media.dispatchEvent( "playing" );
|
||||
media.dispatchEvent( "play" );
|
||||
widget && widget.play();
|
||||
}
|
||||
if ( realPaused ) {
|
||||
|
||||
widget && widget.play();
|
||||
} else {
|
||||
playerQueue.next();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
media.pause = function() {
|
||||
|
||||
if ( !media.paused ) {
|
||||
paused = true;
|
||||
|
||||
media.paused = true;
|
||||
media.dispatchEvent( "pause" );
|
||||
widget && widget.pause();
|
||||
}
|
||||
playerQueue.add(function() {
|
||||
|
||||
if ( !realPaused ) {
|
||||
|
||||
widget && widget.pause();
|
||||
} else {
|
||||
playerQueue.next();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// getter and setter for muted property, multiply volume by 100 as that is the scale soundcloud works on
|
||||
|
@ -86,6 +97,11 @@
|
|||
get: function() {
|
||||
return duration;
|
||||
}
|
||||
},
|
||||
paused: {
|
||||
get: function() {
|
||||
return paused;
|
||||
}
|
||||
}
|
||||
});
|
||||
// called when the SoundCloud api script has loaded
|
||||
|
@ -118,25 +134,34 @@
|
|||
options.widget = widget = SC.Widget( container.id );
|
||||
// setup all of our listeners
|
||||
widget.bind(SC.Widget.Events.FINISH, function() {
|
||||
media.pause();
|
||||
|
||||
media.dispatchEvent( "ended" );
|
||||
});
|
||||
|
||||
widget.bind(SC.Widget.Events.PLAY_PROGRESS, function( data ) {
|
||||
|
||||
currentTime = data.currentPosition / 1000;
|
||||
media.dispatchEvent( "timeupdate" );
|
||||
});
|
||||
|
||||
widget.bind(SC.Widget.Events.PLAY, function( data ) {
|
||||
|
||||
if ( media.paused ) {
|
||||
media.currentTime = currentTime;
|
||||
media.paused && media.play();
|
||||
}
|
||||
paused = realPaused = false;
|
||||
|
||||
media.dispatchEvent( "play" );
|
||||
media.dispatchEvent( "playing" );
|
||||
media.currentTime = currentTime;
|
||||
|
||||
playerQueue.next();
|
||||
});
|
||||
|
||||
widget.bind(SC.Widget.Events.PAUSE, function( data ) {
|
||||
|
||||
!media.paused && media.pause();
|
||||
paused = realPaused = true;
|
||||
media.dispatchEvent( "pause" );
|
||||
|
||||
playerQueue.next();
|
||||
});
|
||||
widget.bind(SC.Widget.Events.READY, function( data ) {
|
||||
widget.getDuration(function( data ) {
|
||||
|
@ -209,7 +234,7 @@
|
|||
|
||||
// remove all bound soundcloud listeners
|
||||
for ( var prop in events ) {
|
||||
widget.unbind( events[ prop ] );
|
||||
widget && widget.unbind( events[ prop ] );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<script src="../../test/qunit/qunit.js"></script>
|
||||
<script src="../../popcorn.js"></script>
|
||||
<script src="../../modules/player/popcorn.player.js"></script>
|
||||
<script src="popcorn.soundcloud.unit.js"></script>
|
||||
<script src="popcorn.soundcloud.js"></script>
|
||||
<script src="popcorn.soundcloud.unit.js"></script>
|
||||
<script src="../../test/inject.js"></script>
|
||||
<style>
|
||||
.soundcloudPlayer {
|
||||
|
|
|
@ -110,6 +110,7 @@ asyncTest( "Popcorn Integration", function () {
|
|||
player = Popcorn.soundcloud( "player_1", "http://api.soundcloud.com/tracks/12643174" );
|
||||
|
||||
function plus() {
|
||||
|
||||
if ( ++count === expects ) {
|
||||
start();
|
||||
player.destroy();
|
||||
|
@ -118,7 +119,8 @@ asyncTest( "Popcorn Integration", function () {
|
|||
|
||||
expect(expects);
|
||||
|
||||
player.on( "load", function() {
|
||||
player.on( "canplaythrough", function() {
|
||||
|
||||
ok( true, "Listen works (load event)" );
|
||||
plus();
|
||||
|
||||
|
@ -130,6 +132,7 @@ asyncTest( "Popcorn Integration", function () {
|
|||
});
|
||||
|
||||
player.on( "pause", function() {
|
||||
|
||||
ok( true, "Pause explicitly called" );
|
||||
plus();
|
||||
|
||||
|
@ -165,13 +168,23 @@ asyncTest( "Events and Player Control", function () {
|
|||
plus();
|
||||
});
|
||||
|
||||
player.on( "playing", function() {
|
||||
ok( true, "Playing was fired" );
|
||||
plus();
|
||||
player.on( "playing", (function() {
|
||||
var hasFired = 0;
|
||||
|
||||
equal( player.paused(), 0, "Paused is unset" );
|
||||
plus();
|
||||
});
|
||||
return function() {
|
||||
if ( hasFired ) {
|
||||
return;
|
||||
}
|
||||
|
||||
hasFired = 1;
|
||||
ok( true, "Playing was fired" );
|
||||
plus();
|
||||
|
||||
equal( player.paused(), false, "Paused is unset" );
|
||||
plus();
|
||||
player.pause();
|
||||
};
|
||||
})());
|
||||
|
||||
player.on( "play", (function() {
|
||||
var hasFired = 0;
|
||||
|
@ -198,15 +211,16 @@ asyncTest( "Events and Player Control", function () {
|
|||
|
||||
equal( player.readyState(), 4, "Ready State is now 4" );
|
||||
plus();
|
||||
|
||||
player.pause();
|
||||
}, false);
|
||||
|
||||
player.on( "pause", function() {
|
||||
|
||||
ok( true, "Pause was fired by dispatch" );
|
||||
plus();
|
||||
|
||||
equal( player.paused(), 1, "Paused is set" );
|
||||
equal( player.paused(), true, "Paused is set" );
|
||||
|
||||
player.play();
|
||||
plus();
|
||||
});
|
||||
|
||||
|
@ -225,32 +239,52 @@ asyncTest( "Events and Player Control", function () {
|
|||
})());
|
||||
|
||||
player.on( "volumechange", function() {
|
||||
player.off( "volumechange" );
|
||||
ok( true, "volumechange was fired by dispatch" );
|
||||
plus();
|
||||
});
|
||||
|
||||
player.cue( 10, function() {
|
||||
// Will trigger a "seeked" event to near end
|
||||
player.currentTime( player.duration() - 1 );
|
||||
});
|
||||
|
||||
player.on( "canplaythrough", function() {
|
||||
ok( true, "Can play through" );
|
||||
plus();
|
||||
|
||||
// Will trigger a "seeked" event to near end
|
||||
player.currentTime( player.duration() - 1 );
|
||||
});
|
||||
|
||||
player.on( "seeked", function() {
|
||||
ok( true, "Seeked was fired" );
|
||||
plus();
|
||||
player.on( "seeked", (function() {
|
||||
var hasFired = 0;
|
||||
|
||||
player.emit( "play" );
|
||||
});
|
||||
return function() {
|
||||
if ( hasFired ) {
|
||||
return;
|
||||
}
|
||||
hasFired = 1;
|
||||
ok( true, "Seeked was fired" );
|
||||
plus();
|
||||
};
|
||||
})());
|
||||
|
||||
player.on( "ended", function() {
|
||||
|
||||
ok( true, "Media is done playing" );
|
||||
plus();
|
||||
|
||||
equal( player.paused, 1, "Paused is set on end" );
|
||||
equal( player.paused(), true, "Paused is set on end" );
|
||||
plus();
|
||||
});
|
||||
|
||||
player.play();
|
||||
var ready = function() {
|
||||
|
||||
player.off( "canplaythrough", ready );
|
||||
player.play();
|
||||
};
|
||||
|
||||
if ( player.readyState() >= 4 ) {
|
||||
ready();
|
||||
} else {
|
||||
player.on( "canplaythrough", ready );
|
||||
}
|
||||
});
|
||||
|
|
|
@ -20,13 +20,15 @@
|
|||
vimeoObject,
|
||||
vimeoContainer = document.createElement( "div" ),
|
||||
currentTime = 0,
|
||||
paused = true,
|
||||
seekTime = 0,
|
||||
seeking = false,
|
||||
volumeChanged = false,
|
||||
lastMuted = false,
|
||||
lastVolume = 0,
|
||||
height,
|
||||
width;
|
||||
width,
|
||||
playerQueue = Popcorn.player.playerQueue();
|
||||
|
||||
vimeoContainer.id = media.id + Popcorn.guid();
|
||||
|
||||
|
@ -46,6 +48,7 @@
|
|||
loadStarted = false;
|
||||
|
||||
vimeo_player_loaded[ vimeoContainer.id ] = function() {
|
||||
|
||||
vimeoObject = document.getElementById( vimeoContainer.id );
|
||||
|
||||
vimeo_player_loaded.seek[ vimeoContainer.id ] = function( time ) {
|
||||
|
@ -57,20 +60,21 @@
|
|||
};
|
||||
|
||||
vimeo_player_loaded.play[ vimeoContainer.id ] = function() {
|
||||
if ( media.paused ) {
|
||||
media.paused = false;
|
||||
media.dispatchEvent( "play" );
|
||||
|
||||
media.dispatchEvent( "playing" );
|
||||
timeUpdate();
|
||||
}
|
||||
paused = false;
|
||||
media.dispatchEvent( "play" );
|
||||
media.dispatchEvent( "playing" );
|
||||
timeUpdate();
|
||||
|
||||
playerQueue.next();
|
||||
};
|
||||
|
||||
vimeo_player_loaded.pause[ vimeoContainer.id ] = function() {
|
||||
if ( !media.paused ) {
|
||||
media.paused = true;
|
||||
media.dispatchEvent( "pause" );
|
||||
}
|
||||
|
||||
paused = true;
|
||||
media.dispatchEvent( "pause" );
|
||||
|
||||
playerQueue.next();
|
||||
};
|
||||
|
||||
vimeo_player_loaded.loadProgress[ vimeoContainer.id ] = function( progress ) {
|
||||
|
@ -121,22 +125,32 @@
|
|||
};
|
||||
|
||||
media.play = function() {
|
||||
media.paused = false;
|
||||
media.dispatchEvent( "play" );
|
||||
|
||||
media.dispatchEvent( "playing" );
|
||||
timeUpdate();
|
||||
vimeoObject.api_play();
|
||||
|
||||
paused = false;
|
||||
playerQueue.add(function() {
|
||||
|
||||
if ( vimeoObject.api_paused() ) {
|
||||
|
||||
vimeoObject.api_play();
|
||||
} else {
|
||||
playerQueue.next();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
media.pause = function() {
|
||||
|
||||
if ( !media.paused ) {
|
||||
paused = true;
|
||||
playerQueue.add(function() {
|
||||
|
||||
media.paused = true;
|
||||
media.dispatchEvent( "pause" );
|
||||
vimeoObject.api_pause();
|
||||
}
|
||||
if ( !vimeoObject.api_paused() ) {
|
||||
|
||||
vimeoObject.api_pause();
|
||||
} else {
|
||||
playerQueue.next();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Popcorn.player.defineProperty( media, "currentTime", {
|
||||
|
@ -163,6 +177,14 @@
|
|||
}
|
||||
});
|
||||
|
||||
Popcorn.player.defineProperty( media, "paused", {
|
||||
|
||||
get: function() {
|
||||
|
||||
return paused;
|
||||
}
|
||||
});
|
||||
|
||||
Popcorn.player.defineProperty( media, "muted", {
|
||||
|
||||
set: function( val ) {
|
||||
|
@ -206,7 +228,6 @@
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
media.duration = vimeoObject.api_getDuration();
|
||||
media.dispatchEvent( "durationchange" );
|
||||
media.dispatchEvent( "loadedmetadata" );
|
||||
|
|
|
@ -66,7 +66,7 @@ asyncTest( "Update Timer", function() {
|
|||
ok( true, "'loadedmetadata' fired" );
|
||||
plus();
|
||||
// make sure that we always have a duration at this point
|
||||
ok( this.duration() > 0, "Videos duration is greather than 0" );
|
||||
ok( this.duration() > 0, "Video's duration is greater than 0" );
|
||||
plus();
|
||||
});
|
||||
|
||||
|
@ -216,11 +216,21 @@ asyncTest( "Update Timer", function() {
|
|||
});
|
||||
|
||||
p2.exec( 3, function() {
|
||||
|
||||
p2.play();
|
||||
});
|
||||
|
||||
p2.currentTime( 3 );
|
||||
var ready = function() {
|
||||
|
||||
p2.off( "canplaythrough", ready );
|
||||
|
||||
p2.volume( 0 ).currentTime( 3 );
|
||||
};
|
||||
|
||||
if ( p2.readyState() >= 4 ) {
|
||||
ready();
|
||||
} else {
|
||||
p2.on( "canplaythrough", ready );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
@ -338,8 +348,16 @@ asyncTest( "Plugin Factory", function() {
|
|||
end: 5
|
||||
});
|
||||
|
||||
popped.currentTime( 0 ).play();
|
||||
var ready = function() {
|
||||
popped.off( "canplaythrough", ready );
|
||||
popped.volume( 0 ).currentTime( 0 ).play();
|
||||
};
|
||||
|
||||
if ( popped.readyState() >= 4 ) {
|
||||
ready();
|
||||
} else {
|
||||
popped.on( "canplaythrough", ready );
|
||||
}
|
||||
});
|
||||
|
||||
asyncTest( "Popcorn vimeo Plugin Url and Duration Tests", function() {
|
||||
|
|
|
@ -138,7 +138,7 @@
|
|||
<body>
|
||||
<div>
|
||||
<div>
|
||||
<div id="video" style="width: 360px; height: 300px;" ></div><br />
|
||||
<div id="video" style="width: 640px; height: 390px;" ></div><br />
|
||||
<button class="simple" id="btn-play-pause">Play</button>
|
||||
<button class="seek" id="btn-seek">Seek to 30</button>
|
||||
<button class="volume" id="btn-volume">Toggle Volume</button>
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
// A global callback for youtube... that makes me angry
|
||||
var onYouTubePlayerReady = function( containerId ) {
|
||||
var onYouTubePlayerAPIReady = function() {
|
||||
|
||||
onYouTubePlayerReady[ containerId ] && onYouTubePlayerReady[ containerId ]();
|
||||
onYouTubePlayerAPIReady.ready = true;
|
||||
for ( var i = 0; i < onYouTubePlayerAPIReady.waiting.length; i++ ) {
|
||||
onYouTubePlayerAPIReady.waiting[ i ]();
|
||||
}
|
||||
};
|
||||
onYouTubePlayerReady.stateChangeEventHandler = {};
|
||||
onYouTubePlayerReady.onErrorEventHandler = {};
|
||||
|
||||
onYouTubePlayerAPIReady.waiting = [];
|
||||
|
||||
Popcorn.getScript( "http://www.youtube.com/player_api" );
|
||||
|
||||
Popcorn.player( "youtube", {
|
||||
_canPlayType: function( nodeName, url ) {
|
||||
|
@ -17,302 +22,179 @@ Popcorn.player( "youtube", {
|
|||
autoPlay = false,
|
||||
container = document.createElement( "div" ),
|
||||
currentTime = 0,
|
||||
paused = true,
|
||||
seekTime = 0,
|
||||
firstGo = true,
|
||||
seeking = false,
|
||||
fragmentStart = 0,
|
||||
|
||||
// state code for volume changed polling
|
||||
volumeChanged = false,
|
||||
lastMuted = false,
|
||||
lastVolume = 100;
|
||||
lastVolume = 100,
|
||||
playerQueue = Popcorn.player.playerQueue();
|
||||
|
||||
var createProperties = function() {
|
||||
|
||||
Popcorn.player.defineProperty( media, "currentTime", {
|
||||
set: function( val ) {
|
||||
Popcorn.player.defineProperty( media, "currentTime", {
|
||||
set: function( val ) {
|
||||
|
||||
// make sure val is a number
|
||||
currentTime = seekTime = +val;
|
||||
seeking = true;
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return currentTime;
|
||||
}
|
||||
|
||||
media.dispatchEvent( "seeked" );
|
||||
media.dispatchEvent( "timeupdate" );
|
||||
|
||||
options.youtubeObject.seekTo( currentTime );
|
||||
|
||||
return currentTime;
|
||||
},
|
||||
get: function() {
|
||||
|
||||
return currentTime;
|
||||
if ( options.destroyed ) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
Popcorn.player.defineProperty( media, "muted", {
|
||||
set: function( val ) {
|
||||
seeking = true;
|
||||
// make sure val is a number
|
||||
currentTime = Math.round( +val * 100 ) / 100;
|
||||
},
|
||||
get: function() {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
return currentTime;
|
||||
}
|
||||
});
|
||||
|
||||
return val;
|
||||
}
|
||||
Popcorn.player.defineProperty( media, "paused", {
|
||||
get: function() {
|
||||
|
||||
if ( options.youtubeObject.isMuted() !== val ) {
|
||||
return paused;
|
||||
}
|
||||
});
|
||||
|
||||
if ( val ) {
|
||||
|
||||
options.youtubeObject.mute();
|
||||
} else {
|
||||
|
||||
options.youtubeObject.unMute();
|
||||
}
|
||||
|
||||
lastMuted = options.youtubeObject.isMuted();
|
||||
media.dispatchEvent( "volumechange" );
|
||||
}
|
||||
|
||||
return options.youtubeObject.isMuted();
|
||||
},
|
||||
get: function() {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return options.youtubeObject.isMuted();
|
||||
}
|
||||
});
|
||||
|
||||
Popcorn.player.defineProperty( media, "volume", {
|
||||
set: function( val ) {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
if ( options.youtubeObject.getVolume() / 100 !== val ) {
|
||||
|
||||
options.youtubeObject.setVolume( val * 100 );
|
||||
lastVolume = options.youtubeObject.getVolume();
|
||||
media.dispatchEvent( "volumechange" );
|
||||
}
|
||||
|
||||
return options.youtubeObject.getVolume() / 100;
|
||||
},
|
||||
get: function() {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return options.youtubeObject.getVolume() / 100;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// setting paused to undefined because youtube has state for not paused or playing
|
||||
media.paused = undefined;
|
||||
container.id = media.id + Popcorn.guid();
|
||||
|
||||
options._container = container;
|
||||
|
||||
media.appendChild( container );
|
||||
|
||||
var youtubeInit = function() {
|
||||
|
||||
var flashvars, params, attributes,
|
||||
src, width, height, query;
|
||||
|
||||
// expose a callback to this scope, that is called from the global callback youtube calls
|
||||
onYouTubePlayerReady[ container.id ] = function() {
|
||||
|
||||
options.youtubeObject = document.getElementById( container.id );
|
||||
|
||||
// more youtube callback nonsense
|
||||
onYouTubePlayerReady.stateChangeEventHandler[ container.id ] = function( state ) {
|
||||
Popcorn.player.defineProperty( media, "muted", {
|
||||
set: function( val ) {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return;
|
||||
return val;
|
||||
}
|
||||
|
||||
// youtube fires paused events while seeking
|
||||
// this is the only way to get seeking events
|
||||
if ( state === 2 ) {
|
||||
if ( options.youtubeObject.isMuted() !== val ) {
|
||||
|
||||
// silly logic forced on me by the youtube API
|
||||
// calling youtube.seekTo triggers multiple events
|
||||
// with the second events getCurrentTime being the old time
|
||||
if ( seeking && seekTime === currentTime && seekTime !== options.youtubeObject.getCurrentTime() ) {
|
||||
if ( val ) {
|
||||
|
||||
seeking = false;
|
||||
options.youtubeObject.seekTo( currentTime );
|
||||
return;
|
||||
options.youtubeObject.mute();
|
||||
} else {
|
||||
|
||||
options.youtubeObject.unMute();
|
||||
}
|
||||
|
||||
currentTime = options.youtubeObject.getCurrentTime();
|
||||
media.dispatchEvent( "timeupdate" );
|
||||
!media.paused && media.pause();
|
||||
|
||||
return;
|
||||
} else
|
||||
// playing is state 1
|
||||
// paused is state 2
|
||||
if ( state === 1 && !firstGo ) {
|
||||
|
||||
media.paused && media.play();
|
||||
return;
|
||||
} else
|
||||
// this is the real player ready check
|
||||
// -1 is for unstarted, but ready to go videos
|
||||
// before this the player object exists, but calls to it may go unheard
|
||||
if ( state === -1 ) {
|
||||
|
||||
options.youtubeObject.playVideo();
|
||||
return;
|
||||
} else if ( state === 1 && firstGo ) {
|
||||
|
||||
firstGo = false;
|
||||
|
||||
if ( media.paused === true ) {
|
||||
|
||||
media.pause();
|
||||
} else if ( media.paused === false ) {
|
||||
|
||||
media.play();
|
||||
} else if ( autoPlay ) {
|
||||
|
||||
media.play();
|
||||
} else if ( !autoPlay ) {
|
||||
|
||||
media.pause();
|
||||
}
|
||||
|
||||
media.duration = options.youtubeObject.getDuration();
|
||||
|
||||
media.dispatchEvent( "durationchange" );
|
||||
volumeupdate();
|
||||
|
||||
media.currentTime = options.youtubeObject.getCurrentTime();
|
||||
|
||||
createProperties();
|
||||
media.dispatchEvent( "loadedmetadata" );
|
||||
media.dispatchEvent( "loadeddata" );
|
||||
|
||||
media.readyState = 4;
|
||||
media.dispatchEvent( "canplaythrough" );
|
||||
|
||||
return;
|
||||
} else if ( state === 0 ) {
|
||||
media.dispatchEvent( "ended" );
|
||||
}
|
||||
};
|
||||
|
||||
onYouTubePlayerReady.onErrorEventHandler[ container.id ] = function( errorCode ) {
|
||||
if ( [ 2, 100, 101, 150 ].indexOf( errorCode ) !== -1 ) {
|
||||
media.error = {
|
||||
customCode: errorCode
|
||||
};
|
||||
media.dispatchEvent( "error" );
|
||||
}
|
||||
};
|
||||
|
||||
// youtube requires callbacks to be a string to a function path from the global scope
|
||||
options.youtubeObject.addEventListener( "onStateChange", "onYouTubePlayerReady.stateChangeEventHandler." + container.id );
|
||||
|
||||
options.youtubeObject.addEventListener( "onError", "onYouTubePlayerReady.onErrorEventHandler." + container.id );
|
||||
|
||||
var timeupdate = function() {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !media.paused ) {
|
||||
|
||||
currentTime = options.youtubeObject.getCurrentTime();
|
||||
media.dispatchEvent( "timeupdate" );
|
||||
setTimeout( timeupdate, 10 );
|
||||
}
|
||||
};
|
||||
|
||||
var volumeupdate = function() {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( lastMuted !== options.youtubeObject.isMuted() ) {
|
||||
|
||||
lastMuted = options.youtubeObject.isMuted();
|
||||
media.dispatchEvent( "volumechange" );
|
||||
}
|
||||
|
||||
if ( lastVolume !== options.youtubeObject.getVolume() ) {
|
||||
return options.youtubeObject.isMuted();
|
||||
},
|
||||
get: function() {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return options.youtubeObject.isMuted();
|
||||
}
|
||||
});
|
||||
|
||||
Popcorn.player.defineProperty( media, "volume", {
|
||||
set: function( val ) {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
if ( options.youtubeObject.getVolume() / 100 !== val ) {
|
||||
|
||||
options.youtubeObject.setVolume( val * 100 );
|
||||
lastVolume = options.youtubeObject.getVolume();
|
||||
media.dispatchEvent( "volumechange" );
|
||||
}
|
||||
|
||||
setTimeout( volumeupdate, 250 );
|
||||
};
|
||||
|
||||
media.play = function() {
|
||||
return options.youtubeObject.getVolume() / 100;
|
||||
},
|
||||
get: function() {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( media.paused !== false || options.youtubeObject.getPlayerState() !== 1 ) {
|
||||
return options.youtubeObject.getVolume() / 100;
|
||||
}
|
||||
});
|
||||
|
||||
media.paused = false;
|
||||
media.dispatchEvent( "play" );
|
||||
media.play = function() {
|
||||
|
||||
media.dispatchEvent( "playing" );
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
paused = false;
|
||||
playerQueue.add(function() {
|
||||
|
||||
if ( options.youtubeObject.getPlayerState() !== 1 ) {
|
||||
|
||||
seeking = false;
|
||||
options.youtubeObject.playVideo();
|
||||
} else {
|
||||
playerQueue.next();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
timeupdate();
|
||||
options.youtubeObject.playVideo();
|
||||
};
|
||||
media.pause = function() {
|
||||
|
||||
media.pause = function() {
|
||||
if ( options.destroyed ) {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
paused = true;
|
||||
playerQueue.add(function() {
|
||||
|
||||
if ( media.paused !== true || options.youtubeObject.getPlayerState() !== 2 ) {
|
||||
if ( options.youtubeObject.getPlayerState() !== 2 ) {
|
||||
|
||||
media.paused = true;
|
||||
media.dispatchEvent( "pause" );
|
||||
options.youtubeObject.pauseVideo();
|
||||
} else {
|
||||
playerQueue.next();
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
container.id = media.id + Popcorn.guid();
|
||||
options._container = container;
|
||||
media.appendChild( container );
|
||||
|
||||
var youtubeInit = function() {
|
||||
|
||||
var src, height, width, query;
|
||||
|
||||
var timeUpdate = function() {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !seeking ) {
|
||||
currentTime = options.youtubeObject.getCurrentTime();
|
||||
media.dispatchEvent( "timeupdate" );
|
||||
} else if ( currentTime === options.youtubeObject.getCurrentTime() ) {
|
||||
|
||||
seeking = false;
|
||||
media.dispatchEvent( "seeked" );
|
||||
media.dispatchEvent( "timeupdate" );
|
||||
} else {
|
||||
|
||||
// keep trying the seek until it is right.
|
||||
options.youtubeObject.seekTo( currentTime );
|
||||
}
|
||||
setTimeout( timeUpdate, 250 );
|
||||
};
|
||||
|
||||
options.controls = +options.controls === 0 || +options.controls === 1 ? options.controls : 1;
|
||||
options.annotations = +options.annotations === 1 || +options.annotations === 3 ? options.annotations : 1;
|
||||
|
||||
flashvars = {
|
||||
playerapiid: container.id
|
||||
};
|
||||
|
||||
params = {
|
||||
wmode: "transparent",
|
||||
allowScriptAccess: "always"
|
||||
};
|
||||
|
||||
src = /^.*(?:\/|v=)(.{11})/.exec( media.src )[ 1 ];
|
||||
|
||||
query = ( media.src.split( "?" )[ 1 ] || "" )
|
||||
|
@ -323,29 +205,126 @@ Popcorn.player( "youtube", {
|
|||
minutes = minutes | 0; // bit-wise OR
|
||||
seconds = seconds | 0; // bit-wise OR
|
||||
|
||||
return "&start=" + ( +seconds + ( minutes * 60 ) );
|
||||
fragmentStart = ( +seconds + ( minutes * 60 ) );
|
||||
return "";
|
||||
});
|
||||
query = query.replace( /&start=(\d+)?/, function( all, seconds ) {
|
||||
|
||||
// Make sure we have real zeros
|
||||
seconds = seconds | 0; // bit-wise OR
|
||||
|
||||
fragmentStart = seconds;
|
||||
return "";
|
||||
});
|
||||
|
||||
autoPlay = ( /autoplay=1/.test( query ) );
|
||||
|
||||
// setting youtube player's height and width, default to 560 x 315
|
||||
width = media.style.width ? "" + media.offsetWidth : "560";
|
||||
height = media.style.height ? "" + media.offsetHeight : "315";
|
||||
// setting youtube player's height and width, min 640 x 390,
|
||||
// anything smaller, and the player reports incorrect states.
|
||||
height = media.style.height && media.offsetHeight >= 390 ? "" + media.offsetHeight : "390";
|
||||
width = media.style.width && media.offsetWidth >= 640 ? "" + media.offsetWidth : "640";
|
||||
|
||||
attributes = {
|
||||
id: container.id,
|
||||
"data-youtube-player": "//www.youtube.com/e/" + src + "?" + query + "&enablejsapi=1&playerapiid=" + container.id + "&version=3"
|
||||
options.youtubeObject = new YT.Player( container.id, {
|
||||
height: height,
|
||||
width: width,
|
||||
videoId: src,
|
||||
events: {
|
||||
"onReady": function(){
|
||||
|
||||
// pulling initial volume states form baseplayer
|
||||
lastVolume = media.volume;
|
||||
lastMuted = media.muted;
|
||||
|
||||
media.duration = options.youtubeObject.getDuration();
|
||||
|
||||
media.dispatchEvent( "durationchange" );
|
||||
volumeupdate();
|
||||
|
||||
// pulling initial paused state from autoplay or the baseplayer
|
||||
// also need to explicitly set to paused otherwise.
|
||||
if ( autoPlay || !media.paused ) {
|
||||
paused = false;
|
||||
}
|
||||
|
||||
createProperties();
|
||||
options.youtubeObject.playVideo();
|
||||
|
||||
if ( paused ) {
|
||||
options.youtubeObject.pauseVideo();
|
||||
}
|
||||
|
||||
media.currentTime = fragmentStart;
|
||||
|
||||
media.dispatchEvent( "loadedmetadata" );
|
||||
media.dispatchEvent( "loadeddata" );
|
||||
media.readyState = 4;
|
||||
|
||||
timeUpdate();
|
||||
media.dispatchEvent( "canplaythrough" );
|
||||
},
|
||||
"onStateChange": function( state ){
|
||||
|
||||
if ( options.destroyed || state.data === -1 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// state.data === 2 is for pause events
|
||||
// state.data === 1 is for play events
|
||||
if ( state.data === 2 ) {
|
||||
|
||||
paused = true;
|
||||
media.dispatchEvent( "pause" );
|
||||
playerQueue.next();
|
||||
} else if ( state.data === 1 ) {
|
||||
paused = false;
|
||||
media.dispatchEvent( "play" );
|
||||
media.dispatchEvent( "playing" );
|
||||
playerQueue.next();
|
||||
} else if ( state.data === 0 ) {
|
||||
media.dispatchEvent( "ended" );
|
||||
}
|
||||
},
|
||||
"onError": function( error ) {
|
||||
|
||||
if ( [ 2, 100, 101, 150 ].indexOf( error.data ) !== -1 ) {
|
||||
media.error = {
|
||||
customCode: error.data
|
||||
};
|
||||
media.dispatchEvent( "error" );
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var volumeupdate = function() {
|
||||
|
||||
if ( options.destroyed ) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( lastMuted !== options.youtubeObject.isMuted() ) {
|
||||
|
||||
lastMuted = options.youtubeObject.isMuted();
|
||||
media.dispatchEvent( "volumechange" );
|
||||
}
|
||||
|
||||
if ( lastVolume !== options.youtubeObject.getVolume() ) {
|
||||
|
||||
lastVolume = options.youtubeObject.getVolume();
|
||||
media.dispatchEvent( "volumechange" );
|
||||
}
|
||||
|
||||
setTimeout( volumeupdate, 250 );
|
||||
};
|
||||
|
||||
swfobject.embedSWF( attributes[ "data-youtube-player" ], container.id, width, height, "8", undefined, flashvars, params, attributes );
|
||||
};
|
||||
|
||||
if ( !window.swfobject ) {
|
||||
|
||||
Popcorn.getScript( "//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", youtubeInit );
|
||||
} else {
|
||||
if ( onYouTubePlayerAPIReady.ready ) {
|
||||
|
||||
youtubeInit();
|
||||
} else {
|
||||
|
||||
onYouTubePlayerAPIReady.waiting.push( youtubeInit );
|
||||
}
|
||||
},
|
||||
_teardown: function( options ) {
|
||||
|
|
|
@ -215,13 +215,13 @@ asyncTest("Update Timer", function () {
|
|||
});
|
||||
|
||||
p2.exec( 3, function() {
|
||||
|
||||
p2.play();
|
||||
});
|
||||
|
||||
var ready = function() {
|
||||
p2.off( "canplaythrough", ready );
|
||||
p2.volume( 0 ).currentTime(3);
|
||||
|
||||
p2.volume( 0 ).currentTime( 3 );
|
||||
};
|
||||
|
||||
if ( p2.readyState() >= 4 ) {
|
||||
|
@ -364,8 +364,10 @@ asyncTest( "Popcorn YouTube Plugin Url and Duration Tests", function() {
|
|||
|
||||
expect( expects );
|
||||
|
||||
equal( popcorn.media.id, 'video2', 'Video id set' );
|
||||
plus();
|
||||
popcorn.on( "canplaythrough", function() {
|
||||
equal( popcorn.media.id, 'video2', 'Video id set' );
|
||||
plus();
|
||||
});
|
||||
|
||||
popcorn.listen( "durationchange", function() {
|
||||
|
||||
|
@ -436,71 +438,6 @@ asyncTest( "Popcorn YouTube Plugin Url Regex Test", function() {
|
|||
});
|
||||
});
|
||||
|
||||
asyncTest( "Controls and Annotations toggling", function() {
|
||||
|
||||
var count = 0,
|
||||
expects = 6,
|
||||
testTarget = "",
|
||||
targetDiv;
|
||||
|
||||
function plus(){
|
||||
if ( ++count == expects ) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
expect( expects );
|
||||
|
||||
var popcorn1 = Popcorn.youtube( "#video", "http://www.youtube.com/watch?v=nfGV32RNkhw" );
|
||||
|
||||
popcorn1.listen( "loadeddata", function() {
|
||||
|
||||
targetDiv = document.getElementById( "video" );
|
||||
testTarget = targetDiv.querySelector( "object" ).getAttribute( "data-youtube-player" );
|
||||
|
||||
popcorn1.volume( 0 );
|
||||
|
||||
ok( !/controls/.test( testTarget ), "controls are defaulted to 1 ( displayed )" );
|
||||
plus();
|
||||
ok( !/iv_load_policy/.test( testTarget ), "annotations ( iv_load_policy ) are defaulted to ( enabled )" );
|
||||
plus();
|
||||
|
||||
popcorn1.destroy();
|
||||
|
||||
var popcorn2 = Popcorn.youtube( "#video", "http://www.youtube.com/watch?v=nfGV32RNkhw&controls=1&iv_load_policy=1" );
|
||||
popcorn2.listen( "loadeddata", function() {
|
||||
|
||||
targetDiv = document.getElementById( "video" );
|
||||
testTarget = targetDiv.querySelector( "object" ).getAttribute( "data-youtube-player" );
|
||||
|
||||
popcorn2.volume( 0 );
|
||||
|
||||
ok( /controls=1/.test( testTarget ), "controls is set to 1 ( displayed )" );
|
||||
plus();
|
||||
ok( /iv_load_policy=1/.test( testTarget ), "annotations ( iv_load_policy ) is set to 1 ( enabled )" );
|
||||
plus();
|
||||
|
||||
popcorn2.destroy();
|
||||
|
||||
var popcorn3 = Popcorn.youtube( "#video", "http://www.youtube.com/watch?v=nfGV32RNkhw&controls=0&iv_load_policy=3" );
|
||||
popcorn3.listen( "loadeddata", function() {
|
||||
|
||||
targetDiv = document.getElementById( "video" );
|
||||
testTarget = targetDiv.querySelector( "object" ).getAttribute( "data-youtube-player" );
|
||||
|
||||
popcorn3.volume( 0 );
|
||||
|
||||
ok( /controls=0/.test( testTarget ), "controls is set to 0 ( hidden )" );
|
||||
plus();
|
||||
ok( /iv_load_policy=3/.test( testTarget ), "annotations ( iv_load_policy ) is set to 3 ( hidden )" );
|
||||
plus();
|
||||
|
||||
popcorn3.destroy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest( "Player height and width", function() {
|
||||
|
||||
expect( 4 );
|
||||
|
@ -514,11 +451,11 @@ asyncTest( "Player height and width", function() {
|
|||
setTimeout( readyStatePoll, 10 );
|
||||
} else {
|
||||
|
||||
equal( popcorn1.media.children[ 0 ].width, 560, "Youtube player default width is 560" );
|
||||
equal( popcorn1.media.children[ 0 ].height, 315, "Youtube player default height is 315" );
|
||||
equal( popcorn1.media.children[ 0 ].width, 640, "Youtube player default width is 560" );
|
||||
equal( popcorn1.media.children[ 0 ].height, 390, "Youtube player default height is 315" );
|
||||
|
||||
equal( popcorn2.media.children[ 0 ].getAttribute( "width" ), 1, "Youtube player explicit width is 1" );
|
||||
equal( popcorn2.media.children[ 0 ].getAttribute( "height" ), 1, "Youtube player explicit height is 1" );
|
||||
equal( popcorn2.media.children[ 0 ].getAttribute( "width" ), 640, "Youtube player min width is 640" );
|
||||
equal( popcorn2.media.children[ 0 ].getAttribute( "height" ), 390, "Youtube player min height is 390" );
|
||||
|
||||
popcorn1.destroy();
|
||||
popcorn2.destroy();
|
||||
|
@ -532,41 +469,6 @@ asyncTest( "Player height and width", function() {
|
|||
readyStatePoll();
|
||||
});
|
||||
|
||||
asyncTest( "Popcorn Youtube Plugin offsetHeight && offsetWidth Test", function() {
|
||||
|
||||
var popped,
|
||||
elem,
|
||||
expects = 2,
|
||||
count = 0;
|
||||
|
||||
expect( expects );
|
||||
|
||||
function plus() {
|
||||
if ( ++count === expects ) {
|
||||
|
||||
popped.destroy();
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
popped = Popcorn.youtube( "#video6", "http://www.youtube.com/watch?v=nfGV32RNkhw" );
|
||||
|
||||
var runner = function() {
|
||||
popped.volume( 0 );
|
||||
elem = document.querySelector( "div#video6 object" );
|
||||
equal( elem.height, popped.media.offsetHeight, "The media object is reporting the correct offsetHeight" );
|
||||
plus();
|
||||
equal( elem.width, popped.media.offsetWidth, "The media object is reporting the correct offsetWidth" );
|
||||
plus();
|
||||
};
|
||||
|
||||
if ( popped.readyState >= 2 ) {
|
||||
runner();
|
||||
} else {
|
||||
popped.listen( "loadeddata", runner);
|
||||
}
|
||||
});
|
||||
|
||||
asyncTest( "Player Errors", function() {
|
||||
|
||||
expect( 2 );
|
||||
|
@ -676,7 +578,9 @@ asyncTest( "Youtube ready state events", function() {
|
|||
asyncTest( "Youtube media start time fragment", function() {
|
||||
|
||||
var popcorn1, popcorn2, popcorn3, popcorn4,
|
||||
count = 0, expects = 4;
|
||||
count = 0, expects = 4,
|
||||
// Youtube's fragment can be off by give or take a second.
|
||||
epsilon = 1;
|
||||
|
||||
expect( expects );
|
||||
|
||||
|
@ -694,25 +598,25 @@ asyncTest( "Youtube media start time fragment", function() {
|
|||
var firstTest = function() {
|
||||
|
||||
popcorn1.off( "loadeddata", firstTest );
|
||||
equal( Math.floor( popcorn1.currentTime() ), 130, "youtube fragment works with &start=130" );
|
||||
ok( Math.ceil( popcorn1.currentTime() ) + epsilon >= 130, "youtube fragment works with &start=130" );
|
||||
plus();
|
||||
},
|
||||
secondTest = function() {
|
||||
|
||||
popcorn2.off( "loadeddata", secondTest );
|
||||
equal( Math.floor( popcorn2.currentTime() ), 130, "youtube fragment works with &t=2m10s" );
|
||||
ok( Math.ceil( popcorn2.currentTime() ) + epsilon >= 130, "youtube fragment works with &t=2m10s" );
|
||||
plus();
|
||||
},
|
||||
thirdTest = function() {
|
||||
|
||||
popcorn3.off( "loadeddata", thirdTest );
|
||||
equal( Math.floor( popcorn3.currentTime() ), 120, "youtube fragment works with &t=2m" );
|
||||
ok( Math.ceil( popcorn3.currentTime() ) + epsilon >= 120, "youtube fragment works with &t=2m" );
|
||||
plus();
|
||||
},
|
||||
fourthTest = function() {
|
||||
|
||||
popcorn4.off( "loadeddata", fourthTest );
|
||||
equal( Math.floor( popcorn4.currentTime() ), 10, "youtube fragment works with &t=10s" );
|
||||
ok( Math.ceil( popcorn4.currentTime() )+ epsilon >= 10, "youtube fragment works with &t=10s" );
|
||||
plus();
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче