您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Load and show YouTube playlists in the sidebar on hover
// ==UserScript== // @name YouTube Sidebar Playlists Loader // @namespace http://tampermonkey.net/ // @version 1.1.2 // @description Load and show YouTube playlists in the sidebar on hover // @author Ahmad H. // @match *://www.youtube.com/* // @grant GM_xmlhttpRequest // @connect www.youtube.com // @compatible ECMAScript 2020+ (ES11+) // @license MIT // ==/UserScript== (function () { 'use strict'; // Run code after the page loads window.addEventListener('load', function () { const sidebar = document.querySelector('#sections'); // Sidebar container console.log("--- Is YT sidebar found ---", !!sidebar); const itemsSection = sidebar?.querySelector('#section-items'); if (!itemsSection) { console.log("==== Not Adding Custom Playlist Link ===="); return; } // Create a new "Playlists" item in the sidebar const playlistLink = document.createElement('a'); playlistLink.innerText = 'My Playlists'; playlistLink.style.cursor = 'pointer'; playlistLink.style.fontSize = "1.4rem"; playlistLink.style.lineHeight = "2rem"; playlistLink.style.fontWeight = "400"; playlistLink.style.padding = '8px 12px 8px 58px'; playlistLink.style.color = '#ddd'; playlistLink.style.background = 'rgba(0,0,0,0)'; playlistLink.style.display = 'block'; itemsSection.appendChild(playlistLink); // Create submenu container for playlists const submenu = document.createElement('div.sub_menu_playlist'); submenu.style.display = 'none'; submenu.style.position = 'absolute'; submenu.style.background = 'rgba(0,0,0,0.8)'; submenu.style.border = '1px solid #aaa'; submenu.style.padding = '10px'; submenu.style.zIndex = '9999'; submenu.style.borderRadius = '10px'; document.body.appendChild(submenu); // Function to fetch playlists const fetchPlaylists = () => { console.log('Start fetchPlaylists:'); GM_xmlhttpRequest({ method: 'GET', url: 'https://www.youtube.com/feed/playlists', onload: function (response) { console.log('after fetcing playlist data'); const ytInitialDataMatch = response.responseText.match(/ytInitialData = ({.*?});<\/script>/); if (ytInitialDataMatch && ytInitialDataMatch[1]) { const ytInitialData = JSON.parse(ytInitialDataMatch[1]); const playlists = ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.richGridRenderer.contents; // Clear existing submenu items while (submenu.firstChild) { submenu.removeChild(submenu.firstChild); } playlists.forEach((item, index) => { const playlistInfo = item.richItemRenderer?.content?.lockupViewModel?.metadata?.lockupMetadataViewModel; const title = playlistInfo?.title?.content; let url = playlistInfo?.metadata?.contentMetadataViewModel?.metadataRows[2]?.metadataParts[0]?.text?.commandRuns[0]?.onTap?.innertubeCommand?.commandMetadata?.webCommandMetadata?.url; url = url || playlistInfo?.metadata?.contentMetadataViewModel?.metadataRows[1]?.metadataParts[0]?.text?.commandRuns[0]?.onTap?.innertubeCommand?.commandMetadata?.webCommandMetadata?.url; if (!url || !title) { console.warn(`!! URL not found for ${title}`); return; } if (title && url) { const playlistItem = document.createElement('a'); playlistItem.href = `https://www.youtube.com${url}`; playlistItem.target = '_blank'; playlistItem.textContent = title; playlistItem.style.display = 'block'; playlistItem.style.color = '#f1f1f1'; playlistItem.style.padding = '5px'; playlistItem.style.fontSize = "1.4rem"; playlistItem.style.lineHeight = "2rem"; playlistItem.style.fontWeight = "400"; if (index < playlists.length - 1) { playlistItem.style.borderBottom = "1px solid #ccc"; } playlistItem.style.textDecoration = 'none'; playlistItem.addEventListener('mouseover', () => { playlistItem.style.color = 'yellow'; }); playlistItem.addEventListener('mouseout', () => { playlistItem.style.color = '#f1f1f1'; }); submenu.appendChild(playlistItem); } }); } } }); }; fetchPlaylists(); // Toggle submenu visibility playlistLink.addEventListener('mouseenter', () => { playlistLink.style.backgroundColor = 'rgba(255, 255, 255, 0.1)'; playlistLink.style.borderRadius = '10px'; submenu.style.display = 'block'; // Show the submenu const rect = playlistLink.getBoundingClientRect(); submenu.style.left = `${rect.right + 10}px`; // Position submenu to the right of the link submenu.style.top = `${rect.top}px`; }); playlistLink.addEventListener('mouseleave', () => { playlistLink.style.backgroundColor = 'rgba(0, 0, 0, 0)'; playlistLink.style.borderRadius = '0'; setTimeout(() => { if (!submenu.matches(':hover')) submenu.style.display = 'none'; }, 200); }); submenu.addEventListener('mouseleave', () => { submenu.style.display = 'none'; }); submenu.addEventListener('mouseenter', () => { submenu.style.display = 'block'; }); }); })();