2

This is my first time creating a Google Chrome Extension, and i can't find a way to reliably get the content script to run once when clicking a suggested video, or any video for that matter, on YouTube. I've tried setting "all_frames" to true, but that calls the script to many times. Is there a simple way to run a content script only once per video when browsing YouTube videos?

PS: I'm using YouTube as my main example but this issue exists on other websites. what causes it and how can I fix it?

{//manifest.json
  "name": "Test",
  "version": "0.0.1",
  "content_scripts": [{
      "matches": ["<all_urls>"],
      "js": ["run.js"],
    }],
  "permissions": ["activeTab"],
  "manifest_version": 3
}

-

//run.js
console.log('running');
1

1 Answer 1

8

The problem is that Youtube updates the page dynamically, so the content script wasn't always being run after page content is changed. You need to detect if page url has been changed.

There is two ways for detect content changing.

Solution

  1. Use chrome.webNavigation.onHistoryStateUpdated event to detect that the content is changed.

You need to set permissions for webNavigation in manifest.json:

"permissions": [
    *"tabs", "webNavigation"*
  ]

background.js

    chrome.webNavigation.onHistoryStateUpdated.addListener(function(details) {
//Send message to content Script -> Page was changed
//or execute parser from here 
// chrome.tabs.executeScript
});

content.js // do pars your content

  1. Use Mutation Observers: at your content script.

The MutationObserver interface provides the ability to watch for changes being made to the DOM tree.

// Select the node that will be observed for mutations
var targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true, subtree: true };

// Callback function to execute when mutations are observed
var callback = function(mutationsList) {
    for(var mutation of mutationsList) {
        if (mutation.type == 'childList') {
            // do something with content 
        }
        else if (mutation.type == 'subtree') {
           // do something with content 
        }
    }
};

// Create an observer instance linked to the callback function
var observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Later, you can stop observing
observer.disconnect();
Sign up to request clarification or add additional context in comments.

2 Comments

If the content script is not running, how can any of this help?
@AlwaysLearning my understanding is that the content script did run on the first injection, but later could not adapt to changes in the interface. hence, a mutation observer would watch for changes and trigger any relevant function.

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.