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