您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds quick Watch Later button
// ==UserScript== // @name YouTube Quick Watch Later // @namespace http://tampermonkey.net/ // @version 2.4 // @description Adds quick Watch Later button // @author kavinned // @match https://www.youtube.com/* // @grant GM_addStyle // @icon https://www.google.com/s2/favicons?sz=64&domain=YouTube.com // @license MIT // ==/UserScript== (function () { "use strict"; // Configuration: Add "Save" translations here const SAVE_BUTTON_TEXTS = [ "Save", // English "儲存", // Traditional Chinese "保存", // Simplified Chinese "Guardar", // Spanish "Sauvegarder", // French "Speichern", // German "Salvar", // Portuguese "Сохранить", // Russian "保存", // Japanese "저장", // Korean "บันทึก", // Thai "Simpan", // Indonesian "Lưu" // Vietnamese ]; function addWatchLaterButton() { const targetDiv = document.querySelector( "#top-level-buttons-computed > segmented-like-dislike-button-view-model > yt-smartimation > div" ); if (!targetDiv || document.querySelector(".quick-watch-later")) return; const button = document.createElement("button"); button.className = "quick-watch-later"; button.textContent = "WL"; button.addEventListener("click", function () { // Helper function to check if text contains any of the save button texts function containsSaveText(text) { return SAVE_BUTTON_TEXTS.some(saveText => text.includes(saveText)); } // First check if Save button is directly visible const directSaveButton = document.querySelector( "ytd-menu-renderer yt-button-view-model .yt-spec-button-shape-next__button-text-content" ); const directSaveButtonWithText = Array.from( document.querySelectorAll("ytd-menu-renderer yt-button-view-model .yt-spec-button-shape-next__button-text-content") ).find(element => containsSaveText(element.textContent)); if (directSaveButtonWithText) { // Save button is directly visible, click it console.log("Direct save button found, clicking it"); directSaveButtonWithText.click(); // Then proceed to click the Watch Later button setTimeout(function () { const watchLaterBox = document.querySelector( "#playlists > ytd-playlist-add-to-option-renderer:first-child #checkbox" ); if ( watchLaterBox && watchLaterBox.getAttribute("aria-checked") === "true" ) { const confirmRemove = window.confirm( "This video is already in your Watch Later playlist. Do you want to remove it?" ); if (confirmRemove) { watchLaterBox.click(); const closeButton = document.querySelector( "#button > yt-icon > span" ); if (closeButton) { closeButton.click(); } } else { const closeButton = document.querySelector( "#button > yt-icon > span" ); if (closeButton) { closeButton.click(); } } } else { // If the video isn't in Watch Later, proceed with adding it watchLaterBox.click(); const closeButton = document.querySelector( "#button > yt-icon > span" ); if (closeButton) { closeButton.click(); } } }, 1000); } else { // Save button is in submenu, use original logic console.log("Save button not directly visible, opening menu"); // First click menu button const menuButton = document.querySelector( "#button-shape > button > yt-touch-feedback-shape > div" ); menuButton.click(); if (menuButton) { console.log("menu clicked"); } // Next click the Save button setTimeout(function () { const saveButtons = document.querySelectorAll( "#items > ytd-menu-service-item-renderer > tp-yt-paper-item > yt-formatted-string" ); const saveButton = Array.from(saveButtons).find((button) => containsSaveText(button.textContent) ); saveButton.click(); // Then click the Watch Later button setTimeout(function () { const watchLaterBox = document.querySelector( "#playlists > ytd-playlist-add-to-option-renderer:first-child #checkbox" ); if ( watchLaterBox && watchLaterBox.getAttribute("aria-checked") === "true" ) { const confirmRemove = window.confirm( "This video is already in your Watch Later playlist. Do you want to remove it?" ); if (confirmRemove) { watchLaterBox.click(); const closeButton = document.querySelector( "#button > yt-icon > span" ); if (closeButton) { closeButton.click(); } } else { const closeButton = document.querySelector( "#button > yt-icon > span" ); if (closeButton) { closeButton.click(); } } } else { // If the video isn't in Watch Later, proceed with adding it watchLaterBox.click(); const closeButton = document.querySelector( "#button > yt-icon > span" ); if (closeButton) { closeButton.click(); } } }, 1000); }, 100); } }); targetDiv.appendChild(button); } setTimeout(addWatchLaterButton, 2000); const observer = new MutationObserver(() => { if (window.location.href.includes("/watch?")) { setTimeout(addWatchLaterButton, 1000); } }); observer.observe(document.body, { childList: true, subtree: true }); GM_addStyle( `#top-level-buttons-computed > segmented-like-dislike-button-view-model > yt-smartimation > div { display: flex; flex-direction: row-reverse; gap: 5px; } #top-level-buttons-computed > segmented-like-dislike-button-view-model > yt-smartimation > div > button { flex-direction: row; border-radius: 24px; border: none; padding-left: 20px; padding-right: 20px; color: white; font-weight: bold; background: #272727; cursor: pointer; &:hover { background: #414141; } } .ryd-tooltip.ryd-tooltip-new-design { height: 0px !important; width: 0px !important; } @media only screen and (max-width: 1200px) { #top-level-buttons-computed > segmented-like-dislike-button-view-model > yt-smartimation > div { flex-direction: column; } #top-level-buttons-computed > segmented-like-dislike-button-view-model > yt-smartimation > div > button { padding: 10.5px 0px; } } }` ); })();