1 /** The minplayer namespace. */
  2 var minplayer = minplayer || {};
  3 
  4 /** All the media player implementations */
  5 minplayer.players = minplayer.players || {};
  6 
  7 /**
  8  * @constructor
  9  * @extends minplayer.players.base
 10  * @class The YouTube media player.
 11  *
 12  * @param {object} context The jQuery context.
 13  * @param {object} options This components options.
 14  */
 15 minplayer.players.youtube = function(context, options) {
 16 
 17   /** The quality of the YouTube stream. */
 18   this.quality = 'default';
 19 
 20   // Derive from players base.
 21   minplayer.players.base.call(this, context, options);
 22 };
 23 
 24 /** Derive from minplayer.players.base. */
 25 minplayer.players.youtube.prototype = new minplayer.players.base();
 26 
 27 /** Reset the constructor. */
 28 minplayer.players.youtube.prototype.constructor = minplayer.players.youtube;
 29 
 30 /**
 31  * @see minplayer.players.base#getPriority
 32  * @return {number} The priority of this media player.
 33  */
 34 minplayer.players.youtube.getPriority = function() {
 35   return 10;
 36 };
 37 
 38 /**
 39  * @see minplayer.players.base#canPlay
 40  * @return {boolean} If this player can play this media type.
 41  */
 42 minplayer.players.youtube.canPlay = function(file) {
 43 
 44   // Check for the mimetype for youtube.
 45   if (file.mimetype === 'video/youtube') {
 46     return true;
 47   }
 48 
 49   // If the path is a YouTube path, then return true.
 50   return (file.path.search(/^http(s)?\:\/\/(www\.)?youtube\.com/i) === 0);
 51 };
 52 
 53 /**
 54  * Return the ID for a provided media file.
 55  *
 56  * @param {object} file A {@link minplayer.file} object.
 57  * @return {string} The ID for the provided media.
 58  */
 59 minplayer.players.youtube.getMediaId = function(file) {
 60   var regex = /^http[s]?\:\/\/(www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9]+)/i;
 61   if (file.path.search(regex) === 0) {
 62     return file.path.replace(regex, '$2');
 63   }
 64   else {
 65     return file.path;
 66   }
 67 };
 68 
 69 /**
 70  * Register this youtube player so that multiple players can be present
 71  * on the same page without event collision.
 72  */
 73 minplayer.players.youtube.prototype.register = function() {
 74 
 75   /**
 76    * Register the standard youtube api ready callback.
 77    */
 78   window.onYouTubePlayerAPIReady = function() {
 79 
 80     // Iterate over each media player.
 81     jQuery.each(minplayer.get(null, 'player'), function(id, player) {
 82 
 83       // Make sure this is the youtube player.
 84       if (player.currentPlayer == 'youtube') {
 85 
 86         // Create a new youtube player object for this instance only.
 87         var playerId = id + '-player';
 88 
 89         // Set this players media.
 90         player.media.player = new YT.Player(playerId, {
 91           events: {
 92             'onReady': function(event) {
 93               player.media.onReady(event);
 94             },
 95             'onStateChange': function(event) {
 96               player.media.onPlayerStateChange(event);
 97             },
 98             'onPlaybackQualityChange': function(newQuality) {
 99               player.media.onQualityChange(newQuality);
100             },
101             'onError': function(errorCode) {
102               player.media.onError(errorCode);
103             }
104           }
105         });
106       }
107     });
108   }
109 };
110 
111 /**
112  * Translates the player state for the YouTube API player.
113  *
114  * @param {number} playerState The YouTube player state.
115  */
116 minplayer.players.youtube.prototype.setPlayerState = function(playerState) {
117   switch (playerState) {
118     case YT.PlayerState.CUED:
119       break;
120     case YT.PlayerState.BUFFERING:
121       this.onWaiting();
122       break;
123     case YT.PlayerState.PAUSED:
124       this.onPaused();
125       break;
126     case YT.PlayerState.PLAYING:
127       this.onPlaying();
128       break;
129     case YT.PlayerState.ENDED:
130       this.onComplete();
131       break;
132     default:
133       break;
134   }
135 };
136 
137 /**
138  * Called when an error occurs.
139  *
140  * @param {string} event The onReady event that was triggered.
141  */
142 minplayer.players.youtube.prototype.onReady = function(event) {
143   minplayer.players.base.prototype.onReady.call(this);
144   this.onLoaded();
145 };
146 
147 /**
148  * Checks to see if this player can be found.
149  * @return {bool} TRUE - Player is found, FALSE - otherwise.
150  */
151 minplayer.players.youtube.prototype.playerFound = function() {
152   var iframe = this.display.find('iframe#' + this.options.id + '-player');
153   return (iframe.length > 0);
154 };
155 
156 /**
157  * Called when the player state changes.
158  *
159  * @param {object} event A JavaScript Event.
160  */
161 minplayer.players.youtube.prototype.onPlayerStateChange = function(event) {
162   this.setPlayerState(event.data);
163 };
164 
165 /**
166  * Called when the player quality changes.
167  *
168  * @param {string} newQuality The new quality for the change.
169  */
170 minplayer.players.youtube.prototype.onQualityChange = function(newQuality) {
171   this.quality = newQuality;
172 };
173 
174 /**
175  * Determines if the player should show the playloader.
176  *
177  * @return {bool} If this player implements its own playLoader.
178  */
179 minplayer.players.youtube.prototype.hasPlayLoader = function() {
180   return true;
181 };
182 
183 /**
184  * @see minplayer.players.base#create
185  * @return {object} The media player entity.
186  */
187 minplayer.players.youtube.prototype.create = function() {
188   minplayer.players.base.prototype.create.call(this);
189 
190   // Insert the YouTube iframe API player.
191   var tag = document.createElement('script');
192   tag.src = 'http://www.youtube.com/player_api?enablejsapi=1';
193   var firstScriptTag = document.getElementsByTagName('script')[0];
194   firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
195 
196   // Now register this player.
197   this.register();
198 
199   // Create the iframe for this player.
200   var iframe = document.createElement('iframe');
201   iframe.setAttribute('id', this.options.id + '-player');
202   iframe.setAttribute('type', 'text/html');
203   iframe.setAttribute('width', '100%');
204   iframe.setAttribute('height', '100%');
205   iframe.setAttribute('frameborder', '0');
206 
207   // Get the source.
208   var src = 'http://www.youtube.com/embed/';
209   src += this.mediaFile.id + '?';
210 
211   // Determine the origin of this script.
212   var origin = location.protocol;
213   origin += '//' + location.hostname;
214   origin += (location.port && ':' + location.port);
215 
216   // Add the parameters to the src.
217   src += jQuery.param({
218     'wmode': 'opaque',
219     'controls': 0,
220     'enablejsapi': 1,
221     'origin': origin,
222     'autoplay': this.options.autoplay,
223     'loop': this.options.loop
224   });
225 
226   // Set the source of the iframe.
227   iframe.setAttribute('src', src);
228 
229   // Return the player.
230   return iframe;
231 };
232 
233 /**
234  * @see minplayer.players.base#load
235  */
236 minplayer.players.youtube.prototype.load = function(file) {
237   minplayer.players.base.prototype.load.call(this, file);
238   if (file && this.isReady()) {
239     this.player.loadVideoById(file.id, 0, this.quality);
240   }
241 };
242 
243 /**
244  * @see minplayer.players.base#play
245  */
246 minplayer.players.youtube.prototype.play = function() {
247   minplayer.players.base.prototype.play.call(this);
248   if (this.isReady()) {
249     this.player.playVideo();
250   }
251 };
252 
253 /**
254  * @see minplayer.players.base#pause
255  */
256 minplayer.players.youtube.prototype.pause = function() {
257   minplayer.players.base.prototype.pause.call(this);
258   if (this.isReady()) {
259     this.player.pauseVideo();
260   }
261 };
262 
263 /**
264  * @see minplayer.players.base#stop
265  */
266 minplayer.players.youtube.prototype.stop = function() {
267   minplayer.players.base.prototype.stop.call(this);
268   if (this.isReady()) {
269     this.player.stopVideo();
270   }
271 };
272 
273 /**
274  * @see minplayer.players.base#seek
275  */
276 minplayer.players.youtube.prototype.seek = function(pos) {
277   minplayer.players.base.prototype.seek.call(this, pos);
278   if (this.isReady()) {
279     this.player.seekTo(pos, true);
280   }
281 };
282 
283 /**
284  * @see minplayer.players.base#setVolume
285  */
286 minplayer.players.youtube.prototype.setVolume = function(vol) {
287   minplayer.players.base.prototype.setVolume.call(this, vol);
288   if (this.isReady()) {
289     this.player.setVolume(vol * 100);
290   }
291 };
292 
293 /**
294  * @see minplayer.players.base#getVolume
295  */
296 minplayer.players.youtube.prototype.getVolume = function(callback) {
297   if (this.isReady()) {
298     callback(this.player.getVolume());
299   }
300 };
301 
302 /**
303  * @see minplayer.players.base#getDuration.
304  */
305 minplayer.players.youtube.prototype.getDuration = function(callback) {
306   if (this.isReady()) {
307     callback(this.player.getDuration());
308   }
309 };
310 
311 /**
312  * @see minplayer.players.base#getCurrentTime
313  */
314 minplayer.players.youtube.prototype.getCurrentTime = function(callback) {
315   if (this.isReady()) {
316     callback(this.player.getCurrentTime());
317   }
318 };
319 
320 /**
321  * @see minplayer.players.base#getBytesStart.
322  */
323 minplayer.players.youtube.prototype.getBytesStart = function(callback) {
324   if (this.isReady()) {
325     callback(this.player.getVideoStartBytes());
326   }
327 };
328 
329 /**
330  * @see minplayer.players.base#getBytesLoaded.
331  */
332 minplayer.players.youtube.prototype.getBytesLoaded = function(callback) {
333   if (this.isReady()) {
334     callback(this.player.getVideoBytesLoaded());
335   }
336 };
337 
338 /**
339  * @see minplayer.players.base#getBytesTotal.
340  */
341 minplayer.players.youtube.prototype.getBytesTotal = function(callback) {
342   if (this.isReady()) {
343     callback(this.player.getVideoBytesTotal());
344   }
345 };
346