Export Youtube Playlist in tab delimited text

Shows a list of the playlist video names in tab delimited text to be easily copied

当前为 2020-12-14 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Export Youtube Playlist in tab delimited text
  3. // @namespace 1N07 & MK
  4. // @version 0.4.1
  5. // @description Shows a list of the playlist video names in tab delimited text to be easily copied
  6. // @author 1N07 & MK
  7. // @require https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
  8. // @include https://www.youtube.com/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. var listCreationAllowed = true;
  16. var urlAtLastCheck = "";
  17. setInterval(function() {
  18. if (urlAtLastCheck != window.location.href) {
  19. urlAtLastCheck = window.location.href;
  20. if (urlAtLastCheck.includes("/playlist?list=")) InsertButtonASAP();
  21. }
  22. }, 100);
  23.  
  24.  
  25. function InsertButtonASAP() {
  26. let buttonInsertInterval = setInterval(function() {
  27. //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
  28. if ($("#exportTabTextList").length == 0 && $("ytd-playlist-sidebar-secondary-info-renderer > #owner-container").length > 0) {
  29. $("ytd-playlist-sidebar-secondary-info-renderer > #owner-container").parent().after("<button id='exportTabTextList' style='font-family: Roboto, Arial, sans-serif; font-size: 13px;'>Export as tab delimited text</button>");
  30. $("#exportTabTextList").click(ScrollUntillAllVisible);
  31. clearInterval(buttonInsertInterval);
  32. }
  33. }, 100);
  34. }
  35.  
  36. function ScrollUntillAllVisible() {
  37. if (!listCreationAllowed) return;
  38.  
  39. listCreationAllowed = false;
  40. $("#exportTabTextList").after(`<p id="listBuildMessage" style="color: red; font-size: 1.33em;">Getting list... please wait.</p>`);
  41. 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, '');
  42. let scrollInterval = setInterval(function(){
  43. if ($("yt-formatted-string#index.ytd-playlist-video-renderer").last().text() != numOfVideosInPlaylist)
  44. $(document).scrollTop($(document).height());
  45. else {
  46. BuildAndDisplayList();
  47. clearInterval(scrollInterval);
  48. }
  49. }, 100);
  50. }
  51.  
  52. function BuildAndDisplayList() {
  53. let list = "<Name>\t<Channel>\t<Duration>";
  54. /*let vTitle = "";
  55. let vChannel = "";
  56. let vDuration = "";
  57. let vFull = "";
  58. $("ytd-playlist-video-renderer #content #video-title").each(function() {
  59. vTitle = $(this).attr("title");
  60. if (vTitle != "[Private video]" && vTitle != "[Deleted video]") {
  61. vFull = $(this).attr("aria-label");
  62. vFull = vFull.replace(vTitle, "");
  63. vFull = vFull.replace(" by ", "\t");
  64. vFull = vFull.replace(/\w+(?=\s+ago)/g, "");
  65. vFull = vFull.replace(/\w+(?=\s+ago)/g, "");
  66. vFull = vFull.replace(" ago ", "\t");
  67. list += vTitle + vFull + "\n";
  68. } else {
  69. list += vTitle + "\n";
  70. }
  71. });*/
  72.  
  73. var myNodeList = document.querySelectorAll("div");
  74. var i;
  75. for (i = 0; i < myNodeList.length; i++) {
  76. if (myNodeList[i].id == "content" && myNodeList[i].className == "style-scope ytd-playlist-video-renderer") {
  77. var mySpanList = myNodeList[i].querySelectorAll("span");
  78. var myAList = myNodeList[i].querySelectorAll("a");
  79. var j;
  80. for (j = 0; j < mySpanList.length; j++) {
  81. if (mySpanList[j].id == "video-title") {
  82. list += "\n" + mySpanList[j].innerText.trim();
  83. }
  84. }
  85. for (j = 0; j < myAList.length; j++) {
  86. if (myAList[j].className == "yt-simple-endpoint style-scope yt-formatted-string") {
  87. list += "\t" + myAList[j].innerText.trim();
  88. }
  89. }
  90. for (j = 0; j < mySpanList.length; j++) {
  91. if (mySpanList[j].className == "style-scope ytd-thumbnail-overlay-time-status-renderer") {
  92. list += "\t " + mySpanList[j].innerText;
  93. }
  94. }
  95. }
  96. }
  97.  
  98. $("body").append('<div id="tablistDisplayContainer" style="position: fixed; z-index: 9999; top: 5%; right: 5%; background-color: gray; padding: 10px; border-radius: 5px;"><button id="selectAllAndCopy" style="font-family: Roboto, Arial, sans-serif; font-size: 13px;">Select all and copy</button>&nbsp;&nbsp;&nbsp;<button id="closeTheListThing" style="font-family: Roboto, Arial, sans-serif; font-size: 13px;">Close</button><br><br><textarea id="tabPlayList" style="width: 50vw; height: 80vh; max-width: 90vw; max-height: 90vh;">'+list+'</textarea></div>');
  99. $("#listBuildMessage").remove();
  100. $("#closeTheListThing").click(function() {
  101. $("#tablistDisplayContainer").remove();
  102. listCreationAllowed = true;
  103. });
  104. $("#selectAllAndCopy").click(function() {
  105. document.getElementById("tabPlayList").select();
  106. document.execCommand("copy");
  107. });
  108. }
  109.  
  110. }) ();