Created
December 5, 2022 19:01
-
-
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 file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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