您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Creates the current playlist as tab delimited text to be easily copied
当前为
- // ==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
- // @match *://*.youtube.com/*
- // @match *://*.youtu.be/*
- // @icon https://cdn.icon-icons.com/icons2/1488/PNG/512/5295-youtube-i_102568.png
- // @version 2.0
- // @license MIT
- // @run-at document-idle
- // ==/UserScript==
- (function() {
- // @require https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
- 'use strict';
- //This document requires TrustedHTML assignment https://greasyfork.org/en/discussions/development/220765-this-document-requires-trustedhtml-assignment
- if (window.trustedTypes != undefined && window.trustedTypes.createPolicy) {
- window.trustedTypes.createPolicy('default', {
- createHTML: (string, sink) => string
- });
- }
- var listCreationAllowed = true;
- var urlAtLastCheck = "";
- var htmlText;
- setInterval(function() {
- if (urlAtLastCheck != window.location.href) {
- urlAtLastCheck = window.location.href;
- if (urlAtLastCheck.includes("/playlist?list=")) InsertButtonASAP();
- }
- }, 100);
- function InsertButtonASAP() {
- var qRes = document.querySelectorAll("#exportTabTextList"); //Remove previous button
- for (let i = 0; i < qRes.length; i++) {
- qRes[i].remove();
- }
- let buttonInsertInterval = setInterval(function() {
- if (document.querySelectorAll("#exportTabTextList").length == 0) {
- if (document.querySelectorAll("div.ytd-playlist-header-renderer > div.play-menu.ytd-playlist-header-renderer").length > 0) { //New design
- qRes = document.querySelectorAll("div.metadata-wrapper.ytd-playlist-header-renderer > div.play-menu.ytd-playlist-header-renderer");
- if (qRes != null && qRes.length > 0) {
- htmlText = "<button id='exportTabTextList' class='yt-spec-button-shape-next--size-m' style='font-family: Roboto, Arial, sans-serif; font-size: 13px; margin-bottom: 16px; padding-top:2px; border: none; height: 28px; line-height: normal; opacity: 0.8;'>Export list as tab delimited text</button>";
- if (window.trustedTypes != undefined) qRes[0].insertAdjacentHTML("afterend", window.trustedTypes.defaultPolicy.createHTML(htmlText));
- else qRes[0].insertAdjacentHTML("afterend", htmlText);
- }
- qRes = document.querySelectorAll("#exportTabTextList");
- if (qRes != null && qRes.length > 0) {
- qRes[0].onclick = ScrollUntilFullListVisible;
- }
- } else if (document.querySelectorAll("ytd-playlist-sidebar-renderer:not([hidden]) > ytd-playlist-sidebar-primary-info-renderer.style-scope.ytd-playlist-sidebar-renderer").length > 0) { //Old design
- qRes = document.querySelectorAll("ytd-playlist-sidebar-primary-info-renderer.style-scope.ytd-playlist-sidebar-renderer");
- if (qRes != null && qRes.length > 0) {
- htmlText = "<button id='exportTabTextList' style='font-family: Roboto, Arial, sans-serif; font-size: 13px; margin: 10px 0px;'>Export list as tab delimited text</button>"
- if (window.trustedTypes != undefined) qRes[0].insertAdjacentHTML("afterend", window.trustedTypes.defaultPolicy.createHTML(htmlText));
- else qRes[0].insertAdjacentHTML("afterend", htmlText);
- }
- qRes = document.querySelectorAll("#exportTabTextList");
- if (qRes != null && qRes.length > 0) {
- qRes[0].onclick = ScrollUntilFullListVisible;
- }
- }
- //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.indexOf("unavailable videos are hidden") > -1) {
- // flgHidden = true;
- // break;
- // }
- // }
- //}
- //if (flgHidden) {
- // $("#exportTabTextList").click(ScrollAsPossible); //Unavailable videos are hidden
- //} 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;
- var numOfVideos = document.querySelectorAll(".metadata-stats");
- if (numOfVideos != null && numOfVideos.length > 0) {
- numOfVideos = numOfVideos[0].innerText.replace(/\ .*/g, '');
- listCreationAllowed = false;
- var qRes = document.querySelectorAll("#exportTabTextList:not(.yt-spec-button-shape-next--size-m)");
- if (qRes != null && qRes.length > 0) {
- htmlText = `<p id="listBuildMessage" style="color: red; font-size: 1.33em;">Getting full list, please wait...</p>`;
- if (window.trustedTypes != undefined) qRes[0].insertAdjacentHTML("afterend", window.trustedTypes.defaultPolicy.createHTML(htmlText));
- else qRes[0].insertAdjacentHTML("afterend", htmlText);
- }
- qRes = document.querySelectorAll("#exportTabTextList.yt-spec-button-shape-next--size-m");
- if (qRes != null && qRes.length > 0) {
- htmlText = `<p id="listBuildMessage" style="color: red; font-size: 1.33em; margin-bottom: 16px; mix-blend-mode: lighten;">Getting full list, please wait...</p>`;
- if (window.trustedTypes != undefined) qRes[0].insertAdjacentHTML("afterend", window.trustedTypes.defaultPolicy.createHTML(htmlText));
- else qRes[0].insertAdjacentHTML("afterend", htmlText);
- }
- let scrollInterval = setInterval(function(){
- if (document.querySelectorAll("ytd-continuation-item-renderer.ytd-playlist-video-list-renderer").length > 0) {
- $(document).scrollTop($(document).height());
- } else {
- BuildAndDisplayList();
- clearInterval(scrollInterval);
- }
- }, 100);
- }
- }
- /*function ScrollAsPossible() { //If unavailable videos are hidden
- if (!listCreationAllowed) return;
- listCreationAllowed = false;
- $("#exportTabTextList").after(`<p id="listBuildMessage" style="color: red; font-size: 1.33em;">Getting full list, please wait...</p>`);
- $(document).scrollTop($(document).height());
- let scrollInterval2 = setInterval(function(){
- if (CheckSpinner()) {
- $(document).scrollTop($(document).height());
- } else {
- BuildAndDisplayList();
- clearInterval(scrollInterval2);
- }
- }, 500);
- }
- function CheckSpinner() { //True if playlist is still loading
- var i;
- var myNodeList = document.querySelectorAll("#spinner");
- for (i = 0; i < myNodeList.length; i++) {
- if (myNodeList[i].className.indexOf("style-scope ytd-continuation-item-renderer") > -1) return true;
- }
- return false;
- }*/
- function BuildAndDisplayList() {
- let list = "<Name>\t<Channel>\t<Duration>\t<URL>";
- var myNodeList = document.querySelectorAll("ytd-playlist-video-renderer");
- var i;
- var myCount = 0;
- for (i = 0; i < myNodeList.length; i++) {
- if (myNodeList[i].className.indexOf("style-scope ytd-playlist-video-list-renderer") > -1) {
- var mySpanList = myNodeList[i].querySelectorAll("span");
- var myAList = myNodeList[i].querySelectorAll("a");
- var j;
- var strAux = "";
- var strAux2 = "";
- myCount++;
- 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
- strAux2 = strAux2.replace(/&pp=.*$/gi, ""); //Remove pp parameter
- }
- }
- 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
- }
- }
- var qRes = document.querySelectorAll("body");
- if (qRes != null && qRes.length > 0) {
- htmlText = '<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> <button id="closeTheListThing" style="font-family: Roboto, Arial, sans-serif; font-size: 13px;">Close</button> <span style="font-family: Roboto, Arial, sans-serif; font-size: 13px; font-weight: bold; color: white">Total videos in list: '+myCount+'</span><br><br><textarea id="tabPlayList" style="width: 50vw; height: 80vh; max-width: 90vw; max-height: 90vh;">'+list+'</textarea></div>';
- if (window.trustedTypes != undefined) qRes[0].insertAdjacentHTML("afterend", window.trustedTypes.defaultPolicy.createHTML(htmlText));
- else qRes[0].insertAdjacentHTML("afterend", htmlText);
- }
- qRes = document.querySelector("#listBuildMessage");
- if (qRes != null) qRes.remove();
- qRes = document.querySelector("#closeTheListThing");
- if (qRes != null) {
- qRes.onclick = function() {
- qRes = document.querySelector("#tablistDisplayContainer");
- if (qRes != null) qRes.remove();
- listCreationAllowed = true;
- }
- }
- qRes = document.querySelector("#selectAllAndCopy");
- if (qRes != null) {
- qRes.onclick = function() {
- document.getElementById("tabPlayList").select();
- document.execCommand("copy");
- }
- }
- }
- }) ();