Embedded YouTube videos won't replay

2019-02-20 04:33发布

问题:

Strange one: embedded YouTube videos, once played (either by clicking 'play' or autoplaying on page load) will not play again.

I'm using the standard iFrame embed copied straight from YouTube. This happens with several different short videos and across all browser/OS combinations I've tested (Chrome/Safari/Firefox/IE on Windows/Mac).

Here's the code:

<iframe width="420" height="315" src="//www.youtube.com/embed/OuSdU8tbcHY" frameborder="0" allowfullscreen></iframe>

and you can see it in action at this fiddle.

回答1:

So it appears that the issue is NOT related to video length; it's a problem with the flash player. If the flash player is loaded, and there is no user interaction with the controls at all, then when the player finishes it will not reload the iframe (despite the fact that it raises the 'video ended' event ... when you try to reload it won't issue the right call to reload the video and hence can never restart playback). You can test longer videos as well; if you start watching them and don't use the scrub bar, they'll exhibit the same behavior. Likewise, on your very short video, if you start playback and then scrub a bit (even backwards in time), that will trigger an iframe reload (akin to what @SuperMan noted), and so when the video finishes, then the reload will work just fine.

This is most likely a recently introduced bug in the Flash player, and it is not present in the HTML5 player; so if your use case allows it, the simplest solution would be to force the HTML5 player by appending ?html5=1 to the source of your iframe.

However, if having the flash player as a possibility is an iron clad requirement, then you can hack your code to force it to reload itself when finished (rather than waiting for a user to hit the reload or replay button).

<html>
<body>
<script>
      var tag = document.createElement('script');
      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          events: {
                onStateChange: 'onPlayerStateChange'
          }
        });
      }

      function onPlayerStateChange(event) {
        if (event.data===YT.PlayerState.ENDED) {
                event.target.cueVideoById(event.target.getVideoData().video_id);
        }
      }

</script>
<iframe width="420" height="315" src="//www.youtube.com/embed/OuSdU8tbcHY" frameborder="0" allowfullscreen id="player"></iframe>
</body>
</html>

Note that this requires giving your iframe an id attribute, so that you can bind to it with the iframe API.

This also avoids having to overlay any DOM elements over the video (which is not in any way a bad solution as long as you don't have any odd wmode requirements; a very strict reading of the YouTube TOS might also lead to the conclusion that you can't overlay anything over any portion of the player even if it's transparent...).

One drawback of my solution is that it won't display the 'related videos' at the end of the video, so if that's a deal breaker then this is a no-go (in other words, my solution is more akin to adding the rel=0 attribute to your iframe source).



回答2:

Okay, I don't know how to fix the problem but here's a work around. The general idea is to place a div over the reload button when the video finishes, and when the div is clicked the video reloads, since the normal method doesn't work.

Here's the code I used, in the code the div is blue for visualization purposes

<!DOCTYPE html>
<html>
    <body>
        <div id="player_prop" style="position:relative;"><iframe id="player" type="text/html" width="640" height="390"
            src="http://www.youtube.com/embed/OuSdU8tbcHY?enablejsapi=1"
            frameborder="0"></iframe></div>
        <script>
            // 2. This code loads the IFrame Player API code asynchronously.
            var tag = document.createElement('script');

            tag.src = "https://www.youtube.com/iframe_api";
            var firstScriptTag = document.getElementsByTagName('script')[0];
            firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

            // 3. This function creates an <iframe> (and YouTube player)
            //    after the API code downloads.
            var player;
            function onYouTubeIframeAPIReady() {
              player = new YT.Player('player', {
                events: {
                  'onReady': onPlayerReady,
                  'onStateChange': onPlayerStateChange
                }
              });
            }

            // 4. The API will call this function when the video player is ready.
            function onPlayerReady(event) {
              event.target.playVideo();
            }

            // 5. The API calls this function when the player's state changes.
            //    The function indicates that when playing a video (state=1),
            //    the player should play for six seconds and then stop.



            //from mantish http://stackoverflow.com/questions/3452546/javascript-regex-how-to-get-youtube-video-id-from-url
            function youtube_parser(url){
                var regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
                var match = url.match(regExp);
                if (match&&match[2].length==11){
                    return match[2];
                }else{
                    //error
                }
            }
            //end of Lasnvs code

            function restart_vid()
            {
                el = document.getElementById("fake_replay_button");
                vid_id = youtube_parser(document.getElementById('player').src);
                player.loadVideoById(vid_id);
                el.parentNode.removeChild(el);
            }

            function fakeplay()
            {
                el = document.getElementById("player_prop");
                var xPos = el.offsetLeft
                var yPos = el.offsetHeight - 30;
                var pseudoPlay = document.createElement('div');
                pseudoPlay.setAttribute('style', 'background-color:blue; cursor:pointer; display:block; width:55px; height:25px; position:absolute; top:'+yPos+'px;');
                pseudoPlay.setAttribute('onclick','restart_vid()');
                pseudoPlay.setAttribute('id','fake_replay_button');
                el.appendChild(pseudoPlay);
            }
            function onPlayerStateChange(event) 
            {
                if(event.data==YT.PlayerState.ENDED)
                {
                    fakeplay();    
                }
            }

        </script>
    </body>
</html>

To use this code all you have to do is copy and paste the script portion, and instead of only using this

<iframe width="420" height="315" src="//www.youtube.com/embed/OuSdU8tbcHY" frameborder="0" allowfullscreen></iframe>

give it an id=player, enable jsapi by adding ?enablejsapi=1 at the end of the src and enclose the iframe in a div with id = player_prop, make sure the div has property position:relative, or else the alignment of the button would be off, it should look like this

<div id="player_prop" style="position:relative;">
<iframe id="player" type="text/html" width="640" height="390" src="http://www.youtube.com/embed/OuSdU8tbcHY?enablejsapi=1" frameborder="0"></iframe>
</div>

And of course here's a link to the Fiddle



回答3:

Maybe something like this:

JsFiddle

It's not a perfect solution, cause you interect with video outside of iframe, but maybe it will get you going(changing src will always reload the video).

$('iframe').attr("src", "//www.youtube.com/embed/OuSdU8tbcHY?autoplay=1"); //  restarts the video