0

So, I've been in a dilemma and can't quite figure out how to properly inject a JavaScript file into YouTube with my Chrome Extension.

Now I've tried these things:

  1. Content Scripts with matches:
   // manifest.json

   "permissions": [
       "scripting",
       "activeTab",
       "tabs",
       "storage",
       "notifications"
   ],
   ...
   "content_scripts": [
       {
         "matches": ["https://www.youtube.com/*"],
         "js": ["video.js"],
         "run_at": "document_idle"
       }
   ]

Doesn't always trigger, epically when using 'Back' and 'Forward' buttons

  1. Programmatically injecting using chrome.tabs.onUpdated.addListener:
// background.js

let tabURL

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (!changeInfo.status && tab.url != tabURL){
        let url = new URL(tabURL)

        if (url.hostname == 'www.youtube.com') {
            if (url.pathname == '/watch') {
                console.log('UPDATED');
                chrome.scripting.executeScript({
                    target: {tabId: tabId},
                    files: ['video.js'] 
                })
            }
        }
    }
})

Works sometimes, but things like reloads don't work.

  1. Using a window.addEventListener('pageshow', startup); in video.js (content_script)

Never worked

The closest I gotten is this code:

//background.js

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if(!changeInfo.status){
        let url = new URL(tab.url)
        console.log(url);

        if (url.hostname == 'www.youtube.com') {
            if (url.pathname == '/watch') {
                console.log('UPDATED');
                chrome.scripting.executeScript({
                    target: {tabId: tabId},
                    files: ['video.js'] 
                })
            }
        }
    }
})

With a setTimeout in the content_script:

// video.js (content_script)

setInterval(startup(), 1000)

Almost works in all scenarios, but causes the script to fire more than once, leading to errors in console like:

Element hasn't loaded yet

Also doesn't account for other people's loading times.

The needed outcomes:

  • Inject JS when content is available on YouTube (For instance: like button) also accounting for different internet speeds.
  • Inject only at: https://www.youtube.com/watch
  • When I click the back/forward buttons to go to other /watch pathnames to also inject JS.
  • When tab is reloaded.

What is the best way to achieve these goals? Is there any documentation that I've missed?

KingPr0o7
  • 7
  • 2
  • Use [navigation.onnavigate](https://developer.mozilla.org/en-US/docs/Web/API/Navigation/navigate_event) event in the content script. See also [How to detect page navigation on YouTube and modify its appearance seamlessly?](https://stackoverflow.com/a/34100952) – wOxxOm Jul 19 '23 at 04:17
  • @wOxxOm, thank you for replying! I've looked into the documentation and link you've sent me. I actually ended up using the `yt-navigate-finish` event listener, which seems to work as far as my testing: `reloading` & `bfcaches`. Now, would the **navigation.onnavigate** be a future proof way to inject the JS for sites like YouTube using pushStates to alter content? – KingPr0o7 Jul 19 '23 at 05:47
  • Yes, but for a universal solution you may need to use MutationObserver after the URL change to wait for the DOM to change as well. – wOxxOm Jul 19 '23 at 05:50
  • RE the MutationObserver, here is [an answer](https://stackoverflow.com/questions/8882502/how-to-track-dom-change-in-chrome-extension/61891029#61891029) that might help you dig into that. – Miguel Rivera Rios Jul 19 '23 at 14:25
  • Oh and if you were able to solve your own question, feel free to post an answer so others can find it if they stumble onto the same issue. – Miguel Rivera Rios Jul 19 '23 at 15:02
  • Thank you, @wOxxOM & @MiguelRiveraRios! I ended having to rewrite most of my code because it was too slow. But I did up using the event listener `yt-navigate-finish`. Posting an answer now! – KingPr0o7 Jul 19 '23 at 21:21

0 Answers0