Search code examples
javascriptgoogle-apiyoutube-apigoogle-appsyoutube-data-api

Using Google API on google sites themselves (like on youtube.com for example)


What I am trying to do? I am trying to create a small javascript snippet that would run in my browser on youtube's subscriptions page (https://www.youtube.com/feed/subscriptions) and would allow to bulk add videos I have not watched into my "Watch Later" playlist so I can binge watch them in chunks and/or on my smartTV later.

How am I trying to do it? I am trying to use Google Youtube Data API and modify "Watch Later" playlist by calling "insert" method.

What is the issue I am getting? In order to do everything from above one of the things is to load google api script onto the page. And that is where I am seeing issue. When I load that script (https://apis.google.com/js/api.js) on a separately hosted HTML page (or just in jsfiddle sandbox) everything works:

<script>
    function handleClientLoad() {
        // Load the API client and auth2 library
        gapi.load('client:auth2', initClient);
    }
    function initClient() {
        // do nothing for now
    }
</script>
<script async defer src="https://apis.google.com/js/api.js" onload="handleClientLoad()"></script>

However, when I try to do the same in my userscript using tampermonkey I am getting an error.

function loadScript(url, callback)
{
    console.log('load script: ' + url);
    // Adding the script tag to the body
    var body = document.getElementsByTagName('body')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;
    script.async = true;
    script.defer = true;

    // Then bind the event to the callback function.
    script.onreadystatechange = function() {
        console.log('in readyStateChange. readyState: ' + this.readyState);
        callback();
    };

    script.onload = function() {
        console.log('in onload');
        this.onload = function() {};
        callback();
    };

    // Fire the loading
    body.appendChild(script);
}

function initGAPI() {
    console.log('initGAPI');
    gapi.load('client:auth2', initClient);
}

function initClient() {
    // do nothing for now
}

loadScript('https://apis.google.com/js/api.js', initGAPI);

I can see that my user script is being successfully triggered when I navigate to https://www.youtube.com/feed/subscriptions, however when it comes to gapi.load() method I am getting this error:

Uncaught TypeError: gapi.loaded_0 is not a function at cb=gapi.loaded_0:1

I tried to inspect what is available on youtube's page before I load my own instance of gapi and realized there is already gapi object exists there and it has only one method: load(). When I try to call that method on that existing object (without trying to load my own instance of gapi script) it:

gapi.load('client:auth2', function() {console.log('gapi loaded');})

I get error of:

GET https://apis.google.com/_/scs/abc-static/_/js/k=gapi.gapi.en.HtLvrA_npCQ.O/m=client/exm=oauth2/rt=j/sv=1/d=1/ed=1/am=AAE/rs=AHpOoo8wHQU_A1WtgGgcOpQEfGjHuD8e-g/cb=gapi.loaded_1 net::ERR_ABORTED somewhere in desktop_polymer.js (line 2661)

I see there are different callbacks engaged (gapi.loaded_0 and gapi.loaded_0). However I can't make anything of it.

I am starting to think that I can't really use Google API while on google's own site (like youtube in my case). Is that correct assumption?

Maybe there are already existing solutions that achive my goal (bulk add non-watched videos into "Watch Later" playlist) - would appreciate any pointers :)


Solution

  • Turned out it was just my lazy eye. I missed the fact that I load https://apis.google.com/js/api.js twice. One time through @require external dependency - feature of tampermonkey script, another time - via dynamically adding that same script to the page as per instructions I started with to onboard with Google API.

    Just loading via @require doesn't really work as that doesn't trigger callback that is necessary to instantiate everything properly. So I had to remove that directive and only rely on adding script to the page dynamically. After I did that - everything started to work. So, all in all, my code I posted in question is actually valid one to use, the problem was only in how I adopted it for usage in tampermonkey userscript :)