Skip to content

Instantly share code, notes, and snippets.

@KohGeek
Forked from sunnywiz/sortWL.js
Last active Oct 27, 2021
Embed
What would you like to do?
SortYoutubeWatchLaterList
// Last tested - 7/9/2021 on Chrome, but it should work on other browsers.
// This will probably not work on mobile.
// You put this in Chrome's Snippets (copy/paste) and then run it from there when you are at the watch later list
// (https://www.youtube.com/playlist?list=WL)
// It will move one video per invocation. I tried to make it do all of them but $$ disappeared.
// Heavily borrowed from many places
// function for triggering mouse events
var fireMouseEvent = function (type, elem, centerX, centerY) {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(type, true, true, window, 1, 1, 1, centerX, centerY, false, false, false, false, 0, elem);
elem.dispatchEvent(evt);
};
function simulateDrag(elemDrag, elemDrop) {
// https://ghostinspector.com/blog/simulate-drag-and-drop-javascript-casperjs/
// calculate positions
var pos = elemDrag.getBoundingClientRect();
var center1X = Math.floor((pos.left + pos.right) / 2);
var center1Y = Math.floor((pos.top + pos.bottom) / 2);
pos = elemDrop.getBoundingClientRect();
var center2X = Math.floor((pos.left + pos.right) / 2);
var center2Y = Math.floor((pos.top + pos.bottom) / 2);
// mouse over dragged element and mousedown
fireMouseEvent("mousemove", elemDrag, center1X, center1Y);
fireMouseEvent("mouseenter", elemDrag, center1X, center1Y);
fireMouseEvent("mouseover", elemDrag, center1X, center1Y);
fireMouseEvent("mousedown", elemDrag, center1X, center1Y);
// start dragging process over to drop target
fireMouseEvent("dragstart", elemDrag, center1X, center1Y);
fireMouseEvent("drag", elemDrag, center1X, center1Y);
fireMouseEvent("mousemove", elemDrag, center1X, center1Y);
fireMouseEvent("drag", elemDrag, center2X, center2Y);
fireMouseEvent("mousemove", elemDrop, center2X, center2Y);
// trigger dragging process on top of drop target
fireMouseEvent("mouseenter", elemDrop, center2X, center2Y);
fireMouseEvent("dragenter", elemDrop, center2X, center2Y);
fireMouseEvent("mouseover", elemDrop, center2X, center2Y);
fireMouseEvent("dragover", elemDrop, center2X, center2Y);
// release dragged element on top of drop target
fireMouseEvent("drop", elemDrop, center2X, center2Y);
fireMouseEvent("dragend", elemDrag, center2X, center2Y);
fireMouseEvent("mouseup", elemDrag, center2X, center2Y);
}
// To explain what broke in the original code, here is a comment
// The original code targeted the thumbnail for dragging when that is no longer viable
// Additionally, the timestamp is now two elements instead of one, so I fixed that
function sortVideosByLength(allAnchors, allDragPoints) {
let videos = [];
for (let j = 0; j < allAnchors.length; j++) {
let thumb = allAnchors[j];
let drag = allDragPoints[j];
let href = thumb.href;
if (href && href.includes("&list=WL&")) {
let timeSpan = thumb.querySelector("#text");
let timeDigits = timeSpan.innerText.trim().split(":").reverse();
var time = parseInt(timeDigits[0]);
if (timeDigits[1]) time += parseInt(timeDigits[1]) * 60;
if (timeDigits[2]) time += parseInt(timeDigits[2]) * 3600;
videos.push({ anchor: drag, time: time, originalIndex: j });
}
}
if (videos.length > 1) {
for (let j = 0; j < videos.length - 1; j++) {
var smallestLength = 86400;
var smallestIndex = -1;
for (var k = j + 1; k < videos.length; k++) {
if (
videos[k].time < videos[j].time &&
videos[k].time < smallestLength
) {
smallestLength = videos[k].time;
smallestIndex = k;
}
}
if (smallestIndex > -1) {
console.log("drag " + smallestIndex + " to " + j);
var elemDrag = videos[smallestIndex].anchor;
var elemDrop = videos[j].anchor;
simulateDrag(elemDrag, elemDrop);
return j;
}
}
return videos.length;
}
return 0;
}
// There is an inherent limit in how fast you can sort the videos, due to Youtube refreshing
// This limit also applies if you do it manually
// It is also much worse if you have a lot of videos, for every 100 videos, it's about an extra 2-4 seconds, maybe longer
async function zeLoop() {
let count = document.querySelectorAll("ytd-playlist-video-renderer").length;
let quantaToWait = Math.max(0, Math.ceil((count - 100)/100)); // about 2600 ms of load per 100 videos
let currentMinimum = 0;
while (true) {
let allAnchors = document.querySelectorAll("div#content a#thumbnail.inline-block.ytd-thumbnail");
let allDragPoints = document.querySelectorAll("yt-icon#reorder");
try {
currentMinimum = sortVideosByLength(allAnchors, allDragPoints);
} catch (e) {
if (e instanceof TypeError) {
console.log("Problem with loading, waiting a bit more.")
await new Promise((r) => setTimeout(r, quantaToWait * 1000));
currentMinimum = sortVideosByLength(allAnchors, allDragPoints); // If it somehow still dies, waits another full cycle
}
}
if (currentMinimum === count) { // If your document is already partially sorted, this will break the code early
console.log("Sort complete, or you didn't load all the videos. Video sorted: " + currentMinimum);
break;
}
await new Promise((r) => setTimeout(r, quantaToWait * 2500)); //Please set this time as needed, youtube refreshes everytime the WL gets changed
}
}
// If the loading time is for some reason hugely inconsistent, you can use this instead to do it one by one
function zeWithoutLoop() {
let allAnchors = document.querySelectorAll("div#content a#thumbnail.inline-block.ytd-thumbnail");
let allDragPoints = document.querySelectorAll("yt-icon#reorder");
sortVideosByLength(allAnchors, allDragPoints);
}
// Uncomment the variant that you want below.
//zeWithoutLoop();
//zeLoop();
@ashtanr
Copy link

