您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically dismiss the liked song notification after some seconds
// ==UserScript== // @name Youtube Music auto dismiss liked song notification // @license MIT // @namespace https://github.com/thecodeisLOVE // @homepageURL https://github.com/thecodeisLOVE/ytmusic-auto-dismiss // @version 0.3 // @description Automatically dismiss the liked song notification after some seconds // @author thecodeisLOVE // @icon https://music.youtube.com/favicon.ico // @match https://music.youtube.com/* // @run-at document-end // @grant none // ==/UserScript== const DISMISS_DELAY_LIKED = 1000; const DISMISS_DELAY_LIBRARY = 1000; const DISMISS_DELAY_PLAYLIST = 5000; const DISMISS_DELAY_GENERAL = 5000; const DESTROY_DELAY = 2000; const DESTROY_DELAY_TEXT = 7000; const ENABLE_DEBUG_LOGGING = true; function timeStamp() { const now = new Date(); const pad = (num, size) => String(num).padStart(size, "0"); const hours = pad(now.getHours(), 2); const minutes = pad(now.getMinutes(), 2); const seconds = pad(now.getSeconds(), 2); const milliseconds = pad(now.getMilliseconds(), 3); return `${hours}:${minutes}:${seconds}.${milliseconds}`; } function contextPrint(message) { const messageTime = () => `[${message}] ${timeStamp()} -` const log = function(...args) {console.log(messageTime(), ...args)}; const warn = function(...args) {console.warn(messageTime(), ...args)}; const error = function(...args) {console.error(messageTime(), ...args)}; const info = function(...args) {console.info(messageTime(), ...args)}; var debug = function(...args) {console.debug(messageTime(), ...args)}; if (!ENABLE_DEBUG_LOGGING) { debug = function() {}; } return {log, warn, error, info, debug}; } const {log, warn, error, info, debug} = contextPrint("YT Music auto dismiss"); function observeChildren(element, config, callback) { const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.type === "childList") { callback(Array.from(mutation.addedNodes)); } } }); if (!config) {config = { childList: true, subtree: false };} observer.observe(element, config); return observer; } function observeChildrenWithFilter(element, config, filter, callback) { return observeChildren(element, config, addedNodes => callback(addedNodes.filter(filter) )); } function observeChildrenWithTags(element, config, filterTags, callback) { return observeChildrenWithFilter(element, config, node => node.nodeType === Node.ELEMENT_NODE && filterTags.includes(node.tagName.toLowerCase()), callback ); } function observeAndHandle(element, tags, fun) { observeChildrenWithTags(element, null, tags, nodes => nodes.forEach(node => fun(node))) } function dismissNotification(notification) { const dismissButton = notification.querySelector("#button"); if (!dismissButton) { warn("Dismiss button not found"); return; } debug("Dismissing notification."); const activeElement = document.activeElement; debug("Element in focus", activeElement); dismissButton.click(); if (activeElement && activeElement.focus) { debug("Restoring focus to element", activeElement); activeElement.focus(); } } function destroyNotification(notification) { if (!notification.parentNode) { warn("Notification element already removed"); return; } debug("Destroying notification element."); notification.parentNode.removeChild(notification); } function getDismissDelay(notification) { const textElement = notification.querySelector("#text"); if (!textElement) { warn("Could not find text element."); return; } const textContent = textElement.textContent.toLowerCase() if (textContent === "saved to liked music") { debug("Saved to liked music notification"); return DISMISS_DELAY_LIKED; } else if (textContent == "added to library") { debug("Added to library notification"); return DISMISS_DELAY_LIBRARY; } else if (textContent == "removed from library") { debug("Removed from library notification"); return DISMISS_DELAY_LIBRARY; } else if (textContent.startsWith("saved to")) { debug("Added to playlist notification"); return DISMISS_DELAY_PLAYLIST; } else if (textContent === "this track is already in the playlist") { debug("Already in playlist notification"); return DISMISS_DELAY_PLAYLIST; } else { debug(`Text content (not yet matched): "${textContent}"`); return DISMISS_DELAY_GENERAL; } } function handleActionNotification(notification) { debug("Action notification detected."); setTimeout(() => { dismissNotification(notification); setTimeout(() => destroyNotification(notification), DESTROY_DELAY, notification); }, getDismissDelay(notification)); } function handleTextNotification(notification) { debug("Text notification detected."); setTimeout(() => destroyNotification(notification), DESTROY_DELAY_TEXT); } (function() { "use strict"; debug("Auto dismiss is active."); const popupContainer = document.getElementsByTagName("ytmusic-popup-container").item(0); if (!popupContainer) { warn("Could not find popup container."); return; } const actionNotificationTags = ["ytmusic-notification-action-renderer"]; observeAndHandle(popupContainer, actionNotificationTags, handleActionNotification); const textNotificationTags = ["ytmusic-notification-text-renderer"]; observeAndHandle(popupContainer, textNotificationTags, handleTextNotification); })();