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