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