Sorts the YouTube feed so that all scheduled streams come before archived videos.
当前为
// ==UserScript==
// @name YT Feed Sorter
// @namespace YTFeedSorter
// @version 0.5
// @description Sorts the YouTube feed so that all scheduled streams come before archived videos.
// @match *://*.youtube.com/*
// @author KFP
// ==/UserScript==
(function() {
'use strict';
let feedSorted = false;
const feedSelector = 'ytd-browse[page-subtype="subscriptions"][role="main"] #contents.ytd-section-list-renderer';
const blockSelector = '#items.ytd-grid-renderer';
const liveSelector = '#video-badges:not([hidden])';
const soonSelector = 'ytd-toggle-button-renderer';
const sortedClass = 'ytfeedsorter-sorted';
const sortBlock = block => {
const wasSorted = block.classList.contains(sortedClass);
if (!wasSorted) block.classList.add(sortedClass);
setTimeout(() => {
[...block.children].sort((a, b) => {
const ai = a.root.querySelector(liveSelector) ? 2 : a.root.querySelector(soonSelector) ? 1 : 0;
const bi = b.root.querySelector(liveSelector) ? 2 : b.root.querySelector(soonSelector) ? 1 : 0;
return (ai > bi) ? -1 : (ai < bi) ? 1 : 0;
}).forEach(item => block.appendChild(item));
}, wasSorted ? 200 : 0);
};
const observer = new MutationObserver(mutations => {
for (const mut of mutations) {
for (const added of mut.addedNodes) {
document.querySelectorAll(blockSelector).forEach(sortBlock);
}
}
});
setInterval(() => {
const feed = document.querySelector(feedSelector);
if (feed) {
if (feedSorted) return;
document.querySelectorAll(blockSelector).forEach(sortBlock);
observer.observe(feed, {childList: true});
feedSorted = true;
} else if (feedSorted) {
observer.disconnect();
feedSorted = false;
}
}, 100);
})();