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!