10

I'm trying to change some behavior of the YouTube player, by changing some variables inside of the player_api script that is embedded into the html watch page of videos.

The embedded script i'm trying to modify

Problem is, whatever i try, the embedded script of the player always runs before my extension adds modifications to it. Thus keeping the behavior of the player the same.

I tried setting the run_at property in my manifest to document-start, but then the script didn't run at all.

What can i do to halt the execution of that script until i make changes to it?

PS: I tried changing the script by intercepting the html call and editing the body with Charles Proxy and the behavior of the player changed as i wanted. So it know it should work, if done at the right time.

.

manifest.json

{
    "manifest_version": 2,
    "name": "YouFit For YouTube",
    "version": "1",
    "content_scripts": [{
        "js": ["content.js"],
        "matches": ["https://*.youtube.com/watch?*",
        "https://*.youtube.com/watch?*"],
    }],
    "browser_action": {
        "default_icon": "icon.png"
    }
}

content.js

function changeBehavior() {
    var scriptElements = document.getElementsByTagName('script');
    for (var i = 14; i < scriptElements.length; i++) {
        var curScriptBody = scriptElements[i].outerHTML;
        // Find the script i'm interested in
        if (curScriptBody.indexOf("var ytplayer") != -1) {
            scriptElements[i].outerHTML = scriptElements[i].outerHTML.replace("<text>", "<replacement text>");
            alert("Replaced");
            break;
        }
    }
}
changeBehavior();
13
  • 1
    Replacing script element's html accomplishes nothing because it happens after the script was executed and there's no way to do it beforehand in Chrome. It won't work like this. You'll have to cancel the script URL before it loads, download its contents yourself, change it, insert as a new script element. There should be an example of doing that somewhere, keep looking. Commented Feb 15, 2018 at 2:19
  • The script isn't loaded from url. It's content is injected inside the script tag. Does that make a difference? Commented Feb 15, 2018 at 10:05
  • 1
    Then you'll need to overwrite the entire page: 1) window.stop() 2) fetch the original html vix XHR/fetch 3) do the text replacements 4) overwrite the page via document.write() Commented Feb 15, 2018 at 11:10
  • I spent a lot of time trying to follow your suggestion. I couldn't though, i'm still new to chrome extensions and content scripts. I will be placing a 50 - 100 point bounty in 8 hours in hopes of getting a more guiding answer. Thank you for the suggestion :) Commented Feb 16, 2018 at 11:10
  • Something like this script. Commented Feb 16, 2018 at 15:09

2 Answers 2

6

Did you try something like this?

content.js

var script = document.createElement('script');
script.textContent = "/* What you have in content.js right now */";
(document.head||document.documentElement).prepend(script);
Sign up to request clarification or add additional context in comments.

4 Comments

Running this at document_start, Seems like I don't have access to other script elements at that point just yet. Running it at document_idle doesn't do the replacement early enough.
Such an underrated answer. With "run_at":"document_start", this solution runs code in context of page right before any script execution and before any DOM element load. Exactly what i needed.
I have been searching for this all day ! Great answer thanks !
How did you replace your "/* What you have in content.js right now */" because I have a content.ts file and I am having trouble implementing this.
2

Add "run_at": "document_start" to the manifest file for the content script then modify your content script such that changeBehavior is called after the current call stack is exhausted using setTimeout(fn, 0). It will run just after the HTML document is rendered but before any embedded scripts.

This solution also avoids potential issues with running unsafe inline scripts when the content security policy is set.

Content.js
function changeBehavior() {
    ...
}

setTimeout(() => {
    changeBehavior();
}, 0);

2 Comments

Can you elaborate on the purpose of setTimeout here? I don't understand
The setTimeout( ..., 0) will ensure that the function is called after the HTML documented is rendered. Without it, it will be called before. stackoverflow.com/questions/779379/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.