您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows a list of the playlist video names/channels/URLs in plaintext to be easily copied
当前为
// ==UserScript== // @name Export Youtube Playlist in plaintext // @namespace 1N07 // @version 0.7.6 // @description Shows a list of the playlist video names/channels/URLs in plaintext to be easily copied // @author 1N07 // @license unlicense // @compatible firefox Tested on Firefox v133.0.3 and Tampermonkey 5.3.3 // @compatible firefox Likely to work on other userscript managers, but not tested // @compatible chrome Latest version untested, but likely works with at least Tampermonkey // @compatible opera Latest version untested, but likely works with at least Tampermonkey // @compatible edge Latest version untested, but likely works with at least Tampermonkey // @compatible safari Latest version untested, but likely works with at least Tampermonkey // @icon https://www.google.com/s2/favicons?domain=youtube.com // @require https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js // @match https://www.youtube.com/* // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (() => { let getVideoTitle = GM_getValue("getVideoTitle", true); let getVideoChannel = GM_getValue("getVideoChannel", false); let getVideoURL = GM_getValue("getVideoURL", false); let videoListSeperator = GM_getValue("videoListSeperator", " ; "); let listCreationAllowed = true; let urlAtLastCheck = ""; let buttonInsertInterval; //add some CSS if (true) { addGlobalStyle(` tp-yt-paper-listbox#items { overflow-x: hidden; } #exportPlainTextList { cursor: pointer; height: 36px; width: 100%; display: flex; align-items: center; } #exportPlainTextList > img { height: 24px; width: 24px; color: rgb(144, 144, 144); padding: 0 13px 0 16px; filter: contrast(0%); } #exportPlainTextList > span { font-family: "Roboto","Arial",sans-serif; color: var(--yt-spec-text-primary); white-space: nowrap; font-size: 1.4rem; line-height: 2rem; font-weight: 400; } #exportPlainTextList:hover { background-color: rgba(255,255,255,0.1); } ytd-menu-popup-renderer.ytd-popup-container { overflow-x: hidden !important; max-height: none !important; } #listDisplayContainer { position: fixed; z-index: 9999; margin: 0 auto; background-color: #464646; padding: 10px; border-radius: 5px; left: 0; right: 0; max-width: 100vw; width: 1200px; height: 900px; max-height: 90vh; top: 5vh; resize: both; overflow: hidden; } #listDisplayContainer > textarea { box-sizing: border-box; width: 100%; margin: 10px 0; height: calc(100% - 40px); background-color: #262626; border: none; color: #EEE; border-radius: 5px; resize: none; } #closeTheListThing { float: right; font-weight: bold; background-color: RGBA(255,255,255,0.25); border: none; font-size: 17px; border-radius: 10px; height: 25px; width: 25px; cursor: pointer; } #closeTheListThing:hover { background-color: rgba(255,255,255,0.5); } tp-yt-iron-dropdown.ytd-popup-container #contentWrapper > yt-sheet-view-model.ytd-popup-container { max-height: unset !important; } `); } setInterval(() => { if (urlAtLastCheck !== window.location.href) { urlAtLastCheck = window.location.href; if (urlAtLastCheck.includes("/playlist?list=")) InsertButtonASAP(); else clearInterval(buttonInsertInterval); } }, 100); function InsertButtonASAP() { buttonInsertInterval = setInterval(() => { //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 ($("#exportPlainTextList").length === 0) { const place = $("tp-yt-iron-dropdown.ytd-popup-container .yt-list-view-model-wiz[role='menu']"); if (place?.length > 0) { place.append(` <div id="exportPlainTextList"> <img src="https://i.imgur.com/emlur3a.png"> <span>Export Playlist</span> </div> `); $("#exportPlainTextList").click(ScrollUntillAllVisible); } } }, 100); } function ScrollUntillAllVisible() { if (!listCreationAllowed) return; $("ytd-browse[page-subtype='playlist']").click(); listCreationAllowed = false; $("#exportPlainTextList").after(`<p id="listBuildMessage" style="color: red; font-size: 1.33em;">Getting list...<br>please click out of the popup to continue autoscrolling...</p>`); const scrollInterval = setInterval(() => { if ($("ytd-continuation-item-renderer.ytd-playlist-video-list-renderer").length) $(document).scrollTop($(document).height()); else { $("#listBuildMessage").remove(); DisplayListOptions(); clearInterval(scrollInterval); } }, 100); } function DisplayListOptions() { $("body").append( `<div id="listDisplayContainer"> <p style="text-align: center;"> <span style="font-size: 21px; font-weight: bold; color: #d9d9d9;">Playlist in plain text</span> <button id="closeTheListThing">X</button> </p> <textarea style="display: none;">${list}</textarea> <ul id="listDisplayOptions" style="list-style: none; font-size: 12px; scale: 1.4; color: #d9d9d9; width: -moz-fit-content; width: fit-content; margin: 40px auto;"> <li><label><input type="checkbox" ${getVideoTitle ? "checked" : ""} id="getVideoTitleCB" name="getVideoTitleCB" value="getVideoTitle"> Get titles</label></li> <li><label><input type="checkbox" ${getVideoChannel ? "checked" : ""} id="getVideoChannelCB" name="getVideoChannelCB" value="getVideoChannel"> Get channel names</label></li> <li><label><input type="checkbox" ${getVideoURL ? "checked" : ""} id="getVideoURLCB" name="getVideoURLCB" value="getVideoURL"> Get URLs</label></li> <li><label><input type="text" style="width: 40px; text-align: center;" id="videoListSeperatorInput" name="videoListSeperatorInput" value="${videoListSeperator}"> Name/Author/URL seperator</label></li> <li><button id="listDisplayGetListButton" style="position: relative; margin: 10px 0; font-size: 13px; left: 50%; -ms-transform: translateX(-50%); transform: translateX(-50%);">Get list</button></li> </ul> </div>` ); $("#getVideoTitleCB").change(function () { getVideoTitle = $(this).is(":checked"); GM_setValue("getVideoTitle", getVideoTitle); }); $("#getVideoChannelCB").change(function () { getVideoChannel = $(this).is(":checked"); GM_setValue("getVideoChannel", getVideoChannel); }); $("#getVideoURLCB").change(function () { getVideoURL = $(this).is(":checked"); GM_setValue("getVideoURL", getVideoURL); }); $("#videoListSeperatorInput").change(function () { videoListSeperator = $(this).val(); GM_setValue("videoListSeperator", videoListSeperator); }); $("#listDisplayGetListButton").click(BuildAndDisplayList); $("#closeTheListThing").click(() => { $("#listDisplayContainer").remove(); listCreationAllowed = true; }); } function BuildAndDisplayList() { $("#listDisplayOptions").hide(); $("#listDisplayContainer > textarea").show(); const videoTitleArr = []; const videoChannelArr = []; const videoURLArr = []; let videoCount = 0; $("ytd-playlist-video-list-renderer > #contents.ytd-playlist-video-list-renderer > ytd-playlist-video-renderer #content").each(function () { if (getVideoTitle) videoTitleArr.push($(this).find("#video-title").attr("title")); if (getVideoURL) videoURLArr.push(`https://www.youtube.com${$(this).find("#video-title").attr("href").split("&")[0]}`); if (getVideoChannel) videoChannelArr.push($(this).find("#channel-name yt-formatted-string.ytd-channel-name > a").text()); videoCount++; }); let list = ""; for (let i = 0; i < videoCount; i++) { if (getVideoTitle) list += videoTitleArr[i]; if (getVideoChannel) list += (getVideoTitle ? `${videoListSeperator}` : "") + videoChannelArr[i]; if (getVideoURL) list += (getVideoTitle || getVideoChannel ? `${videoListSeperator}` : "") + videoURLArr[i]; list += "\n"; } $("#listDisplayContainer > textarea").html(list); $("#listBuildMessage").remove(); } function addGlobalStyle(css) { const head = document.getElementsByTagName('head')[0]; if (!head) { return; } const style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = css; head.appendChild(style); } })();