Hi, I'm using Views Slideshow to show a slideshow of youtube videos, each embedded in their own content item.

When the user starts a video, then clicks Next while the video is still playing, the slideshow advances to the next slide but the previous slide's video does not stop playing (all browsers). The user can then click play on the next video, and two videos will be playing at once. If the user advances to the next slide, they could potentially start a third simultaneous video, and so on. I would like to stop any currently playing videos when the user clicks Next to move on to the next slide.

I know there must be a js solution to this, but I'm a js noob... is there anyone who can provide some simple code to prevent multiple videos on different slides from ever being played at the same time?
Thank you for your help.

Comments

vrMarc’s picture

Here's what I did to get this to work. I haven't tested it completely and there are better ways but I wanted to share my quick and dirty solution with you. Once I get it going the Drupal way I'll post that solution. Rob W did the heavy lifting - http://jsfiddle.net/8R5y6/

1) My slideshow is using text controls
2) in modules/views_slideshow/js/views_slideshow.js I added: callPlayer("videoID","stopVideo"); to this section of code -

// Process next link
      $('.views_slideshow_controls_text_next:not(.views-slideshow-controls-text-next-processed)', context).addClass('views-slideshow-controls-text-next-processed').each(function() {
        var uniqueID = $(this).attr('id').replace('views_slideshow_controls_text_next_', '');
        $(this).click(function() {
          Drupal.viewsSlideshow.action({ "action": 'nextSlide', "slideshowID": uniqueID });
		   callPlayer("videoID","stopVideo");
          return false;

3) My node looks like this:

<div id="videoID">
	<iframe allowfullscreen="" frameborder="0" height="259" src="http://www.youtube.com/embed/C7k1_XxHxy0?enablejsapi=1" width="460"></iframe></div>

You have to add ?enablejsapi=1 to the src url of every video you want to control this way and you have to wrap every iframe with a div id of videoID or whatever id you choose.

4) I threw this in the top of my page.tpl.php file -

<script type='text/javascript'>//<![CDATA[ 

/*
 * @author       Rob W (http://stackoverflow.com/a/7513356/938089
 * @description  Executes function on a framed YouTube video (see previous link)
 *               For a full list of possible functions, see:
 *               http://code.google.com/apis/youtube/js_api_reference.html
 * @param String frame_id The id of (the div containing) the frame
 * @param String func     Desired function to call, eg. "playVideo"
 * @param Array  args     (optional) List of arguments to pass to function func*/
function callPlayer(frame_id, func, args) {
    if (window.jQuery && frame_id instanceof jQuery) frame_id = frame_id.get(0).id;
    var iframe = document.getElementById(frame_id);
    if (iframe && iframe.tagName.toUpperCase() != 'IFRAME') {
        iframe = iframe.getElementsByTagName('iframe')[0];
    }
    if (iframe) {
        // Frame exists, 
        iframe.contentWindow.postMessage(JSON.stringify({
            "event": "command",
            "func": func,
            "args": args || [],
            "id": frame_id
        }), "*");
    }
}
//]]>  

</script>

I hope this helps.

vrMarc’s picture

I've found a problem with this. More than one DIV with the same ID is not a good idea and this will only work on the first DIV with the ID.

vrMarc’s picture

1) Ok here is what I have in page.tpl.php (this is probably not the best place for this code)

<script type='text/javascript'>//<![CDATA[ 

/*
 * @author       Rob W (http://stackoverflow.com/a/7513356/938089
 * @description  Executes function on a framed YouTube video (see previous link)
 *               For a full list of possible functions, see:
 *               http://code.google.com/apis/youtube/js_api_reference.html
 * @param String frame_id The id of (the div containing) the frame
 * @param String func     Desired function to call, eg. "playVideo"
 * @param Array  args     (optional) List of arguments to pass to function func*/
function callPlayer(frame_id, func, args) {
    if (window.jQuery && frame_id instanceof jQuery) frame_id = frame_id.get(0).id;
    var iframe = document.getElementById(frame_id);
    if (iframe && iframe.tagName.toUpperCase() != 'IFRAME') {
        iframe = iframe.getElementsByTagName('iframe')[0];
    }
    if (iframe) {
        // Frame exists, 
        iframe.contentWindow.postMessage(JSON.stringify({
            "event": "command",
            "func": func,
            "args": args || [],
            "id": frame_id
        }), "*");
    }
}
//]]>  
function stopMadden(){callPlayer("madden","stopVideo"); return false;}
function stopClassic(){callPlayer("cclassic","stopVideo"); return false;}
function stopLally(){callPlayer("lally","stopVideo"); return false;} 
function stopTest(){callPlayer("testVideo","stopVideo"); return false;} 

</script>

note: madden, cclassic, lally, and testVideo are the ID's of the Divs that wrap their respective iframe embed codes in the nodes.

2) In modules/views_slideshow/js/views_slideshow.js OR in whatever JS file is processing the previous, pause, and next links add all the stop functions from #1 into each section. Below I only list the next link section. If you're using Views Slideshow Configurable Controls then modify /modules/vscc/js/vscc.js.

    // Process next link
      $('.vscc_controls_next:not(.vscc-next-processed)', context).addClass('vscc-next-processed').each(function() {
        var uniqueID = $(this).attr('id').replace('vscc_controls_next_', '');
        $(this).click(function() {
          Drupal.viewsSlideshow.action({ "action": 'nextSlide', "slideshowID": uniqueID });
		  
		  // STOPS VIDEO WHEN THIS LINK IS CLICKED		
		 stopMadden();stopLally();stopClassic();stopTest();

          return false;

3. Here is an example of a node

<div id="madden">
	<iframe allowfullscreen="" frameborder="0" height="259" src="http://www.youtube.com/embed/C7k1_XxHxy0?enablejsapi=1" width="460"></iframe></div>

You have to add ?enablejsapi=1 to the end of the src url and the url has to be youtube.com. I tried an embed code with a url of youtube-nocookie.com and it wouldn't work until I removed -nocookie

4. Can someone help simplify this so the code in steps#1 and #2 don't have to be updated every time a video is added?

NickDickinsonWilde’s picture

Issue summary: View changes
Status: Active » Closed (outdated)

If still an issue, re-open.