15

This piece of code works great in DESKTOP browsers (code courtesy of @Rob-W), click the thumbnail and the adjacent video will start playing, using YouTube's API.

HTML

<div id="tabs2">
    <div>
    <img class='thumb' src='http://i2.cdnds.net/11/34/odd_alan_partridge_bio_cover.jpg'>
    <iframe id="frame1" width="640" height="390" frameborder="0" title="YouTube video player"type="text/html"src="http://www.youtube.com/embed/u1zgFlCw8Aw?enablejsapi=1"></iframe>
    </div>

    <div>
        <img class='thumb' src='http://i2.cdnds.net/11/34/odd_alan_partridge_bio_cover.jpg'>
   <iframe id="frame2" width="640" height="390" frameborder="0" title="YouTube video player"type="text/html"src="http://www.youtube.com/embed/u1zgFlCw8Aw?enablejsapi=1"></iframe>
    </div>
</div>

CSS

#tabs2 div {
    position: relative;
}
/* For security reasons, an element cannor be placed over a frame */
/*.thumb {
    position: absolute;
}*/    
.play {
    border: 3px solid red;
}

JS

function getFrameID(id) {
    var elem = document.getElementById(id);
    if (elem) {
        if (/^iframe$/i.test(elem.tagName)) return id; //Frame, OK
        // else: Look for frame
        var elems = elem.getElementsByTagName("iframe");
        if (!elems.length) return null; //No iframe found, FAILURE
        for (var i = 0; i < elems.length; i++) {
            if (/^https?:\/\/(?:www\.)?youtube(?:-nocookie)?\.com(\/|$)/i.test(elems[i].src)) break;
        }
        elem = elems[i]; //The only, or the best iFrame
        if (elem.id) return elem.id; //Existing ID, return it
        // else: Create a new ID
        do { //Keep postfixing `-frame` until the ID is unique
            id += "-frame";
        } while (document.getElementById(id));
        elem.id = id;
        return id;
    }
    // If no element, return null.
    return null;
}

// Define YT_ready function.
var YT_ready = (function() {
    var onReady_funcs = [],
        api_isReady = false;
/* @param func function     Function to execute on ready
         * @param func Boolean      If true, all qeued functions are executed
         * @param b_before Boolean  If true, the func will added to the first
                                     position in the queue*/
    return function(func, b_before) {
        if (func === true) {
            api_isReady = true;
            for (var i = 0; i < onReady_funcs.length; i++) {
                // Removes the first func from the array, and execute func
                onReady_funcs.shift()();
            }
        }
        else if (typeof func == "function") {
            if (api_isReady) func();
            else onReady_funcs[b_before ? "unshift" : "push"](func);
        }
    }
})();
// This function will be called when the API is fully loaded

function onYouTubePlayerAPIReady() {
    YT_ready(true)
}

var players = {};
//Define a player storage object, to enable later function calls,
//  without having to create a new class instance again.
YT_ready(function() {
    $(".thumb + iframe[id]").each(function() {
        var identifier = this.id;
        var frameID = getFrameID(identifier);
        if (frameID) { //If the frame exists
            players[frameID] = new YT.Player(frameID, {
                events: {
                    "onReady": createYTEvent(frameID, identifier)
                }
            });
        }
    });
});

// Returns a function to enable multiple events
function createYTEvent(frameID, identifier) {
    return function (event) {
        var player = players[frameID]; // player object
        var the_div = $('#'+identifier).parent();
        the_div.children('.thumb').click(function() {
            var $this = $(this);
            $this.fadeOut().next().addClass('play');
            if ($this.next().hasClass('play')) {
                player.playVideo();
            }
        });
    }
}
// Load YouTube Frame API
(function(){ //Closure, to not leak to the scope
  var s = document.createElement("script");
  s.src = "http://www.youtube.com/player_api"; /* Load Player API*/
  var before = document.getElementsByTagName("script")[0];
  before.parentNode.insertBefore(s, before);
})();

