您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
让 YouTube™ 直播聊天室的贴图可以被复制
// ==UserScript== // @name YT Live Chat Emoji Copy Tool // @name:zh YT 直播聊天室貼圖複製工具 // @name:zh-TW YT 直播聊天室貼圖複製工具 // @name:zh-CN YT 直播聊天室贴图复制工具 // @namespace https://github.com/kevin823lin // @version 0.3 // @description Make YouTube™ Live Chat's emoji can be copied. // @description:zh 讓 YouTube™ 直播聊天室的貼圖可以被複製 // @description:zh-TW 讓 YouTube™ 直播聊天室的貼圖可以被複製 // @description:zh-CN 让 YouTube™ 直播聊天室的贴图可以被复制 // @author kevin823lin // @match https://www.youtube.com/live_chat* // @match https://www.youtube.com/live_chat_replay* // @match https://studio.youtube.com/live_chat* // @match https://studio.youtube.com/live_chat_replay* // @icon https://www.google.com/s2/favicons?domain=youtube.com // @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js // @grant none // @date 2025-01-11 // @license MIT // ==/UserScript== /*! * YT Live Chat Emoji Copy Tool v0.3 * https://github.com/kevin823lin/yt-live-chat-emoji-copy-tool * * Includes Lodash v4.17.21 * * Copyright (c) 2025 kevin823lin * Released under the MIT license * https://opensource.org/licenses/MIT * * Date: 2025-01-11 */ (function() { 'use strict'; // Your code here... const TYPES = { CHAT: Symbol("Chat"), INPUT: Symbol("Input"), PICKER: Symbol("Picker"), }; const YOUTUBE_CHANNEL_ID_REGEX = /^UCkszU2WH9gy1mb0dV-11UJg\//; const CHAT_EMOJI_SELECTOR = 'img.emoji.yt-live-chat-text-message-renderer[shared-tooltip-text][data-emoji-id]:not(.copyable)'; const INPUT_FIELD_SELECTOR = 'yt-live-chat-text-input-field-renderer > #input'; const EMOJI_PICKER_SELECTOR = 'div.yt-emoji-picker-renderer#categories'; const VERSION = (typeof GM_info !== 'undefined') ? GM_info?.script?.version : (typeof chrome !== 'undefined') ? chrome?.runtime?.getManifest()?.version : ''; /** * Check if the emoji is already copyable. */ function isEmojiCopyable(emoji) { return emoji.classList.contains('copyable'); } /** * Retrieve the emoji's ID. */ function getEmojiId(emoji) { return emoji.dataset.emojiId || emoji.id; } /** * Determine if the emoji is a YouTube-specific emoji. */ function isYoutubeEmoji(emoji) { const id = getEmojiId(emoji); return !id || YOUTUBE_CHANNEL_ID_REGEX.test(id); } /** * Update the emoji's alt attribute with colon format. */ function updateEmojiAltWithColon(emoji, compareText = null) { if (compareText && !compareText.match(emoji.alt)) return; emoji.alt = `:${isYoutubeEmoji(emoji) ? '' : '_'}${emoji.alt}:`; } /** * Process the emoji based on its type. */ function processEmoji(emoji, type) { if (isEmojiCopyable(emoji)) return; emoji.classList.add('copyable'); let compareText = null; switch (type) { case TYPES.CHAT: if (!document.contains(emoji)) return; compareText = emoji.getAttribute('shared-tooltip-text'); break; case TYPES.INPUT: if (!getEmojiId(emoji)) return; break; case TYPES.PICKER: compareText = emoji.getAttribute('aria-label'); break; default: console.warn(`Unknown emoji type: ${type}`); return; } updateEmojiAltWithColon(emoji, compareText); } /** * Update all emojis in the selected range. */ function updateSelectedRangeEmojis() { try { const selection = window.getSelection(); if (!selection.rangeCount) return; const range = selection.getRangeAt(0); const fragment = range.cloneContents(); const selectedEmojis = fragment.querySelectorAll(CHAT_EMOJI_SELECTOR); selectedEmojis.forEach(clonedEmoji => { const originalEmoji = range.commonAncestorContainer.querySelector(`img.emoji#${clonedEmoji.id}`); if (originalEmoji) { processEmoji(originalEmoji, TYPES.CHAT); } }); } catch (error) { console.error(`Error in updateSelectedRangeEmojis: ${error}`); } } /** * Update all emojis inside the input field. */ function updateInputFieldEmojis(inputField) { const inputEmojis = inputField?.getElementsByClassName('yt-live-chat-text-input-field-renderer') || []; Array.from(inputEmojis).forEach((node) => processEmoji(node, TYPES.INPUT)); } /** * Update emojis in the emoji picker based on mutations. */ function updateEmojiPickerEmojis(mutations) { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'IMG') { processEmoji(node, TYPES.PICKER); } }); }); } /** * Initialize observers and event listeners on page load. */ function initializeObservers() { const inputField = document.querySelector(INPUT_FIELD_SELECTOR); const emojiPicker = document.querySelector(EMOJI_PICKER_SELECTOR); const selectionchangeCallback = _.debounce(updateSelectedRangeEmojis, 200); const observeInputFieldCallback = _.debounce(() => { if (inputField) updateInputFieldEmojis(inputField); }, 200); const observeEmojiPickerCallback = updateEmojiPickerEmojis; const inputFieldObserver = new MutationObserver(observeInputFieldCallback); const emojiPickerObserver = new MutationObserver(observeEmojiPickerCallback); if (inputField) inputFieldObserver.observe(inputField, { childList: true, subtree: true }); if (emojiPicker) emojiPickerObserver.observe(emojiPicker, { childList: true, subtree: true }); document.addEventListener('selectionchange', selectionchangeCallback); } if (/^\/live_chat/.test(window.location.pathname)) { initializeObservers(); console.log(`[YT Live Chat Emoji Copy Tool${VERSION ? ` v${VERSION}` : ''}]`); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址