1 /** 2 * @author Gillis Haasnoot <gillis.haasnoot@gmail.com> 3 * @package Banana.Controls 4 * @summary Youtube iframe player experimental control. 5 */ 6 7 goog.provide('Banana.Controls.YoutubeIFramePlayer'); 8 9 /** @namespace Banana.Controls.YoutubeIFramePlayer*/ 10 namespace('Banana.Controls').YoutubeIFramePlayer = Banana.Controls.Panel.extend({ 11 /** @lends Banana.Controls.YoutubeIFramePlayer.prototype */ 12 13 /** 14 * Creates highly experimental youtube iframe player 15 * 16 * Example: 17 18 var player = new YoutubeIFramePlayer(400,300); 19 player.bind('onPlayerReady',this.getProxy(function(){ 20 21 p.setVolume(0); 22 p.loadVideoById("Hyw7OYU0_mE"); 23 24 })); 25 26 //event triggered when duration of the videoitem is known 27 player.bind('onDurationKnown',this.getProxy(function(e,time){ 28 29 console.log(time.getTime()); 30 })) 31 32 33 * @constructs 34 * @extends Banana.Controls.Panel 35 */ 36 init : function(width,height) 37 { 38 this._super(); 39 40 this.height = height; 41 this.width = width; 42 43 this.createRequiredApiStructures(); 44 }, 45 46 createRequiredApiStructures : function() 47 { 48 //load required script files. we do this only once 49 //other player instances wont load these scripts again 50 if (!window.youtubeApiScripsLoaded) 51 { 52 var tag = document.createElement('script'); 53 tag.src = "http://www.youtube.com/player_api?wmode=transparent"; 54 var firstScriptTag = document.getElementsByTagName('script')[0]; 55 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 56 57 window.youtubeApiScripsLoaded = true; 58 } 59 60 //make player globally available to get access from onYouTubePlayerReadyevent 61 if (!window.queuedBananaYouTubePlayers) 62 { 63 window.queuedBananaYouTubePlayers = []; 64 } 65 66 if (!window.youtubeApiReadyCallback) 67 { 68 //after api is ready we create the queued players 69 window.onYouTubePlayerAPIReady= function(id) 70 { 71 for (var i =0; i < window.queuedBananaYouTubePlayers.length; i++) 72 { 73 window.queuedBananaYouTubePlayers[i](); 74 } 75 76 window.youtubeApiReady = true; 77 } 78 } 79 }, 80 81 isApiReady : function() 82 { 83 return window.youtubeApiReady == true; 84 }, 85 86 unload : function() 87 { 88 //these are not automatically cleaned by banana 89 window.queuedBananaYouTubePlayers = undefined; 90 }, 91 92 createComponents : function() 93 { 94 this.placeHolder = new Banana.Controls.Panel(); 95 this.buttonHolder = new Banana.Controls.Panel(); 96 97 this.addControl(this.placeHolder); 98 this.addControl(this.buttonHolder); 99 }, 100 101 /** 102 * We create the player when everything is fully rendered 103 */ 104 updateDisplay : function() 105 { 106 this.createPlayer(); 107 }, 108 109 createPlayer : function() 110 { 111 this.placeHolder.clear(); 112 113 var dim = this.getDimensions(); 114 115 if (!this.height) 116 { 117 this.height = dim.height; 118 } 119 120 if (!this.width) 121 { 122 this.width = dim.width; 123 } 124 125 //dont add the player again after i.e rerender 126 if (this.added) 127 { 128 return; 129 } 130 this.added = true; 131 132 //if player api not available we put them in a que 133 window.queuedBananaYouTubePlayers.push(this.getProxy(function(data){ 134 135 return this.getProxy(function(){ 136 137 this.player = new YT.Player(data.id, { 138 height: data.height, 139 width: data.width, 140 playerVars:{'wmode':'transparent', 141 'cc_load_policy':0, 142 'iv_load_policy':3, 143 'showinfo':0, 144 'rel':0, 145 'modestbranding':1, 146 'controls':0, 147 'showsearch':0 148 149 }, 150 // videoId: data.data, 151 events: { 152 'onReady': this.getProxy(function(e){ this.playerIsReady(e);}), 153 'onStateChange': this.getProxy(function(e){ this.playerStateChanged(e);}), 154 'onError': this.getProxy(function(e){ this.playerIsErrored(e);}) 155 } 156 }); 157 }) 158 })({'id':this.placeHolder.getClientId(),'data':this.data,'width':this.width,'height':this.height})); 159 160 //create directly when api is ready 161 if (this.isApiReady()) 162 { 163 window.queuedBananaYouTubePlayers[window.queuedBananaYouTubePlayers.length-1](); 164 } 165 }, 166 167 /** 168 * Loads video by id. 169 * this can only be done after the videoplayer is available 170 * 171 * @param {int} id 172 */ 173 loadVideoById : function(id,startSeconds) 174 { 175 if (!this.getPlayer()) 176 { 177 console.log(this.id,'no player'); 178 return; 179 } 180 181 //reset duration 182 this.duration = null; 183 184 this.getPlayer().loadVideoById(id,startSeconds); 185 }, 186 187 /** 188 * Loads video by id. 189 * this can only be done after the videoplayer is available 190 * 191 * @param {int} id 192 */ 193 cueVideoById : function(id, startSeconds) 194 { 195 if (!this.getPlayer()) 196 { 197 console.log(this.id,'no player'); 198 return; 199 } 200 201 //reset duration 202 this.duration = null; 203 204 this.getPlayer().cueVideoById(id,startSeconds); 205 }, 206 207 /** 208 * @param {int} 209 */ 210 setVolume : function(v) 211 { 212 if (!this.getPlayer()) 213 { 214 log.error("no player"); 215 return; 216 } 217 218 this.getPlayer().setVolume(v); 219 }, 220 221 mute : function() 222 { 223 if (!this.getPlayer()) 224 { 225 log.error("no player"); 226 return; 227 } 228 229 this.isMutedPasv = true; 230 this.getPlayer().mute(); 231 }, 232 233 unMute : function() 234 { 235 if (!this.getPlayer()) 236 { 237 log.error("no player"); 238 return; 239 } 240 this.isMutedPasv = false; 241 this.getPlayer().unMute(); 242 }, 243 244 isMuted : function(passive) 245 { 246 if (passive) 247 { 248 return this.isMutedPasv; 249 } 250 251 if (!this.getPlayer()) 252 { 253 log.error("no player"); 254 return null; 255 } 256 257 return this.getPlayer().isMuted(); 258 }, 259 260 /** 261 * @return {int} 262 */ 263 getDuration : function() 264 { 265 if (!this.getPlayer()) 266 { 267 log.error("no player"); 268 return; 269 } 270 271 return this.getPlayer().getDuration(); 272 }, 273 274 /** 275 * @return {int} 276 */ 277 getCurrentTime : function() 278 { 279 if (!this.getPlayer()) 280 { 281 log.error("no player"); 282 return; 283 } 284 285 return new Banana.Util.DateTimecode(this.getPlayer().getCurrentTime()*1000); 286 }, 287 288 /** 289 * @return {int}; 290 */ 291 getPlayerState: function() 292 { 293 if (!this.getPlayer()) 294 { 295 log.error("no player"); 296 return; 297 } 298 299 return this.getPlayer().getPlayerState(); 300 }, 301 302 /** 303 * @param {int} seekTo 304 * @param {boolean} allowSeekAhead 305 */ 306 seekTo : function(seekTo,allowSeekAhead) 307 { 308 if (!this.getPlayer()) 309 { 310 log.error("no player"); 311 return; 312 } 313 314 return this.getPlayer().seekTo(seekTo,allowSeekAhead); 315 }, 316 317 playVideo : function() 318 { 319 if (!this.getPlayer()) 320 { 321 log.error("no player"); 322 return; 323 } 324 325 return this.getPlayer().playVideo(); 326 }, 327 328 pauseVideo : function() 329 { 330 if (!this.getPlayer()) 331 { 332 log.error("no player"); 333 return; 334 } 335 336 return this.getPlayer().pauseVideo(); 337 }, 338 339 340 stopVideo : function() 341 { 342 if (!this.getPlayer()) 343 { 344 log.error("no player"); 345 return; 346 } 347 348 return this.getPlayer().stopVideo(); 349 }, 350 351 /** 352 * @return {Object} 353 */ 354 getPlayer : function() 355 { 356 if (!this.playerReady) 357 { 358 log.error("no player"); 359 return; 360 } 361 362 return this.player; 363 }, 364 365 playerStateChanged : function(e) 366 { 367 ///logic to determine media duration 368 //duration is known some time after media is playin 369 if (this.duration != this.getDuration()) 370 { 371 this.duration = this.getDuration(); 372 this.triggerEvent("onDurationKnown",new Banana.Util.DateTimecode(this.duration*1000)); 373 } 374 375 this.triggerEvent('onPlayerStateChanged',e); 376 }, 377 378 /** 379 * Fired when player is ready 380 */ 381 playerIsReady : function(e) 382 { 383 this.playerReady = true; 384 385 try 386 { 387 this.triggerEvent('onPlayerReady',e); 388 } 389 catch(e) 390 { 391 console.log(e) 392 } 393 }, 394 395 /** 396 * Fired when player is errored 397 */ 398 playerIsErrored : function(e) 399 { 400 this.triggerEvent('onPlayerError',e); 401 } 402 });