JSFiddle

The problem is that it fails to play on iOS devices (because of the lack of Flash player, I think, it just hangs).

I can force it to play by tapping the video once more, which prompts it to play using QuickTime.

But how do I get it to play with QuickTime automatically?

brasofilo
  • 23,940
  • 15
  • 86
  • 168
SparrwHawk
  • 11,653
  • 21
  • 57
  • 89
  • Note: stopPlayer() does seem to work - however I can't restart playback after I've stopped it!!! it plays for 1/2 second and stops of its own accord – Simon_Weaver Mar 21 '13 at 22:05

3 Answers3

27

I'm sorry to say this is not possible in iOS. According to Apple's documentation,

"...embedded media cannot be played automatically in Safari on iOS - the user always initiates playback."

The restriction is consistent regardless of network connection as it is both a bandwidth decision as well as a user experience decision.

Update, October, 2016: It's worth noting, now that iOS 10 is out and gaining significant market share, that people can leverage changes in the way video playback works on iOS 10 to get autoplay behavior. If the video has no audio tracks or the tag is muted, autoplay can be possible. More information is available in this webkit blog. The YouTube API may handle this nicely soon.

Aaron
  • 4,624
  • 1
  • 24
  • 43
  • Thanks Tegeril, I suspect you're right. I'll award you the bounty if no one else answers in a few days. I have another question similar to this, do you think you can answer that too? Many thanks http://stackoverflow.com/questions/9033080/youtube-wmode-opaque-not-working-in-ie9-or-any-other-ie – SparrwHawk Jan 27 '12 at 14:05
  • I found another reference a few minutes ago but then proceeded to crash my browser. There is a YouTube discussion out there somewhere ultimately confirming this to be the case :( – Aaron Jan 27 '12 at 16:26
  • any html5 video api will only work upon user-initialization. this is how things are for now. – amit Jan 31 '12 at 11:41
  • This is outdated information, you can either roll your own solution or use the official framework: https://github.com/youtube/youtube-ios-player-helper – ABeanSits Aug 17 '16 at 18:08
  • @ABeanSits - this entire post is about autoplaying video in a web browser, not with the native SDK. – Aaron Aug 23 '16 at 07:10
  • @Tegeril sure but even the official solution use a web view with an iFrame to play the videos. That is why the same rules apply to both. – ABeanSits Sep 08 '16 at 01:58
  • @ABeanSits the same API does but parts of it does not work in iOS. Autoplay is one of those parts. To be clear. The native sdk can autoplay because it controls its own webview. The question above is about just loading any random webpage into mobile safari and expecting autoplay, which does not work. – Aaron Sep 08 '16 at 04:45
3

Beginning in iOS 4, UIWebView has the mediaPlaybackRequiresUserAction property. I can’t tell if you’re implementing this on the Web or in a native app, but setting that to NO in a native app should allow auto play to work.

Jeff Kelley
  • 18,594
  • 5
  • 67
  • 80
  • 1
    Hi Jeff, it's purely on the web, as shown on the JSFiddle I posted. Could you show me how I would implement this using the fiddle? Thanks – SparrwHawk Jan 29 '12 at 10:46
  • 1
    You can’t if it’s on the web; this only applies to native apps. – Jeff Kelley Jan 29 '12 at 15:31
  • so this basically says if you were embedding safari into your own app you could have media auto-play. so Chrome for iPad could set this to false if they'd wanted to - but it looks like they didnt – Simon_Weaver Mar 21 '13 at 01:10
-4

You can use the YouTube iFrame API on iOS.

Jeff Kelley
  • 18,594
  • 5
  • 67
  • 80
  • He is using the YouTube iFrame API. It successfully transitions from the YouTube chrome to the native iOS play icon, but that API does not actually start playback. – Aaron Jan 28 '12 at 22:08