How to detect page navigation on YouTube and modify its appearance seamlessly?
Solution 1:
YouTube site doesn't reload pages on navigation, it replaces the history state.
The extension's content scripts aren't reinjected when URL changes without a page being reloaded. Naturally when you reload a page manually the content script is executed.
There are several methods to detect page transitions on Youtube site:
-
using a background page script: webNavigation API, tabs API
-
using a content script:
transitionend
event for the progress meter on video pages -
using a content script and a site-specific event triggered on video navigation:
Run
getEventListeners(document)
in devtools console and inspect the output.yt-navigate-start is what we need in this case.
Notes:
- for other tasks we might want yt-navigate-finish
- the old youtube design was using
spfdone
event
manifest.json:
{
"name": "YouTube Playlist Length",
"version": "0.0.1",
"manifest_version": 2,
"description": ".............",
"content_scripts": [{
"matches": [ "*://*.youtube.com/*" ],
"js": [ "content.js" ],
"run_at": "document_start"
}]
}
Note: the matches
key encompasses the entire youtube.com domain so that the content script runs when the user first opens the home youtube page then navigates to a watch page.
content.js:
document.addEventListener('yt-navigate-start', process);
if (document.body) process();
else document.addEventListener('DOMContentLoaded', process);
The process
function will alter the page.
Note, the specified element classes and structure will change in the future.
function process() {
if (!location.pathname.startsWith('/playlist')) {
return;
}
var seconds = [].reduce.call(
document.getElementsByClassName('timestamp'),
function (sum, ts) {
var minsec = ts.textContent.split(':');
return sum + minsec[0] * 60 + minsec[1] * 1;
},
0,
);
if (!seconds) {
console.warn('Got no timestamps. Empty playlist?');
return;
}
var timeHMS = new Date(seconds * 1000).toUTCString().split(' ')[4]
.replace(/^[0:]+/, ''); // trim leading zeroes
document.querySelector('.pl-header-details')
.insertAdjacentHTML('beforeend', '<li>Length: ' + timeHMS + '</li>');
}
Solution 2:
2017 answer:
I use this for new Material Design version Youtube
body.addEventListener("yt-navigate-finish", function(event) {
// code here
});
and this for old Youtube
window.addEventListener("spfdone", function(e) {
// code here
});
code come from 2 script I wrote call
"Youtube subtitle downloader" and "Youtube auto subtitle downloader".
both of them work, I tested.
if you are interested in my script and want know more detail:
https://github.com/1c7/Youtube-Auto-Subtitle-Download