To demonstrate the breaking change I discovered today I took the basic JS API sample page which can be found with link below and simply commented out the videoId parameter:
YT Sample Code demonstrating initialization error: http://www.multitask123.com/fmgem/YT_Sample2.htm
With said removal of videoId parameter the player will now display/initialize with the following error message in the embedded player, "An error occurred. Please try later." This was not the case until this afternoon.
For the past three months I could call onYouTubePlayerAPIReady as follows and there would be no error message:
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
//videoId: 'JW5meKfy3fY', - COMMENTED OUT INTENTIONALLY! HARD REQUIREMENT!
events: {
'onReady': onPlayerReady,
'onError': onPlayerError,
'onStateChange': onPlayerStateChange
}
});
}
The error is caught by the onPlayerError event handler during initialization and the error comes in with the "evt" parameter's data attribute. So onPlayerError(evt) is called on initialization and evt.data = 2. This value is documented as, "The request contains an invalid parameter value" which is clearly the API expecting a videoId.
I do not want to go into too much detail but I spent countless hours getting the initialization of the player to work just right as there are numerous cross browser initialization issues. I need to hide the player until I actually need it to play something.
I forget which browser is the culprit but one of them actually forces me to show the player even though no video is playing.
I discovered I cannot lazy load/JIT the embedded player because it loads asynchronously so if I try to only load it when my users wish to actually view a video or there are other parameters of the URL involved that will load a playlist for example the player will balk because I cannot BOTH initialize the player and ask it to play a video.
So the bottom line is the player NEEDS to be initialized when the page is loading but NOT with a videoId parameter because quite simply I have no idea what is going to be played in 90% of the circumstances and even if I did that would be the result of a different asynchronous call to a different API. I say this because the solution to initialize it with a videoid is unacceptable.
The YouTube API is amazing and I love it so much so that I have spent 18 months developing http://www.fmgem.com and now this breaking change is ruining the first impression beta users will have of my app. So if the YT API team does indeed monitor this please change it back. Pretty please with sugar on top. :))
Something similar happened a few weeks ago with the same function's wmode attribute on load.
//wmode: 'opaque' //--- causes wicked bug in Chrome - And I was able to change opaque to transparent so no biggie there but this would require me to review my entire architecture and methodically handle apx 9 different asynchronous use-cases for load that again, have all had cross-browser quirks.
So I cannot afford to be reactive and I have been forced to put in a "sneezing baby panda" videoId into the live code at http://www.fmgem.com but that looks quite unprofessional and it is merely a band-aid until I can review the entire architecture unless YT Team actually acknowledges this as a breaking change and then puts it back to its prior behavior.
This was detected by some users sometime during the afternoon of 2/27/2013 and I have read on google groups that YouTube's developers monitor SO.
Any answers, solutions, guidance or confirmation would be greatly appreciated.
Thanks!!
You can initially load a blank 0 second movie. Or you can re-arrange your code a tad bit.
Do not call
onYouTubePlayerAPIReady
function yourself. Use flag variables instead:Set the first variable when the API file calls
onYouTubePlayerAPIReady
function:Set the second variable when the user chooses to play first video:
Re-use the same player for subsequent videos as shown in the
else
block.I'm not ruling out that something may have changed on Feb. 27, but the intention has always been that
videoId
(or a list id) is required when initializing an iframe Player. It isn't spelled out explicitly in the documentation, but at the same time, it never suggests that the parameter is optional, and all examples given do include a value forvideoId
.So I wouldn't count on this behavior changing back in the future.
The most common thing to do when you have a YouTube iframe Player that you want to be initialized and not visible is to use CSS to set its position outside of the viewable area in the browser (such as by using negative
x
andy
coordinates). You can initialize the player with whatever placeholder video you want, then callloadVideoById()
when you're ready to play back a real video, and when you detectonStateChange
withYT.PlayerState.BUFFERING
orYT.PlayerState.PLAYING
, you can move the player to the appropriate visible position.Alternatively, you can just delay loading the player until you need it.
While this is a breaking change beyond a doubt now that I got a good night's sleep I found a solution to my own issue to lazy load / JIT the player.
The solution I have a proof of concept of and am currently implementing is as simple as setting a global var to test if I have a videoid.
Then when I actually want to play a video I just see if the variable is false and if so I call the onYouTubePlayerAPIReady function and pass it the videoid and initialize it. My mistake was to try to initialize and then call the play() function in the same call. The solution for me is to either call the initializer with an id or call the playbyid function if already initialized.
While I do love the YT public API and others that I use it does open the door to lots of breaking changes and that is always a test of one's architectural and mental fortitude.