2

I want to make a small extension that injects a simple html into a YouTube page right under the video. It works fine if I simple visiting a youtube url. However if I choose a video from youtube offers then my html code is injected twice but removed. I can see that it to appear and then disappear almost immediately.

My code is:

background.js

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {

    if ( changeInfo.status == 'complete' && tab.status == 'complete' && tab.url != undefined ) {

        chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
            chrome.tabs.sendMessage(tabs[0].id, {method: "reDraw"}, function(response) {
                console.log("Injection ready!");
            });
        });

    }

});

content.js

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        if (request.method == "reDraw") {
            $.get(chrome.extension.getURL('/mytest.html'), function(data) {
                $(data).insertAfter('#placeholder-player');
            });   
        } 
    }
);  
Vmxes
  • 1,873
  • 1
  • 17
  • 27

3 Answers3

10

chrome.tabs.onUpdated will also fire for iframes, and for youtube, there are many iframes will trigger this event, besides that, youtube doesn't reload the page when you go from one video to another. For more details about youtube issue, you could take a look at these threads:

So my recommendation would be using chrome.webNavigation api, and combining webNavigation.onCompleted with webNavigation.onHistoryStateUpdated, sample code would look like the following

Considering you are detecting youtube video page, I would suggest you used chrome.webNavigation.onHistoryStateUpdated

// To handle youtube video page
chrome.webNavigation.onHistoryStateUpdated.addListener(function(details) {
    if(details.frameId === 0) {
        // Fires only when details.url === currentTab.url
        chrome.tabs.get(details.tabId, function(tab) {
            if(tab.url === details.url) {
                console.log("onHistoryStateUpdated");
            }
        });
    }
});
Community
  • 1
  • 1
Haibara Ai
  • 10,315
  • 2
  • 28
  • 47
  • This solution is working fine in most cases, but I just realized that one of a popular chrome extension prevents this event to fire and so my extension is not working. – Vmxes May 04 '16 at 08:37
  • @Vmxes, more details? – Haibara Ai May 04 '16 at 11:07
  • Your solution was working fine until I installed "Magic Actions for YouTube 6.9.0.0." If this extension is enabled then onHistoryStateUpdated event was not fired or was not access my extension listener. – Vmxes May 05 '16 at 12:47
  • can i add this to my content script or should it be on a background page? – oldboy Jul 23 '17 at 06:58
1

Here is a way to only fire one time using chrome.webNavigation.onHistoryStateUpdated

// background.js
'use strict';

console.log('QboAudit Background Script');

chrome.runtime.onInstalled.addListener(details => {
  console.log('QboAudit previousVersion', details.previousVersion);
})

chrome.webNavigation.onHistoryStateUpdated.addListener( (details) => {
  console.log('QboAudit Page uses History API and we heard a pushSate/replaceState.')
  if(typeof chrome._LAST_RUN === 'undefined' || notRunWithinTheLastSecond(details.timeStamp)){
    chrome._LAST_RUN = details.timeStamp
    chrome.tabs.getSelected(null, function (tab) { 
      if(tab.url.match(/.*\/app\/auditlog$/)){
        chrome.tabs.sendRequest(tab.id, 'runQboAuditLog')
      }
    })
  }
})

const notRunWithinTheLastSecond = (dt) => {
  const diff = dt - chrome._LAST_RUN
  if (diff < 1000){
    return false
  } else {
    return true
  }
}

In short you make a global var chrome._LAST_RUN to track if this event has already fired less than a second ago.

// contentscript.js
chrome.extension.onRequest.addListener((request, sender, sendResponse) => {
  //console.log('request', request)
  if (request == 'runQboAuditLog')
    new QboAuditLog()
});
Minimul
  • 3,872
  • 2
  • 19
  • 17
0

I guess youTube is using Ajax calls on some pages to load things, so your code is being replaced with the Ajax response.

Use a setTimeout() function to check after a few seconds if your code is on the page, if it's not, add it again.

andreini
  • 166
  • 1
  • 3
  • 16