ashtanr commented Sep 23, 2021

it's not working on any kind of video length not even 27 videos in watch later it can sort I don't know what is wrong it runs start calculating playlist but then nothing happens. if possible you can do one short youtube video to show how to execute it properly as per ur command it's not working at all.

Loading

@KohGeek
Copy link
Author

KohGeek commented Sep 23, 2021

@ashtanr Have you checked that you've uncommented either the zeWithoutLoop(); or zeLoop(); at the bottom of the code? I left the choice to the user, but if needed I'll just pick a default

Loading

@ashtanr
Copy link

ashtanr commented Sep 24, 2021

buddy i don't know i just copy the script in snippet and then run then nothing happen at the time of clicking on playlist showing playlist then nothing happens and another error comes glead error block by owner. i don't know even if im excecuting this command nicely or not, if u can guide me step by how to use that would be helpful.
thanks

Loading

@KohGeek
Copy link
Author

KohGeek commented Sep 24, 2021

Okay, before you run the code next time, line 132 or 133 (either one) should have the // removed, then it should work

Loading

@ashtanr
Copy link

ashtanr commented Sep 24, 2021

Loading

@ashtanr
Copy link

ashtanr commented Sep 24, 2021

Loading

@KohGeek
Copy link
Author

KohGeek commented Sep 24, 2021

Loading

@bhavpatel54
Copy link

bhavpatel54 commented Oct 14, 2021

Does not work anymore. I had copied and pasted it into the console for edge closer to the publication date and it worked. For whatever reason it times out on the last video and never loops back around

Loading

@KohGeek
Copy link
Author

KohGeek commented Oct 21, 2021

Does not work anymore. I had copied and pasted it into the console for edge closer to the publication date and it worked. For whatever reason it times out on the last video and never loops back around

Apologies for the late reply, I fixed it. It seems Youtube has an always-on miniplayer in the background and that messed with the selector. Changing the query selector fixed it.

Loading

@bhavpatel54
Copy link

bhavpatel54 commented Oct 22, 2021

No worries. just thought id bring it up. and i understand the pain. i dont understand why everything keeps having to change slightly

Loading

@ashtanr
Copy link

ashtanr commented Oct 22, 2021

Loading

@bhavpatel54
Copy link

bhavpatel54 commented Oct 27, 2021

i am using it on edge without any issues.
Simply opening up the "watch later" playlist on youtube.com
scroll all the way to the bottom so all the videos are loaded

Right click in an empty area on in the site. Click on "Inspect"
in the tab that opens
Find "Console"
Copy and past the script inside
and at the very bottom of the script
which will look like below:

// Uncomment the variant that you want below.
//zeWithoutLoop();
//zeLoop();

uncomment the last line so it looks like this

// Uncomment the variant that you want below.
//zeWithoutLoop();
zeLoop();

and run it and wait
Love this. It makes watching all the video so quick

Loading

@ashtanr
Copy link

ashtanr commented Oct 27, 2021

Loading

@KohGeek
Copy link
Author

KohGeek commented Oct 27, 2021

@ashtanr 4000+ is just too much for this algorithm - part of the reason is it takes a long time to refresh: 40 times to load and refresh.

I would recommend this https://ytplaylistsorter.carterrj.co.uk/, but it has a 2000 video limit.

Best method is to just start from the beginning. The estimated time to sort 4000 videos here is around 4.7 days non-stop, if there's no error.

Loading

@ashtanr
Copy link

ashtanr commented Oct 27, 2021

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment