0

I want to use the "YouTube iframe API" in a "content script" Google Chrome extension. How should I require the Youtube iframe API in my extension?

URL for Youtube iFrame API: https://www.youtube.com/iframe_api.

You usually include scripts in a Google Chrome extension in the manifest file, however Chrome's extension page throws an error since the URL does not end in .js.

Also, it looks like the script at this URL tries to inject <script> tags, which won't work with a content_script plugin since it doesn't have access to the page's javascript.

manifest.json

{
    ...
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": ["main.js"],
            "all_frames": true
        }
    ]
}

main.js

// Inject the script, but this won't work since content scripts can't access the page's javascript (which is where this script is injected).
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/player_api";

(document.head || document.documentElement).appendChild(tag);


// Create our own player
var player;

var videoID = 'e7Px2yJA6S4';

// When the YouTube API is loaded, it calls this function.
function onYouTubeIframeAPIReady() {
  player = new YT.Player('movie_player', {
    height: '390',
    width: '640',
    videoId: videoID,
    events: {
      'onReady': onPlayerReady,
      'onStateChange': onPlayerStateChange
    }
  });
}

What should I be doing differently? How can I correctly include this script?

Don P
  • 60,113
  • 114
  • 300
  • 432

1 Answers1

1

Rob W's answer has covered this scenario: Insert code into the page context using a content script, see Method 1 & Method2.

In general, because content scripts execute in isolated word, if you include youtube api as a <script> tag (which is in the web page world) while initializing youtube player in content scripts (which is in an isolated world), it will fail since content scripts and <script> tag can't access variables/functions defined by each other.

One workaround would be both injecting these codes through <script> tags, see following sample.

manifest.json

{
    ...
    "content_scripts": [
        {
            "matches": ["<all_urls>"],
            "js": ["inject.js"],
            "all_frames": true
        }
    ],
    "web_accessible_resources": ["https://www.youtube.com/player_api"]
}

inject.js

function insertScriptFile(callback) {
    // Inject the script
    var tag = document.createElement('script');
    tag.src = "https://www.youtube.com/player_api";
    tag.onload = function () {
        callback();
    };
   (document.head || document.documentElement).appendChild(tag);
}

function insertEmmedCode() {
    var actualCode = `// 3. This function creates an <iframe> (and YouTube player)
  //    after the API code downloads.
  var player;
  function onYouTubeIframeAPIReady() {
    player = new YT.Player('player', {
      height: '390',
      width: '640',
      videoId: 'M7lc1UVf-VE',
      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.
  var done = false;
  function onPlayerStateChange(event) {
    if (event.data == YT.PlayerState.PLAYING && !done) {
      setTimeout(stopVideo, 6000);
      done = true;
    }
  }
  function stopVideo() {
    player.stopVideo();
  }
`;

    var script = document.createElement('script');
    script.textContent = actualCode;
    (document.head || document.documentElement).appendChild(script);
}

var div = document.createElement("div");
div.id = "player";
document.body.appendChild(div);

insertScriptFile(function () {
    insertEmmedCode();
});
Community
  • 1
  • 1
Haibara Ai
  • 10,703
  • 2
  • 31
  • 47
  • The problem with this solution is main.js still doesn't have access to the API injected from inject.js. – Don P Jul 06 '16 at 09:01
  • 1
    @DonnyP, updated. Basically due to execution environment, content scripts and ` – Haibara Ai Jul 06 '16 at 10:20