Getting control of YouTube via Javascript
by Matt Reimer | October 7th, 2011 | Comments
Recently I was trying to write a WordPress slideshow plugin that would include YouTube videos. The challenge was that when I play the video I want to pause the slide. On regular picture slides I just needed to add a click() event listener to the slide object and attach a call to pause jQueryCycle. YouTube, though, refused to take the click() listener seriously. The solution came to me by reading up on the Youtube player api. I must say I'm a bit surprised that WordPress doesn't turn this on by default in its [embed] tag but here is my solution in the hopes that I can save someone else the trouble of finding this out again.
Step 1: Opt in to Use the API
Wordpress oembed doesn't turn add enablejsapi=1 to the embedded url when you use the embed shortcode
<code>//add ENABLEjsAPI to youtube videos //With mad props to mehigh http://mehigh.biz/wordpress/adding-wmode-transparent-to-wordpress-3-media-embeds.html function add_video_wmode_transparent($html, $url, $attr) { $pattern = '/(youtube.com\/)(v\/\w+\?version=\d+)/i'; $add = '&enablejsapi=1'; $new_pattern = "$1$2$add$3"; $html = preg_replace($pattern, $new_pattern, $html); if (strpos($html, "<embed src=" ) !== false) { $html = str_replace('&lt;/param&gt;&lt;embed', '&lt;/param&gt;&lt;param name=" value="1"></embed><param name="wmode" value="transparent" /><embed wmode="transparent"></embed></code>
What you end up with is the following:
<object height="330" width="440"><param name="movie" value="http://www.youtube.com/v/fxQWbMenYCc?version=3&enablejsapi=1" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="enablejsapi" value="1" /><param name="wmode" value="transparent" /><embed allowfullscreen="true" allowscriptaccess="always" height="330" src="http://www.youtube.com/v/fxQWbMenYCc?version=3&enablejsapi=1" type="application/x-shockwave-flash" width="440" wmode="transparent"></embed></object>
This code is doing a couple of things with a really basic hack that rewrites the oembed html as it's passing through to being printed.
- Tack on '&enablejsapi=1' to the embedded url
- add <param> tags to the
&lt;object&gt;tag: We're addingenablejsapi=1andwmode =transparent. wmode is a parameter that will allow Youtube videos to exist underneath our dropdown menus.
In the end these two steps were a little hack-y so if anyone knows a better way to override the [embed] shortcode functionality I'm all ears.
Step 2: Capture the youtube clicks
Now that we have access to the YouTube API we need to capture the clicks that come into it:
<code> /***************************************************** Capture Youtube clicks so we can pause our slideshow when video plays. *****************************************************/ function onYouTubePlayerReady(){ var players = jQuery('#basic_slideshow embed').each(function(){ if (this.addEventListener) { this.addEventListener('onStateChange', 'handlePlayerStateChange'); } else { this.attachEvent('onStateChange', 'handlePlayerStateChange'); } }); } </code>
Ok. Now we've got the listeners in place to spy on YouTube for us. It's time to write one more little function to give instructions when things change.
<code> function handlePlayerStateChange (state) { var slideshow = jQuery('#basic_slideshow div.list'); switch (state) { case 1: case 3: // Video has begun playing/buffering slideshow.cycle('pause'); break; case 2: case 0: // Video has been paused/ended slideshow.cycle('resume'); break; } } </code>
I'll have to find some way to do it for Vimeo at some point but that uses iframes so it's a little different. Also, YouTube videos seem to be smart enough to pause themselves when jQueryCycle changes the slide and Vimeo videos just keep playing in the background.