// ==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
//
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 = "