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