您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在主按鈕列新增一個「儲存」快捷鍵,點擊自動展開選單並點擊儲存
// ==UserScript== // @name YouTube 修復儲存快捷按鈕 // @namespace http://tampermonkey.net/ // @version 1.3.1 // @description 在主按鈕列新增一個「儲存」快捷鍵,點擊自動展開選單並點擊儲存 // @author shanlan(ChatGPT o3-mini) // @match *://*.youtube.com/* // @grant none // @run-at document-end // @license MIT // ==/UserScript== (function(){ 'use strict'; const observer = new MutationObserver(addSaveShortcut); observer.observe(document.body, {childList: true, subtree: true}); function addSaveShortcut(){ const topBtnsList = Array.from(document.querySelectorAll('#top-level-buttons-computed')) .filter(el => el.closest('ytd-watch-metadata')); if(!topBtnsList.length) return; topBtnsList.forEach(topBtns => { const menuRenderer = topBtns.closest('ytd-menu-renderer'); const hasNativeSave = menuRenderer && Array.from(menuRenderer.querySelectorAll('button')).some(b => !b.classList.contains('yt-save-shortcut-btn') && /儲存|Save/i.test((b.innerText || b.textContent || b.getAttribute('aria-label') || b.title || '').trim()) ); if (topBtns.querySelector('.yt-save-shortcut-btn') || hasNativeSave) return; const btn = document.createElement('button'); btn.className = 'yt-spec-button-shape-next yt-spec-button-shape-next--tonal yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-leading yt-save-shortcut-btn'; btn.style.marginLeft = '8px'; btn.innerHTML = ` <div aria-hidden="true" class="yt-spec-button-shape-next__icon"> <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24" style="vertical-align:middle"> <path d="M18 4v15.06l-5.42-3.87-.58-.42-.58.42L6 19.06V4h12m1-1H5v18l7-5 7 5V3z"></path> </svg> </div> <div class="yt-spec-button-shape-next__button-text-content">儲存</div>`; btn.onclick = function(e){ e.stopPropagation(); const top = e.currentTarget.closest('#top-level-buttons-computed'); const container = top ? top.parentElement : null; const moreBtn = container ? container.querySelector('yt-icon-button#button, yt-button-shape#button-shape, ytd-button-renderer #button') : null; if(!moreBtn) return; moreBtn.dispatchEvent(new MouseEvent('click', {bubbles: true, composed: true})); let tryCount = 0; const tryClickSave = setInterval(()=>{ tryCount++; const menus = Array.from(document.querySelectorAll('ytd-menu-popup-renderer')).filter(m => m.offsetParent !== null); const saveItem = menus.flatMap(m => Array.from(m.querySelectorAll('ytd-menu-service-item-renderer, tp-yt-paper-item'))) .find(item => /儲存|Save/i.test(item.innerText.trim())); if(saveItem){ saveItem.click(); clearInterval(tryClickSave); } if(tryCount > 30) clearInterval(tryClickSave); }, 100); }; topBtns.appendChild(btn); }); } })();