Skip to content

Instantly share code, notes, and snippets.

@exo-pla-net
Created December 5, 2022 19:01
Show Gist options
  • Save exo-pla-net/3c4a5a7040c75fc481fd56675dad557c to your computer and use it in GitHub Desktop.
Save exo-pla-net/3c4a5a7040c75fc481fd56675dad557c to your computer and use it in GitHub Desktop.
Tampermonkey: Sort your YouTube channel subscriptions by fresh content (blue dot)
// This script sorts your YouTube subscriptions by whether or not they have unwatched new videos (as indicated by blue dots).
// Now you can more conveniently choose which channel with fresh content you want to watch!
// This sorting applies to the left menu list of Subscriptions on any YouTube page.
// ==UserScript==
// @name Youtube Subscription Sorter
// @namespace http://tampermonkey.net/
// @version 0.1
// @description sorts subscriptions by whether or not they have unwatched new videos
// @author exo-pla-net
// @match https://*.youtube.com/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant none
// ==/UserScript==
(function() {
function reorderSubscriptions(subscriptions){
// "Expanded" / "Show more" subscriptions live in their own wrapper.
// We want to flatten everything to the same level,
// So grab the parent of a root subscription
let subscriptionsParentNode = subscriptions[0].parentNode
subscriptions.sort(compareSubscriptionsWithNewOrLiveFirst)
// if we sequentially move all of the sorted items to the bottom,
// they'll be in the correct order
// (appending an already-existing element effectively moves it)
subscriptions.forEach(el => subscriptionsParentNode.append(el))
}
function getSubscriptions(){
console.log("Fetching subscriptions...");
// find the h3 containing "Subscriptions" to locate subscription sidebar
let h3s = document.querySelectorAll("h3");
h3s = [...h3s] // convert to array
let subscriptionsH3 = h3s.find(el => el.textContent.trim() === "Subscriptions")
// the subscriptions live in a sibling element called "#items"
if (subscriptionsH3 == null){
return [];
}
let subscriptions = subscriptionsH3.parentNode.querySelector("#items").children;
subscriptions = [...subscriptions]
// if the subscriptions have been expanded,
// the final item will have an element called "#expandable-items",
// and its children will be additional subscriptions
let finalElement = subscriptions[subscriptions.length-1]
let extraSubscriptionsWrapper = finalElement.querySelector("#expandable-items")
if(extraSubscriptionsWrapper != null){
subscriptions.push(...extraSubscriptionsWrapper.children)
}
//subscriptions.forEach(el => console.log(el.textContent.trim()))
return subscriptions
}
function hasNewVideoOrIsLive(subscriptionElement){
let dot = subscriptionElement.querySelector("#newness-dot");
let liveIcon = subscriptionElement.querySelectorAll("yt-icon")[1];
let dotIsVisible = window.getComputedStyle(dot).display != "none";
let liveIsVisible = window.getComputedStyle(liveIcon).display != "none";
return dotIsVisible || liveIsVisible ? true : false;
}
// compare(a,b)
// -1 => a before b
// 1 => a after b
// 0 keep order
function compareSubscriptionsWithNewOrLiveFirst(a,b) {
let aBeNew = hasNewVideoOrIsLive(a)
let bBeNew = hasNewVideoOrIsLive(b)
if(aBeNew && !bBeNew) return -1
if(!aBeNew && bBeNew) return 1
return 0
};
function sleepForMilliseconds(milliseconds) {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, milliseconds);
});
}
function clickShowMore(subscriptions){
let showMoreElement = subscriptions[subscriptions.length -1]
// console.log(showMoreElement.textContent.trim())
showMoreElement.querySelector("#expander-item").click()
}
async function main(){
console.log("Attempting to sort subscriptions...");
// await subscriptions to load
let subscriptions = null
while(true){
subscriptions = getSubscriptions();
if (subscriptions.length > 0) break;
console.log("Page is still loading...")
await sleepForMilliseconds(100)
}
// click "show more" to load all subscriptions
// wait for there to be more subscriptions
let startingSubscriptionCount = subscriptions.length
console.log(`Found ${startingSubscriptionCount} subscriptions before expansion...`);
clickShowMore(subscriptions)
while(true){
subscriptions = getSubscriptions()
if (subscriptions.length > startingSubscriptionCount) break;
console.log("Expanded subscriptions are still loading...")
await sleepForMilliseconds(100)
}
// we now have all subscriptions loaded and can reorder them
reorderSubscriptions(subscriptions)
console.log("Subscription reordering complete!")
}
main()
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment