// ==UserScript==
// @name YouTube All Videos Playlists (YAVP)
// @namespace c0d3r
// @license MIT
// @version 0.1
// @description Adds buttons for various channel playlists: All Videos, Shorts, Streams, Members-Only
// @author c0d3r
// @match https://www.youtube.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @run-at document-idle
// @grant none
// @downloadURL none
// ==/UserScript==
// custom buttons use native classes and tags so both Light and Dark theme is supported
function btnHtml(text, title, href) {
return `
`;
}
function btnBlock(data, chanId) {
const root = 'https://www.youtube.com/playlist?list=';
let html = '';
// only add relevant buttons based on available channel tabs
// for IDs see https://github.com/RobertWesner/YouTube-Play-All/blob/main/documentation/available-lists.md
data.response.contents.twoColumnBrowseResultsRenderer.tabs.forEach(function (tab) {
if (tab.hasOwnProperty('tabRenderer')) {
// check for URLs instead of tab titles because languages might be different
const url = tab.tabRenderer.endpoint.commandMetadata.webCommandMetadata.url;
if (url.endsWith('/videos')) {
html += btnHtml('VAll', 'All Videos', root + 'UULF' + chanId);
html += btnHtml('VPop', 'Popular Videos', root + 'UULP' + chanId);
} else if (url.endsWith('/shorts')) {
html += btnHtml('SAll', 'All Shorts', root + 'UUSH' + chanId);
html += btnHtml('SPop', 'Popular Shorts', root + 'UUPS' + chanId);
} else if (url.endsWith('/streams')) {
html += btnHtml('LAll', 'All Streams', root + 'UULV' + chanId);
html += btnHtml('LPop', 'Popular Streams', root + 'UUPV' + chanId);
}
}
});
// add Members-Only button only if Join button exists
let addMemberBtn = false;
const head = data.response.header;
// when not logged in
if (head.hasOwnProperty('c4TabbedHeaderRenderer') &&
head.c4TabbedHeaderRenderer.hasOwnProperty('sponsorButton')) {
addMemberBtn = true;
}
// when logged in
if (head.hasOwnProperty('pageHeaderRenderer')) {
const actionRows = head.pageHeaderRenderer.content.pageHeaderViewModel.actions.flexibleActionsViewModel.actionsRows;
actionRows.forEach(function (row) {
row.actions.forEach(function (action) {
if (action.hasOwnProperty('buttonViewModel') && action.buttonViewModel.targetId === 'sponsorships-button') {
addMemberBtn = true;
}
});
});
}
if (addMemberBtn) {
html += btnHtml('Mem', 'Members-Only Videos', root + 'UUMO' + chanId);
}
html += '
';
return html;
}
(function () {
'use strict';
let oldChanId;
// native event that fires on each page or tab change
window.addEventListener('yt-navigate-finish', function () {
const path = window.location.pathname;
// run only on channel pages, see https://support.google.com/youtube/answer/6180214
if (path.startsWith('/channel/') || path.startsWith('/@') ||
path.startsWith('/c/') || path.startsWith('/user/')) {
const pageMan = document.querySelector('#page-manager');
// native function that returns useful data
const pageData = pageMan.getCurrentData();
// get channel ID, but remove UC from the start
const chanId = pageData.response.metadata.channelMetadataRenderer.externalId.substring(2);
// proceed only if a new channel is opened, don't react to tab changes
if (oldChanId !== chanId) {
// remove the wrapper if it exists
const wrapper = document.querySelector('#yavp-wrap');
if (wrapper) {
wrapper.remove();
}
const tabBlock = document.querySelector('#tabsContainer');
if (tabBlock) {
// tabs container might already exist in DOM
tabBlock.insertAdjacentHTML('afterEnd', btnBlock(pageData, chanId));
} else {
// Chrome needs to wait for this block to be added at first
let stopObserve = false;
const observer = new MutationObserver(function (mutList) {
for (let i = 0; i < mutList.length; i++) {
for (let j = 0; j < mutList[i].addedNodes.length; j++) {
if (mutList[i].addedNodes[j].tagName === 'TP-YT-APP-HEADER-LAYOUT') {
const tabs = mutList[i].addedNodes[j].querySelector('#tabsContainer');
tabs.insertAdjacentHTML('afterEnd', btnBlock(pageData, chanId));
observer.disconnect();
stopObserve = true;
break;
}
}
if (stopObserve) {
break;
}
}
});
observer.observe(pageMan, {
subtree: true, childList: true
});
}
// save channel ID for future checks
oldChanId = chanId;
}
}
});
})();