Greasyfork Code Copier

Add a copy button for script code.

  1. // ==UserScript==
  2. // @name Greasyfork Code Copier
  3. // @description Add a copy button for script code.
  4. // @icon https://gf.qytechs.cn/vite/assets/blacklogo96-CxYTSM_T.png
  5. // @version 1.5
  6. // @author afkarxyz
  7. // @namespace https://github.com/afkarxyz/userscripts/
  8. // @supportURL https://github.com/afkarxyz/userscripts/issues
  9. // @license MIT
  10. // @match https://gf.qytechs.cn/*/scripts/*
  11. // @match https://sleazyfork.org/*/scripts/*
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM_setClipboard
  14. // @run-at document-end
  15. // ==/UserScript==
  16.  
  17. (function() {
  18. 'use strict';
  19. function createSVGIcon(path) {
  20. const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  21. svg.setAttribute("viewBox", "0 0 384 512");
  22. svg.setAttribute("width", "16");
  23. svg.setAttribute("height", "16");
  24. const iconPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
  25. iconPath.setAttribute("d", path);
  26. iconPath.setAttribute("fill", "currentColor");
  27. svg.appendChild(iconPath);
  28. return svg;
  29. }
  30.  
  31. function createCopyButton(scriptUrl) {
  32. const initialIconPath = 'M145.5 68c5.3-20.7 24.1-36 46.5-36s41.2 15.3 46.5 36c1.8 7.1 8.2 12 15.5 12l18 0c8.8 0 16 7.2 16 16l0 32-96 0-96 0 0-32c0-8.8 7.2-16 16-16l18 0c7.3 0 13.7-4.9 15.5-12zM192 0c-32.8 0-61 19.8-73.3 48L112 48C91.1 48 73.3 61.4 66.7 80L64 80C28.7 80 0 108.7 0 144L0 448c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-304c0-35.3-28.7-64-64-64l-2.7 0c-6.6-18.6-24.4-32-45.3-32l-6.7 0C253 19.8 224.8 0 192 0zM320 112c17.7 0 32 14.3 32 32l0 304c0 17.7-14.3 32-32 32L64 480c-17.7 0-32-14.3-32-32l0-304c0-17.7 14.3-32 32-32l0 16c0 17.7 14.3 32 32 32l96 0 96 0c17.7 0 32-14.3 32-32l0-16zM208 80a16 16 0 1 0 -32 0 16 16 0 1 0 32 0zM136 272a24 24 0 1 0 -48 0 24 24 0 1 0 48 0zm40-16c-8.8 0-16 7.2-16 16s7.2 16 16 16l96 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-96 0zm0 96c-8.8 0-16 7.2-16 16s7.2 16 16 16l96 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-96 0zm-64 40a24 24 0 1 0 0-48 24 24 0 1 0 0 48z';
  33. const alternateIconPath = 'M145.5 68c5.3-20.7 24.1-36 46.5-36s41.2 15.3 46.5 36c1.8 7.1 8.2 12 15.5 12l18 0c8.8 0 16 7.2 16 16l0 32-96 0-96 0 0-32c0-8.8 7.2-16 16-16l18 0c7.3 0 13.7-4.9 15.5-12zM192 0c-32.8 0-61 19.8-73.3 48L112 48C91.1 48 73.3 61.4 66.7 80L64 80C28.7 80 0 108.7 0 144L0 448c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-304c0-35.3-28.7-64-64-64l-2.7 0c-6.6-18.6-24.4-32-45.3-32l-6.7 0C253 19.8 224.8 0 192 0zM320 112c17.7 0 32 14.3 32 32l0 304c0 17.7-14.3 32-32 32L64 480c-17.7 0-32-14.3-32-32l0-304c0-17.7 14.3-32 32-32l0 16c0 17.7 14.3 32 32 32l96 0 96 0c17.7 0 32-14.3 32-32l0-16zM208 80a16 16 0 1 0 -32 0 16 16 0 1 0 32 0zm91.3 171.3c6.2-6.2 6.2-16.4 0-22.6s-16.4-6.2-22.6 0L160 345.4l-52.7-52.7c-6.2-6.2-16.4-6.2-22.6 0s-6.2 16.4 0 22.6l64 64c6.2 6.2 16.4 6.2 22.6 0l128-128z';
  34. const copyButton = document.createElement("a");
  35. copyButton.className = "install-help-link";
  36. copyButton.href = "javascript:void(0)";
  37. copyButton.style.marginLeft = "5px";
  38. copyButton.style.borderRadius = "10%";
  39. const icon = createSVGIcon(initialIconPath);
  40. copyButton.appendChild(icon);
  41. copyButton.addEventListener("click", function(event) {
  42. event.preventDefault();
  43. icon.firstChild.setAttribute("d", alternateIconPath);
  44. GM_xmlhttpRequest({
  45. method: "GET",
  46. url: scriptUrl,
  47. onload: function(response) {
  48. if (response.status === 200) {
  49. GM_setClipboard(response.responseText);
  50. setTimeout(() => {
  51. icon.firstChild.setAttribute("d", initialIconPath);
  52. }, 500);
  53. } else {
  54. setTimeout(() => {
  55. icon.firstChild.setAttribute("d", initialIconPath);
  56. }, 500);
  57. }
  58. },
  59. onerror: function() {
  60. setTimeout(() => {
  61. icon.firstChild.setAttribute("d", initialIconPath);
  62. }, 500);
  63. }
  64. });
  65. });
  66. return copyButton;
  67. }
  68.  
  69. function createLinesIcon() {
  70. const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  71. svg.setAttribute("viewBox", "0 0 640 512");
  72. svg.setAttribute("width", "14");
  73. svg.setAttribute("height", "14");
  74. svg.style.marginRight = "5px";
  75. svg.style.position = "relative";
  76. svg.style.top = "0";
  77. const iconPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
  78. iconPath.setAttribute("d", "M399.1 1.1c-12.7-3.9-26.1 3.1-30 15.8l-144 464c-3.9 12.7 3.1 26.1 15.8 30s26.1-3.1 30-15.8l144-464c3.9-12.7-3.1-26.1-15.8-30zm71.4 118.5c-9.1 9.7-8.6 24.9 1.1 33.9L580.9 256 471.6 358.5c-9.7 9.1-10.2 24.3-1.1 33.9s24.3 10.2 33.9 1.1l128-120c4.8-4.5 7.6-10.9 7.6-17.5s-2.7-13-7.6-17.5l-128-120c-9.7-9.1-24.9-8.6-33.9 1.1zm-301 0c-9.1-9.7-24.3-10.2-33.9-1.1l-128 120C2.7 243 0 249.4 0 256s2.7 13 7.6 17.5l128 120c9.7 9.1 24.9 8.6 33.9-1.1s8.6-24.9-1.1-33.9L59.1 256 168.4 153.5c9.7-9.1 10.2-24.3 1.1-33.9z");
  79. iconPath.setAttribute("fill", "currentColor");
  80. svg.appendChild(iconPath);
  81. return svg;
  82. }
  83.  
  84. function countLines(scriptUrl) {
  85. GM_xmlhttpRequest({
  86. method: "GET",
  87. url: scriptUrl,
  88. onload: function(response) {
  89. if (response.status === 200) {
  90. const totalLines = response.responseText.split('\n').length;
  91. const correctedLines = Math.max(0, totalLines - 2);
  92. displayLineCount(correctedLines);
  93. }
  94. }
  95. });
  96. }
  97.  
  98. function formatLineCount(count) {
  99. return count >= 1000 ? count.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : count.toString();
  100. }
  101.  
  102. function displayLineCount(count) {
  103. const wrapLinesLabel = document.querySelector('label[for="wrap-lines"]');
  104. if (wrapLinesLabel) {
  105. let lineCountContainer = document.getElementById('line-count-display');
  106. if (!lineCountContainer) {
  107. lineCountContainer = document.createElement('div');
  108. lineCountContainer.id = 'line-count-display';
  109. lineCountContainer.style.fontSize = '13px';
  110. lineCountContainer.style.display = 'flex';
  111. lineCountContainer.style.alignItems = 'center';
  112. const containerDiv = document.createElement('div');
  113. containerDiv.style.display = 'flex';
  114. containerDiv.style.justifyContent = 'space-between';
  115. containerDiv.style.alignItems = 'center';
  116. containerDiv.style.width = '100%';
  117. const parentDiv = wrapLinesLabel.parentNode;
  118. const wrapLinesDiv = document.createElement('div');
  119. wrapLinesDiv.appendChild(document.getElementById('wrap-lines'));
  120. wrapLinesDiv.appendChild(wrapLinesLabel);
  121. containerDiv.appendChild(wrapLinesDiv);
  122. containerDiv.appendChild(lineCountContainer);
  123. parentDiv.replaceWith(containerDiv);
  124. }
  125. const linesIcon = createLinesIcon();
  126. lineCountContainer.innerHTML = '';
  127. lineCountContainer.appendChild(linesIcon);
  128. const textSpan = document.createElement('span');
  129. textSpan.style.fontSize = '13px';
  130. textSpan.style.position = 'relative';
  131. textSpan.textContent = formatLineCount(count);
  132. lineCountContainer.appendChild(textSpan);
  133. }
  134. }
  135.  
  136. function initialize() {
  137. const installButton = document.querySelector(".install-link");
  138. if (installButton) {
  139. const scriptUrl = installButton.href;
  140. const helpLink = document.querySelector(".install-help-link");
  141. if (helpLink) {
  142. const copyButton = createCopyButton(scriptUrl);
  143. helpLink.parentNode.insertBefore(copyButton, helpLink.nextSibling);
  144. countLines(scriptUrl);
  145. }
  146. }
  147. }
  148.  
  149. if (document.readyState === "loading") {
  150. document.addEventListener("DOMContentLoaded", initialize);
  151. } else {
  152. initialize();
  153. }
  154. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址