Reputation: 27
Basically what I want the extension to do is, when I open a youtube video, grab the name of the youtube channel and add it to the window title so that I can block youtube videos of only some channels. So if the youtube channel name was "Mark Rober" and the video title (and thus also the window title) was "Is NASA a waste of money?" I want to change the window title into something like "Is NASA a waste of money? - Mark Rober".
I tried writing a chrome extension for this but I can't figure out how to get the name of the youtube channel to put it into the window title. I tried using document.querySelector and document.getElementById and both return "null" or undefined. Probably because I don't know how to access specifically the channel name because it doesn't really have a unique ID in the HTML.
I also thought about doing this through the YouTube API but that requires an OAuth Token. And since this extension would be really helpful to use alongside many web blockers I would love to share it when its working and with a token that might be less accessible (I think).
So if anyone can help me do this I'd be really grateful :)
Upvotes: 0
Views: 780
Reputation: 23
Building off of @Endymion0000's answer, I added the actual account username (URL) to the Window title so now it outputs like this:
I Found a Giant NVIDIA PC - Bringus Studios (@BringusStudios)
manifest.json
:
{
"name": "YouTube Channel Name",
"version": "2.1",
"description": "Display YouTube Channel Name",
"manifest_version": 3,
"content_scripts": [ {
"matches": ["https://www.youtube.com/*"],
"js": ["displayChannelName.js"]
} ]
}
displayChannelName.js
:
console.log("displayChannelName started");
let currTitle = "";
window.SameCount = 0;
function updateTitle(node) {
if (window.location.href.indexOf("/watch?v=") > -1) {
if (document.title != currTitle) {
if (node == undefined) {
channelName = (function () { return; })();
node = document.getElementById("above-the-fold");
};
updateTitletimeout = setTimeout(function () { // wait a little in case title changes before the node reloads
if(node) {
channelA = node.querySelector('#channel-name #text a');
if(channelA) {
let channelName = channelA.innerHTML;
let channelUrl = channelA.href.split('/').pop();
let videoTitle = document.title;
console.log('displayChannelName - channelName = '+ channelName);
console.log('displayChannelName - channelUrl = '+ channelUrl);
if (channelName && channelUrl) {
if (videoTitle.indexOf(channelName) === -1) {
videoTitle += " - " + channelName + " (" + channelUrl + ")";
console.log("displayChannelName - updateTitle - " + document.title + " -> " + videoTitle);
window.SameCount = 0;
}
}
videoTitle = videoTitle.replace(' - YouTube','');
document.title = videoTitle;
currTitle = document.title;
}
}
currTitle = document.title;
}, 500);
} else {
window.SameCount = window.SameCount + 1;
if (window.SameCount >= 1) {
console.log("displayChannelName stopped");
clearTimeout(updateTitletimeout);
} else {
console.log("displayChannelName Title Same - " + window.SameCount);
}
}
}
};
if (window.location.href.indexOf("/watch?v=") > -1) {
let node = document.getElementById("above-the-fold");
if (node != undefined) {
updateTitle(node);
};
// listen for future changes
new MutationObserver(function (mutations) {
updateTitle(undefined);
}).observe(
document.querySelector("title"),
{ subtree: true, characterData: true, childList: true }
);
}
Upvotes: 0
Reputation: 11
(New Fixes added for a random error in the log and sometimes looping of active tabs in other hidden windows. Basically limited how many times it would try to replace the title after triggering)
I found that the code provided by Orius was no longer working, but was a huge help.
I've fixed it with an easier way of selecting the channel name along with some improvements:
• It now removes the "- YouTube" text on video pages only.
• It will check if the channel name is already in the Title and not add it again.
• Some interactions with other extensions caused it to add the channel name twice. (I have a script that removes the notification number from the titles so likely that interaction). The same feature that doesn't add it when it's already there solves this as well.
• Previously, this only worked if you opened a video in a new tab since it was limited to "/watch?v=" pages by the manifest. Loading the home page, subscriptions, etc. first would not load the extension and thus not be loaded when a video link was clicked and YouTube did it's load into page instead of normal page load thing.
It now loads on all YouTube pages and the javascript itself detects the "/watch?v=" change, so it still only changes the video page title but you now can start on any page and click around.
YouTube leaves the html for video titles on the page that normally swaps in video data when a new video is clicked, but on non video pages it's just hidden junk data and would cause the info about the previous video viewed to get added to the title. So this is why title changes are still limited to video pages.
• Also added some checks here and there to prevent console errors when it tries to get the data before it can be found on the page.
Here's version 2
manifest.json
:
{
"name": "YouTube Channel Name",
"version": "2.1",
"description": "Display YouTube Channel Name",
"manifest_version": 3,
"content_scripts": [ {
"matches": ["https://www.youtube.com/*"],
"js": ["displayChannelName.js"]
} ]
}
displayChannelName.js
:
console.log("displayChannelName started");
let currTitle = "";
window.SameCount = 0;
function updateTitle(node) {
if (window.location.href.indexOf("/watch?v=") > -1) {
if (document.title != currTitle) {
if (node == undefined) {
channelName = (function () { return; })();
node = document.getElementById("above-the-fold");
};
updateTitletimeout = setTimeout(function () { // wait a little in case title changes before the node reloads
if(node) {
channelA = node.querySelector('#channel-name #text a');
if(channelA) {
let channelName = channelA.innerHTML;
videoTitle = document.title;
console.log('displayChannelName - channelName = '+ channelName);
if(channelName) {
if (videoTitle.indexOf(channelName) === -1) {
videoTitle += " - " + channelName;
console.log("displayChannelName - updateTitle - " + document.title + " -> " + videoTitle);
window.SameCount = 0;
}
}
videoTitle = videoTitle.replace(' - YouTube','');
document.title = videoTitle;
currTitle = document.title;
}
}
currTitle = document.title;
}, 500);
} else {
window.SameCount = window.SameCount + 1;
if (window.SameCount >= 1) {
console.log("displayChannelName stopped");
clearTimeout(updateTitletimeout);
} else {
console.log("displayChannelName Title Same - " + window.SameCount);
}
}
}
};
if (window.location.href.indexOf("/watch?v=") > -1) {
let node = document.getElementById("above-the-fold");
if (node != undefined) {
updateTitle(node);
};
// listen for future changes
new MutationObserver(function (mutations) {
updateTitle(undefined);
}).observe(
document.querySelector("title"),
{ subtree: true, characterData: true, childList: true }
);
}
Upvotes: 1
Reputation: 1093
I'm not sure what's going on in their code, maybe IDs are not unique or something, but anyway, I've managed to get the channel's name using the ugliest expression:
document.getElementById("primary-inner").children[7].children[1].children[0].children[0].children[0].children[0].children[1].children[0].children[0].children[0].children[0].children[0].innerHTML
(Are you aware of the issue that it takes time for the page to load and if the script runs before the page has finished loading you might get null
? There are techniques to overcome this issue, in case it's new to you.)
Edit:
The full code of a Chrome extension that works for me:
displayChannelName.js
:
console.log("displayChannelName started.");
let nodeLoaded = setInterval(function () {
let node = document.getElementById("primary-inner");
if (node != undefined) {
let channelName = node.children[7].children[1].children[0].children[0].children[0].children[0].children[1].children[0].children[0].children[0].children[0].children[0].innerHTML;
console.log("channel name: " + channelName);
document.title = document.title + " - " + channelName;
clearInterval(nodeLoaded);
};
}, 500);
manifest.json
:
{
"name": "YouTube Channel Name",
"version": "1",
"description": "Display YouTube Channel Name",
"manifest_version": 3,
"content_scripts": [ {
"matches": ["https://www.youtube.com/watch*"],
"js": ["displayChannelName.js"]
} ]
}
Edit:
With MutationObserver:
displayChannelName.js
:
console.log("displayChannelName script started.");
let currTitle;
function updateTitle(node) {
if (document.title != currTitle) {
console.log("updateTitle function called.");
if (node == undefined) {
node = document.getElementById("primary-inner");
};
setTimeout(function () { // wait a little in case title changes before the node reloads
let channelName = node.children[7].children[1].children[0].children[0].children[0].children[0].children[1].children[0].children[0].children[0].children[0].children[0].innerHTML;
document.title += " - " + channelName;
currTitle = document.title;
}, 500);
};
};
let nodeLoaded = setInterval(function () {
// update title on page load
let node = document.getElementById("primary-inner");
if (node != undefined) {
updateTitle(node);
clearInterval(nodeLoaded);
};
}, 500);
// listen for future changes
new MutationObserver(function (mutations) {
updateTitle(undefined);
}).observe(
document.querySelector("title"),
{ subtree: true, characterData: true, childList: true }
);
Upvotes: 1