0

I'm working on a TamperMonkey script that makes use of the YouTube API for Embedded Videos. I have a basic test file that I run locally that looks like this:

<html>
<head>
<script>

let tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
tag.id = "iframe_api";
let firstScriptTag = document.getElementsByTagName('head')[0];
firstScriptTag.insertBefore(tag, firstScriptTag.firstChild);

function onYouTubeIframeAPIReady() {
    console.log("onYouTubeIframeAPIReady");
}

</script>

</head>
<body>
<iframe title="Who Framed Roger Rabbit - Nostalgia Critic" src="https://www.youtube.com/embed/JGFYaMlD67A?feature=oembed&enablejsapi=1" allow="accelerometer; autoplay; picture-in-picture" allowfullscreen="" width="620" height="349" frameborder="0" ></iframe>
</body>
</html>

This works perfectly fine, i.e. onYouTubeIframeAPIReady is called once the API is loaded and prints the "onYouTubeIframeAPIReady" message to the console.

However, I then take that code and move it into a TamperMonkey script, and then I run my test file again:

// ==UserScript==
// @name         Test Script
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        file:///*
// ==/UserScript==

let tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
tag.id = "iframe_api";
let firstScriptTag = document.getElementsByTagName('head')[0];
firstScriptTag.insertBefore(tag, firstScriptTag.firstChild);

function onYouTubeIframeAPIReady() {
    console.log("onYouTubeIframeAPIReady");
}

The <script> tag with the API is properly injected, but the console message never appears. As best I can tell, onYouTubeIframeAPIReady() is never called.

A lot of searching suggests that onYouTubeIframeAPIReady() needs to be global, so I make the following change to my script:

// ==UserScript==
// @name         Test Script
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        file:///*
// ==/UserScript==

let tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
tag.id = "iframe_api";
let firstScriptTag = document.getElementsByTagName('head')[0];
firstScriptTag.insertBefore(tag, firstScriptTag.firstChild);

window.onYouTubeIframeAPIReady = function() {
    console.log("onYouTubeIframeAPIReady");
}

However, the problem persists. The only solution I've found so far is to turn the onYouTubeIframeAPIReady() into a string and inject it directly into the page:

// ==UserScript==
// @name         Test Script
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        file:///*
// ==/UserScript==

let code = "function onYouTubeIframeAPIReady() {" +
"    console.log(\"onYouTubeIframeAPIReady222\");" +
"}";

let newHTML = document.createElement ('script');
newHTML.innerHTML = code;
let firstScriptTag = document.getElementsByTagName('head')[0];
firstScriptTag.insertBefore(newHTML, firstScriptTag.firstChild);

let tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
tag.id = "iframe_api";
let firstScriptTagh = document.getElementsByTagName('head')[0];
firstScriptTagh.insertBefore(tag, firstScriptTagh.firstChild);

I would rather not have to turn my function into a string and do a straight injection, however. I don't understand why the script I write directly in my test file does not work when I transfer it into my TamperMonkey script, and I'd like to find a better solution than the one above. I would appreciate any insight anybody could provide.

Thanks!

123MilitaryNerd
  • 103
  • 2
  • 7

0 Answers0