您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Quickly create playlists from your Youtube subscription feed
// ==UserScript== // @name Youtube Subscription List Quick Playlist // @namespace https://greasyfork.org/en/users/13981-chk1 // @description Quickly create playlists from your Youtube subscription feed // @include https://www.youtube.com/feed/subscriptions* // @version 1.0.3 // @grant GM_addStyle // @run-at document-end // ==/UserScript== GM_addStyle("#subs2playlistContainer { position:fixed; bottom: 10px; right: 10px; width: 180px; } "); GM_addStyle("#subs2playlistLink { display: block; clear: both; } "); GM_addStyle("#subs2playlistClear { float: right; font-size: 12px; padding-top: 5px; padding-bottom: 5px; display: block; color: #bb0000; }"); GM_addStyle("#subs2playlistCopy { float: left; font-size: 12px; padding-top: 5px; padding-bottom: 5px; display: block; color: #000; }"); GM_addStyle("#subs2playlistCopyTemp { width:1px; height:1px; position:fixed; }"); GM_addStyle("#subs2playlistContainer input { font-size: 12px; display:block; color: #767676; clear:both; width: 100%; border: 1px solid #d5d5d5; border-radius: 2px; font-family: monospace }"); GM_addStyle("#subs2playlistContainer span { font-size: 12px; display:block; clear:both; transition: color 0.2s; color: #767676; }"); GM_addStyle("#subs2playlistContainer span.warning { color: #bb0000; }"); GM_addStyle(".subs2playlist.subs2playlist-add span::after { content: 'Add to playlist' }"); GM_addStyle(".subs2playlist.subs2playlist-remove span::after { content: 'Remove from playlist' }"); var videoIds = []; var playlistElements; // create DOM nodes function createPlaylistContainer() { var playlistLinkContainer = document.createElement('div'); playlistLinkContainer.className = "yt-card yt-card-has-padding"; playlistLinkContainer.id = "subs2playlistContainer"; var playlistLinkH3 = document.createElement('h3'); playlistLinkH3.className = "yt-lockup-title"; var playlistLink = document.createElement('a'); playlistLink.href = "https://www.youtube.com/watch_videos?video_ids="; playlistLink.id = "subs2playlistLink"; var playlistLinkText = document.createTextNode("Your playlist link"); var playlistLinkCount = document.createElement("span"); playlistLinkCount.innerHTML = "0 videos"; var clearLink = document.createElement("a"); clearLink.id = "subs2playlistClear"; clearLink.onclick = function() { clearPlaylist() }; var clearText = document.createTextNode("Clear"); var copyLink = document.createElement("a"); copyLink.id = "subs2playlistCopy"; var copyText = document.createTextNode('Copy IDs'); var copyLinkInput = document.createElement('input'); copyLinkInput.type = "text"; copyLinkInput.placeholder = "video IDs..."; copyLinkInput.className = "yt-uix-form-input-bidi"; copyLink.onclick = function() { html5Copy(copyLinkInput); }; var playlistLinkFunctionContainer = document.createElement('div'); var introText = document.createElement("span"); introText.innerHTML = "Add videos from your subscription box to create a quick playlist."; copyLink.appendChild(copyText); clearLink.appendChild(clearText); playlistLink.appendChild(playlistLinkText); playlistLinkH3.appendChild(playlistLink); playlistLinkContainer.appendChild(playlistLinkH3); playlistLinkFunctionContainer.appendChild(playlistLinkCount); playlistLinkFunctionContainer.appendChild(clearLink); playlistLinkFunctionContainer.appendChild(copyLink); playlistLinkFunctionContainer.appendChild(copyLinkInput); playlistLinkFunctionContainer.style.display = "none"; playlistLinkContainer.appendChild(playlistLinkH3); playlistLinkContainer.appendChild(introText); playlistLinkContainer.appendChild(playlistLinkFunctionContainer); return { 'container': playlistLinkContainer, 'link': playlistLink, 'text': playlistLinkText, 'plain': copyLinkInput, 'count': playlistLinkCount, 'intro': introText, 'functioncontainer': playlistLinkFunctionContainer }; } // copy video IDs to clipboard function html5Copy(inputnode){ var node = document.createElement('pre'); node.className = 'subs2playlistCopyTemp'; node.textContent = inputnode.value; document.body.appendChild(node); var selection = getSelection(); selection.removeAllRanges() var range = document.createRange(); range.selectNodeContents(node); console.log(range); selection.addRange(range); document.execCommand('copy'); document.body.removeChild(node); } // update playlist link, run after adding/removing videos function updatePlaylistLink() { // toggle intro text visibility off playlistElements.functioncontainer.style.display = "block"; playlistElements.intro.style.display = "none"; // check playlist length for known limits if(videoIds.length > 20) { playlistElements.count.classList.add("warning"); playlistElements.count.textContent = ""+videoIds.length+" videos - The playlist link will only play the first 20 videos."; } else if(playlistElements.text.textContent.length > 2000){ playlistElements.count.classList.add("warning"); playlistElements.count.textContent = ""+videoIds.length+" videos - Too many videos, URL is too long. Some videos in the playlist link may not work."; } else { playlistElements.count.classList.remove("warning"); playlistElements.link.href="https://www.youtube.com/watch_videos?video_ids="+videoIds.join(','); playlistElements.plain.value=videoIds.join(','); playlistElements.count.textContent = ""+videoIds.length+" videos"; } } // clear all video IDs, reset buttons function clearPlaylist() { videoIds = []; var buttons = document.querySelectorAll('#browse-items-primary > .section-list .subs2playlist'); for (var i = 0; i < buttons.length; ++i) { buttons[i].classList.remove("subs2playlist-remove"); //buttons[i].classList.remove("yt-uix-button-subscribed-branded"); buttons[i].classList.remove("c4-module-editor-delete"); buttons[i].classList.add("subs2playlist-add"); buttons[i].classList.add("c4-editor-plus"); } updatePlaylistLink(); } // only add videos that aren't duplicates function toggleVideoId(videoId){ var alreadyIn = videoIds.indexOf(videoId); if(alreadyIn === -1){ videoIds.push(videoId); return true; } else { videoIds.splice(alreadyIn, 1); return false; } } // add a button to a subscription list item function createPlusButton(videoId){ var container = document.createElement('button'); container.setAttribute('onclick', 'toggleVideoId(\''+videoId+'\');'); container.className = "subs2playlist subs2playlist-add yt-uix-button yt-uix-button-size-default yt-uix-button-default yt-uix-button-has-icon no-icon-markup yt-uix-inlineedit-edit c4-editor-plus"; container.onclick = function(){ toggleVideoId(videoId); container.classList.toggle("c4-module-editor-delete"); container.classList.toggle("c4-editor-plus"); container.classList.toggle("subs2playlist-remove"); container.classList.toggle("subs2playlist-add"); updatePlaylistLink(); }; container.innerHTML = "<span class=\"yt-uix-button-content\"></span>"; return container; } // iterate subscription list items, then add buttons function appendAllTheThings(node) { var videoId = node.getAttribute("data-context-item-id"); var plusButtonNode = createPlusButton(videoId); node.appendChild(plusButtonNode); } var observerConfig = { childList: true, attributes: true, subtree: false, attributeOldValue: false }; // add buttons to items loaded after clicking "load more" or endless scroll, which are dynamically added var listObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if(mutation.type == "childList" && mutation.addedNodes.length >= 1) { console.log(mutation); for (var i = 0; i < mutation.addedNodes.length; ++i) { var node = mutation.addedNodes[i]; if(node.nodeType === 1){ var videoLinkContainer = node.querySelector('.yt-lockup'); appendAllTheThings(videoLinkContainer); } } } }); }); var subListContainer = document.querySelector('#browse-items-primary > .section-list'); listObserver.observe(subListContainer, observerConfig); // first run: create our container, add buttons to playlist items function firstRun(){ var videoLinkNodes = document.querySelectorAll('div.yt-lockup'); for (var i = 0; i < videoLinkNodes.length; ++i) { var node = videoLinkNodes[i]; appendAllTheThings(node); } playlistElements = createPlaylistContainer(); document.body.appendChild(playlistElements.container); } firstRun();