I have embarked on a project to create a Chrome extension that alters the information displayed on the thumbnails of YouTube's recommended videos. In this case, I am looking to replace the video length with the name of the channel.
Imagine you are on a YouTube video page with the video player in the center and a list of thumbnails on the right side. The following code snippet allows for this replacement:
function processNode(node: HTMLElement) {
const channelName = node
.closest('ytd-thumbnail')
?.parentElement?.querySelector('.ytd-channel-name')
?.querySelector('yt-formatted-string');
if (channelName?.textContent) node.textContent = channelName?.textContent;
}
async function replaceCurrentThumbnailTimes(): Promise<void> {
for (const node of document.querySelectorAll(
'span.ytd-thumbnail-overlay-time-status-renderer',
)) {
processNode(node as HTMLElement);
}
}
void replaceCurrentThumbnailTimes();
While this approach works initially, it fails to update the replaced values when navigating to a new page within YouTube. Despite refreshing the thumbnails, the outdated information persists.
For instance, upon opening a video by Alice where her name replaces the time on the thumbnail, clicking on another video featuring Bob does not update the previous Alice thumbnail with the latest info.
In an attempt to address this issue, I explored using the MutationObserver
API. However, my efforts proved ineffective as it only worked for newly added thumbnails, neglecting existing ones that were altered.
async function replaceFutureThumbnailTimes(): Promise<void> {
const observer = new MutationObserver((mutations) => {
// Check for video thumbnail times in each new node added
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (
node instanceof HTMLElement &&
node.classList.contains(
'ytd-thumbnail-overlay-time-status-renderer',
) &&
node.getAttribute('id') === 'text'
) {
processNode(node);
}
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
characterData: true,
attributes: true,
});
}
void replaceFutureThumbnailTimes();
This challenge may be related to shadow/shady DOM structures, posing difficulties in finding a workaround. If you wish to test the code, I have shared a pure JavaScript version on pastebin for easy replication: https://pastebin.com/NWKfzCwQ