6
votes

I'm trying to build a Chrome extension to show a Youtube video using Youtube's iframe API. However, the player's OnReady event never fires. From previous posts here I gather this is due to the fact that Youtube cannot access the player because it is a local instantiation.

I wonder: is there a way to make this work?


My code instantiates the player in a popup. I want to play new videos to the player by passing the video ID to the player's loadVideoById function. Here's the code of my player (in a file called 'youtube.js'):

function loadPlayer() {
var popups = chrome.extension.getViews({type: "popup"});
if (popups.length != 0) {
    var popup = popups[0];
    console.log("Popup found, starting to load the player...");
    var tag = popup.document.createElement('script');
    tag.src = "https://www.youtube.com/iframe_api";
    var firstScriptTag = popup.document.getElementsByTagName('script')[0];
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
    var done = false;
    console.log("Finished loading the player.");
    }
}

The onYouTubeIframeAPIReady function is as below:

function onYouTubeIframeAPIReady() {
    console.log("Starting to instantiate the player...");
    var popups = chrome.extension.getViews({type: "popup"});
    if (popups.length != 0) {
        var popup = popups[0];
        popup.document.ytplayer = new YT.Player('player', {
            height: '200',
            width: '300',
            videoId: 'V4n6OjoPuJc',
            playerVars: {
                origin: 'location.origin',
                showinfo: 0,
                controls: 1,
                playsinline: 1,
                autoplay: 0
            },
              events: {
                'onReady': onPlayerReady,
                'onStateChange': onPlayerStateChange
            }
        })
    };
    console.log("Player element created.");
    console.log(popup.document.ytplayer);
}    

The popup.html file has a div for the player:

<div id="player"></div>

The player should have sufficient rights. The security policy included in the manifest.json file:

"content_security_policy": "script-src 'self' https://www.youtube.com/iframe_api https://s.ytimg.com/yts/jsbin/www-widgetapi-vfldKI4RW.js https://s.ytimg.com/yts/jsbin/www-widgetapi-vflgGL-5Q.js; object-src 'self'",

The player instantiates fine, and is able to play the initial videoId that I hardcode. However, the player's OnReady event does not seem to fire. Also, the majority of the API's functionality is unusable (i.e. returns errors like "TypeError: Object # has no method 'loadVideoById'" if I try to pass new videoIds) for the player created. From previous posts I gather that these problems have one and the same origin: the inability for Youtube to communicate with my player because it has no associated domain.

Is there a way to do this? If so, what am I doing wrong? Thanks a lot beforehand!


There are several related posts available; however, these are players for web html that do have their own domain (if that is the correct way of expressing it), which is not the case for a Chrome extension. YouTube API onPlayerReady not firing Youtube Embed Iframe - Events Not Firing In Local

There is one other related post, but that does not present an issue for this specific problem. Youtube API player chrome extension

2

2 Answers

1
votes

I don't think there's a way around this right now, but I thought I'd share my solution with others. I think it's probably the most robust workaround atm:

<div id="dummyTarget"></div>
<iframe id="youtube-player" frameborder="0" allowfullscreen="1" title="YouTube player" width="640" height="360"></iframe>

//  Call this once to get the appropriate http or https. Can't do this all in one call due to a bug in YouTube's API:https://code.google.com/p/gdata-issues/issues/detail?id=5670&q=onReady&colspec=API%20ID%20Type%20Status%20Priority%20Stars%20Summary
new window.YT.Player('dummyTarget');
var isHttps = $('#dummyTarget').attr('src').indexOf('https') !== -1;
$('#dummyTarget').remove();

var url = isHttps ? 'https' : 'http';
url += '://www.youtube.com/embed/?enablejsapi=1&origin=chrome-extension:\\\\{EXTENSION-ID}';
$('#youtube-player').attr('src', url);

I prefer this implementation because it allows you to accurately determine whether to use http or https when creating your iframe. This is important because some clients might not work with only http or https and YouTube's API is able to intelligently determine that. Applying the API to a dummyTarget first allows us to leverage that intelligence.

1
votes

This seems to be due to a bug in Youtube Iframe API. The events will not fire if you set the youtube player's origin parameter like

"chrome-extension://[extension-id]"

You have to change the slashes to backslashes like below

"chrome-extension:\\[extension-id]"

I have reported this issue to google group.

https://code.google.com/p/gdata-issues/issues/detail?can=2&start=0&num=100&q=&colspec=API%20ID%20Type%20Status%20Priority%20Stars%20Summary&groupby=&sort=&id=5670