Greasy Fork 还支持 简体中文。

Add Copy Button to Chat Messages on 360's bot.n.cn

Adds a "Copy" button to chat message elements to easily copy their content.

目前為 2025-01-27 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Add Copy Button to Chat Messages on 360's bot.n.cn
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.0.1
  5. // @description Adds a "Copy" button to chat message elements to easily copy their content.
  6. // @author aspen138
  7. // @match *://bot.n.cn/*
  8. // @grant none
  9. // @run-at document-end
  10. // @icon https://p1.ssl.qhimg.com//t11098f6bcd26caa77d8aa4d2fb.png
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. // Update these if class names change
  19. const MESSAGE_CONTENT_CLASS = 'UserMessage-module__container--cAvvK';
  20. const CHAT_MESSAGE_CONTENT_CLASS = 'ChatMessage-module__content--MYneF';
  21. const NEW_MESSAGE_SELECTOR = '.max-w-\\[80\\%\\].rounded-\\[16px\\].px-\\[16px\\].py-\\[10px\\].text-white.text-\\[15px\\].leading-\\[22px\\].whitespace-pre-line.break-all.overflow-x-hidden';
  22.  
  23. function createCopyButton() {
  24. const button = document.createElement('button');
  25. button.innerText = 'Copy';
  26. button.classList.add('copy-button');
  27. button.style.position = 'sticky';
  28. button.style.top = '10px';
  29. button.style.right = '10px';
  30. button.style.backgroundColor = '#4CAF50';
  31. button.style.color = '#fff';
  32. button.style.border = 'none';
  33. button.style.borderRadius = '4px';
  34. button.style.padding = '5px 10px';
  35. button.style.cursor = 'pointer';
  36. button.style.fontSize = '0.9em';
  37. button.style.zIndex = '1000';
  38. button.style.boxShadow = '0 2px 6px rgba(0,0,0,0.2)';
  39. button.style.marginLeft = 'auto';
  40. button.style.float = 'right';
  41. button.style.display = 'inline-block';
  42.  
  43. button.addEventListener('mouseenter', () => {
  44. button.style.backgroundColor = '#45a049';
  45. });
  46. button.addEventListener('mouseleave', () => {
  47. button.style.backgroundColor = '#4CAF50';
  48. });
  49.  
  50. return button;
  51. }
  52.  
  53. function addCopyButton(element) {
  54. if (element.querySelector('.copy-button')) return;
  55.  
  56. const isNewMessage = element.matches(NEW_MESSAGE_SELECTOR);
  57. const contentElement = isNewMessage ? element : element.querySelector(`.${MESSAGE_CONTENT_CLASS}`);
  58.  
  59. if (!contentElement) return;
  60.  
  61. element.style.position = 'relative';
  62. element.style.display = 'block';
  63.  
  64. const copyButton = createCopyButton();
  65.  
  66. copyButton.addEventListener('click', () => {
  67. const textToCopy = contentElement.innerText.trim().replace(/Copy(?=[^Copy]*$)/, "");
  68. navigator.clipboard.writeText(textToCopy).then(() => {
  69. copyButton.innerText = 'Copied!';
  70. copyButton.style.backgroundColor = '#388E3C';
  71. setTimeout(() => {
  72. copyButton.innerText = 'Copy';
  73. copyButton.style.backgroundColor = '#4CAF50';
  74. }, 2000);
  75. }).catch(err => {
  76. console.error('Failed to copy text: ', err);
  77. });
  78. });
  79.  
  80. element.appendChild(copyButton);
  81. }
  82.  
  83. function processExistingMessages() {
  84. // Process original chat messages
  85. document.querySelectorAll(`.${CHAT_MESSAGE_CONTENT_CLASS}`).forEach(addCopyButton);
  86. // Process new gradient messages
  87. document.querySelectorAll(NEW_MESSAGE_SELECTOR).forEach(addCopyButton);
  88. }
  89.  
  90. function observeNewMessages() {
  91. const observer = new MutationObserver((mutations) => {
  92. for (const mutation of mutations) {
  93. if (mutation.type === 'childList') {
  94. mutation.addedNodes.forEach(node => {
  95. if (node.nodeType === Node.ELEMENT_NODE) {
  96. // Check for both message types
  97. if (node.matches(`.${CHAT_MESSAGE_CONTENT_CLASS}, ${NEW_MESSAGE_SELECTOR}`)) {
  98. addCopyButton(node);
  99. }
  100. // Check nested elements
  101. node.querySelectorAll(`.${CHAT_MESSAGE_CONTENT_CLASS}, ${NEW_MESSAGE_SELECTOR}`).forEach(addCopyButton);
  102. }
  103. });
  104. }
  105. }
  106. });
  107.  
  108. observer.observe(document.body, { childList: true, subtree: true });
  109. }
  110.  
  111. function init() {
  112. processExistingMessages();
  113. observeNewMessages();
  114. }
  115.  
  116. if (document.readyState === 'loading') {
  117. document.addEventListener('DOMContentLoaded', init);
  118. } else {
  119. init();
  120. }
  121. })();