// ==UserScript== // @name Export Youtube Playlist in tab delimited text // @description Creates the current playlist as tab delimited text to be easily copied // @author 1N07 & MK // @namespace max44 // @homepage https://greasyfork.org/en/users/309172-max44 // @include https://www.youtube.com/* // @require https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js // @version 0.4.7.1 // @note v0.4.7.1 - temporary solution for lists with hidden videos // @note v0.4.7 2021-05-03 - error, when button disappears after switching hide/show unavailable videos, is corrected // @note v0.4.6 2021-04-19 - error, when some videos with "watched" status were missed from exported data, is corrected // @note v0.4.5 2021-03-07 - timestamp is removed from video URL // @note v0.4.4 2021-03-07 - video URL is added to exported data // @note v0.4.2 2021-02-17 - amendments to recognized new CSS code for video name // @note v0.4.1 2020-12-14 - various bugfixes and improvements // @note v0.4 2020-12-14 - initial fork // @downloadURL none // ==/UserScript== (function() { 'use strict'; var listCreationAllowed = true; var urlAtLastCheck = ""; setInterval(function() { if (urlAtLastCheck != window.location.href) { urlAtLastCheck = window.location.href; if (urlAtLastCheck.includes("/playlist?list=")) InsertButtonASAP(); } }, 100); function InsertButtonASAP() { let buttonInsertInterval = setInterval(function() { //wait for possible previous buttons to stop existing (due to how youtube loads pages) and for the space for the new button to be available if ($("#exportTabTextList").length == 0 && $("ytd-playlist-sidebar-secondary-info-renderer > #owner-container").length > 0) { $("ytd-playlist-sidebar-secondary-info-renderer > #owner-container").parent().after(""); //Check whether unavailable videos are hidden or not var i; var strAux = ""; var flgHidden = false; var myNodeList = document.querySelectorAll("#text"); for (i = 0; i < myNodeList.length; i++) { if (myNodeList[i].className.indexOf("style-scope ytd-alert-with-button-renderer") > -1) { strAux = myNodeList[i].innerText; strAux = strAux.trim(); strAux = strAux.toLowerCase(); if (strAux == "unavailable videos are hidden") { flgHidden = true; break; } } } //If unavailable videos are hidden, do not scroll till the very end of the list //Unavailable videos are hidden if (flgHidden) { $("#exportTabTextList").after(`

Some videos are hidden. Temporarily cannot create a list for copy

`); //$("#exportTabTextList").click(ScrollAsPossible); } else { $("#exportTabTextList").click(ScrollUntilFullListVisible); } //clearInterval(buttonInsertInterval); - Do not clear interval in order to add button back if playlist is rebuilt } }, 100); } function ScrollUntilFullListVisible() { if (!listCreationAllowed) return; listCreationAllowed = false; $("#exportTabTextList").after(`

Getting full list, please wait...

`); let numOfVideosInPlaylist = $("ytd-playlist-sidebar-renderer.ytd-browse > #items #stats > yt-formatted-string.ytd-playlist-sidebar-primary-info-renderer:first").text().replace(/(\D+|\s+)/g, ''); let scrollInterval = setInterval(function(){ if ($("yt-formatted-string#index.ytd-playlist-video-renderer").last().text() != numOfVideosInPlaylist) $(document).scrollTop($(document).height()); else { BuildAndDisplayList(); clearInterval(scrollInterval); } }, 100); } function ScrollAsPossible() { function sleep(miliseconds) { var currentTime = new Date().getTime(); while (currentTime + miliseconds >= new Date().getTime()) {} } if (!listCreationAllowed) return; listCreationAllowed = false; $("#exportTabTextList").after(`

Getting list w/o unavailable videos, please wait...

`); //let numOfVideosInPlaylist = $("ytd-playlist-sidebar-renderer.ytd-browse > #items #stats > yt-formatted-string.ytd-playlist-sidebar-primary-info-renderer:first").text().replace(/(\D+|\s+)/g, ''); //let scrollInterval = setInterval(function(){ var iH = $(document).height(); var iHNew = iH; var flgLoop = true; while (flgLoop) { flgLoop = false; $(document).scrollTop(iH + 100); sleep(1000); iHNew = $(document).height(); console.log(`iH: ${iH} iHNew: ${iHNew}`); //$("#listBuildMessage").remove(); //$("#exportTabTextList").after(`

iH: ${iH} iHNew: ${iHNew}

`); if (iH < iHNew) { iH = iHNew; flgLoop = true; } } BuildAndDisplayList(); } function BuildAndDisplayList() { let list = "\t\t\t"; /*let vTitle = ""; let vChannel = ""; let vDuration = ""; let vFull = ""; $("ytd-playlist-video-renderer #content #video-title").each(function() { vTitle = $(this).attr("title"); if (vTitle != "[Private video]" && vTitle != "[Deleted video]") { vFull = $(this).attr("aria-label"); vFull = vFull.replace(vTitle, ""); vFull = vFull.replace(" by ", "\t"); vFull = vFull.replace(/\w+(?=\s+ago)/g, ""); vFull = vFull.replace(/\w+(?=\s+ago)/g, ""); vFull = vFull.replace(" ago ", "\t"); list += vTitle + vFull + "\n"; } else { list += vTitle + "\n"; } });*/ var myNodeList = document.querySelectorAll("div"); var i; for (i = 0; i < myNodeList.length; i++) { if (myNodeList[i].id == "content" && myNodeList[i].className.indexOf("style-scope ytd-playlist-video-renderer") > -1) { var mySpanList = myNodeList[i].querySelectorAll("span"); var myAList = myNodeList[i].querySelectorAll("a"); var j; var strAux = ""; var strAux2 = ""; for (j = 0; j < myAList.length; j++) { if (myAList[j].id == "video-title") { strAux = myAList[j].innerText; //Video title strAux = strAux.replace(/[\x0D\x0A]/g, " "); list += "\n" + strAux.trim(); strAux2 = myAList[j].href; //Video URL strAux2 = strAux2.replace(/&list=.*&index=\d+/gi, ""); //Remove reference to list and video's index strAux2 = strAux2.replace(/&t=.*$/gi, ""); //Remove timestamp } } list += "\t"; for (j = 0; j < myAList.length; j++) { if (myAList[j].className == "yt-simple-endpoint style-scope yt-formatted-string") { strAux = myAList[j].innerText; //Channel name strAux = strAux.replace(/[\x0D\x0A]/g, " "); list += strAux.trim(); } } list += "\t "; for (j = 0; j < mySpanList.length; j++) { if (mySpanList[j].className == "style-scope ytd-thumbnail-overlay-time-status-renderer") { strAux = mySpanList[j].innerText; //Duration strAux = strAux.replace(/[\x0D\x0A]/g, " "); list += strAux.trim(); } } list += "\t" + strAux2.trim(); //Video URL is the last column } } $("body").append('
   

'); $("#listBuildMessage").remove(); $("#closeTheListThing").click(function() { $("#tablistDisplayContainer").remove(); listCreationAllowed = true; }); $("#selectAllAndCopy").click(function() { document.getElementById("tabPlayList").select(); document.execCommand("copy"); }); } }) ();