Discord Catbox Uploader

adds a button to upload files to catbox.moe, output gets copied to your clipboard

目前為 2024-10-20 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Discord Catbox Uploader
  3. // @namespace https://tampermonkey.net/
  4. // @version 1.5
  5. // @description adds a button to upload files to catbox.moe, output gets copied to your clipboard
  6. // @author OasisVee
  7. // @match https://*.discord.com/*
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM_setClipboard
  10. // @grant GM_addStyle
  11. // @grant GM_getValue
  12. // @grant GM_setValue
  13. // @connect catbox.moe
  14. // @icon https://www.google.com/s2/favicons?sz=64&domain=catbox.moe
  15. // @license MIT
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. 'use strict';
  20.  
  21. const STYLES = `
  22. .catbox-tooltip {
  23. position: absolute;
  24. background-color: #202225;
  25. color: #dcddde;
  26. padding: 8px 12px;
  27. border-radius: 5px;
  28. font-size: 14px;
  29. font-weight: 500;
  30. pointer-events: none;
  31. opacity: 0;
  32. transition: opacity 0.1s ease-in-out;
  33. z-index: 9999;
  34. top: -30px;
  35. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  36. white-space: nowrap;
  37. border: 1px solid #36393F;
  38. }
  39. .catbox-tooltip::before {
  40. content: '';
  41. position: absolute;
  42. width: 0;
  43. height: 0;
  44. border: 8px solid transparent;
  45. border-top-color: #202225;
  46. bottom: -16px;
  47. left: 50%;
  48. transform: translateX(-50%);
  49. }
  50. #catbox-settings {
  51. position: fixed;
  52. top: 50%;
  53. left: 50%;
  54. transform: translate(-50%, -50%);
  55. background-color: #36393f;
  56. padding: 20px;
  57. border-radius: 5px;
  58. z-index: 10000;
  59. display: none;
  60. }
  61. #catbox-settings input {
  62. width: 100%;
  63. margin-bottom: 10px;
  64. padding: 5px;
  65. background-color: #40444b;
  66. border: none;
  67. color: #dcddde;
  68. }
  69. #catbox-settings button {
  70. background-color: #5865f2;
  71. color: white;
  72. border: none;
  73. padding: 5px 10px;
  74. border-radius: 3px;
  75. cursor: pointer;
  76. }
  77. `;
  78.  
  79. const CAT_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path d="M12,8L10.67,8.09C9.81,7.07 7.4,4.5 5,4.5C5,4.5 3.03,7.46 4.96,11.41C4.41,12.24 4.07,12.67 4,13.66L2.07,18.37L2.06,18.39C1.61,19.31 2.08,20.68 3,21.13L3.09,21.17C3.42,21.31 3.77,21.35 4.09,21.3C4.39,21.33 4.7,21.27 4.95,21.13L5.36,20.94C6.35,20.44 6.69,20.18 7.12,20.03C7.88,19.83 8.88,19.9 10.01,19.9H14C15.15,19.9 16.15,19.83 16.91,20.03C17.34,20.18 17.66,20.44 18.65,20.94L19.06,21.13C19.3,21.27 19.61,21.33 19.91,21.3C20.23,21.35 20.58,21.31 20.91,21.17L21,21.13C21.92,20.68 22.39,19.31 21.94,18.39L21.93,18.37L20,13.66C19.93,12.67 19.59,12.24 19.04,11.41C20.97,7.46 19,4.5 19,4.5C16.6,4.5 14.19,7.07 13.33,8.09L12,8M9,11A1,1 0 0,1 10,12A1,1 0 0,1 9,13A1,1 0 0,1 8,12A1,1 0 0,1 9,11M15,11A1,1 0 0,1 16,12A1,1 0 0,1 15,13A1,1 0 0,1 14,12A1,1 0 0,1 15,11M11,14H13L12.3,15.39C12.5,16.03 13.06,16.5 13.75,16.5A1.5,1.5 0 0,0 15.25,15H15.75A2,2 0 0,1 13.75,17C13,17 12.35,16.59 12,16V16H12C11.65,16.59 11,17 10.25,17A2,2 0 0,1 8.25,15H8.75A1.5,1.5 0 0,0 10.25,16.5C10.94,16.5 11.5,16.03 11.7,15.39L11,14Z"/></svg>`;
  80.  
  81. const catboxButtonTemplate = document.createElement('button');
  82. catboxButtonTemplate.id = 'catbox-upload-btn';
  83. catboxButtonTemplate.innerHTML = CAT_SVG;
  84. catboxButtonTemplate.setAttribute('data-tooltip', 'Upload to Catbox');
  85.  
  86. const fileInput = document.createElement('input');
  87. fileInput.type = 'file';
  88.  
  89. const tooltipElement = document.createElement('div');
  90. tooltipElement.className = 'catbox-tooltip';
  91.  
  92. const notificationElement = document.createElement('div');
  93. notificationElement.style.cssText = `
  94. position: fixed;
  95. top: 10px;
  96. right: 10px;
  97. padding: 10px 20px;
  98. border-radius: 5px;
  99. color: white;
  100. font-weight: bold;
  101. z-index: 9999;
  102. opacity: 0;
  103. transition: opacity 0.3s ease-in-out;
  104. `;
  105.  
  106. function addCatboxButton() {
  107. const uploadButton = document.querySelector('button.attachButton_f298d4.attachButton_d0696b');
  108. if (uploadButton && !document.getElementById('catbox-upload-btn')) {
  109. const catboxButton = catboxButtonTemplate.cloneNode(true);
  110. catboxButton.className = uploadButton.className;
  111. catboxButton.style.cssText = `
  112. vertical-align: top;
  113. padding: 0px 8px;
  114. height: 0px;
  115. line-height: 0px;
  116. top: -20px;
  117. margin-left: 23px;
  118. position: relative;
  119. transform: translateX(0px);
  120. color: white;
  121. opacity: 80%;
  122. display: flex;
  123. align-items: center;
  124. justify-content: center;
  125. `;
  126. catboxButton.addEventListener('click', handleCatboxUpload);
  127. catboxButton.addEventListener('mouseenter', showTooltip);
  128. catboxButton.addEventListener('mouseleave', hideTooltip);
  129. catboxButton.addEventListener('contextmenu', toggleSettings);
  130. uploadButton.parentNode.insertBefore(catboxButton, uploadButton.nextSibling);
  131. return true;
  132. }
  133. return false;
  134. }
  135.  
  136. function showTooltip(event) {
  137. const button = event.currentTarget;
  138. tooltipElement.textContent = button.getAttribute('data-tooltip');
  139. document.body.appendChild(tooltipElement);
  140. const buttonRect = button.getBoundingClientRect();
  141. const tooltipRect = tooltipElement.getBoundingClientRect();
  142. tooltipElement.style.left = `${buttonRect.left + (buttonRect.width / 2) - (tooltipRect.width / 2)}px`;
  143. tooltipElement.style.top = `${buttonRect.top - tooltipRect.height - 15}px`;
  144. requestAnimationFrame(() => tooltipElement.style.opacity = '1');
  145. }
  146.  
  147. function hideTooltip() {
  148. tooltipElement.style.opacity = '0';
  149. setTimeout(() => {
  150. if (tooltipElement.parentNode) {
  151. tooltipElement.parentNode.removeChild(tooltipElement);
  152. }
  153. }, 100);
  154. }
  155.  
  156. function handleCatboxUpload(event) {
  157. event.preventDefault();
  158. event.stopPropagation();
  159. fileInput.click();
  160. }
  161.  
  162. function uploadFile(file) {
  163. const formData = new FormData();
  164. formData.append('reqtype', 'fileupload');
  165. formData.append('fileToUpload', file);
  166.  
  167. const userHash = GM_getValue('catboxUserHash', '');
  168. if (userHash) {
  169. formData.append('userhash', userHash);
  170. }
  171.  
  172. GM_xmlhttpRequest({
  173. method: 'POST',
  174. url: 'https://catbox.moe/user/api.php',
  175. data: formData,
  176. onload: handleUploadResponse,
  177. onerror: () => showNotification('Error uploading to Catbox.moe. Please try again.', 'error')
  178. });
  179. }
  180.  
  181. function handleUploadResponse(response) {
  182. if (response.status === 200) {
  183. GM_setClipboard(response.responseText);
  184. showNotification('File uploaded and link copied to clipboard!', 'success');
  185. } else {
  186. showNotification('Error uploading to Catbox.moe. Please try again.', 'error');
  187. }
  188. }
  189.  
  190. function showNotification(message, type) {
  191. notificationElement.textContent = message;
  192. notificationElement.style.backgroundColor = type === 'error' ? '#ff4444' : '#00C851';
  193. document.body.appendChild(notificationElement);
  194. requestAnimationFrame(() => {
  195. notificationElement.style.opacity = '1';
  196. setTimeout(() => {
  197. notificationElement.style.opacity = '0';
  198. setTimeout(() => document.body.removeChild(notificationElement), 300);
  199. }, 3000);
  200. });
  201. }
  202.  
  203. function toggleSettings(event) {
  204. event.preventDefault();
  205. const existingSettings = document.getElementById('catbox-settings');
  206. if (existingSettings) {
  207. existingSettings.remove();
  208. return;
  209. }
  210.  
  211. const settingsDiv = document.createElement('div');
  212. settingsDiv.id = 'catbox-settings';
  213. settingsDiv.innerHTML = `
  214. <input type="text" id="catbox-user-hash" placeholder="Enter Catbox User Hash">
  215. <button id="save-catbox-settings">Save</button>
  216. `;
  217. document.body.appendChild(settingsDiv);
  218. const userHashInput = document.getElementById('catbox-user-hash');
  219. userHashInput.value = GM_getValue('catboxUserHash', '');
  220. document.getElementById('save-catbox-settings').addEventListener('click', saveSettings);
  221. settingsDiv.style.display = 'block';
  222.  
  223. // Close settings when clicking outside
  224. document.addEventListener('click', closeSettingsOutside);
  225. }
  226.  
  227. function closeSettingsOutside(event) {
  228. const settingsDiv = document.getElementById('catbox-settings');
  229. if (settingsDiv && !settingsDiv.contains(event.target) && event.target.id !== 'catbox-upload-btn') {
  230. settingsDiv.remove();
  231. document.removeEventListener('click', closeSettingsOutside);
  232. }
  233. }
  234.  
  235. function saveSettings() {
  236. const userHash = document.getElementById('catbox-user-hash').value;
  237. GM_setValue('catboxUserHash', userHash);
  238. document.getElementById('catbox-settings').remove();
  239. showNotification('Catbox settings saved!', 'success');
  240. document.removeEventListener('click', closeSettingsOutside);
  241. }
  242.  
  243. function init() {
  244. GM_addStyle(STYLES);
  245. const observer = new MutationObserver((mutations) => {
  246. if (mutations.some(mutation => mutation.addedNodes.length > 0)) {
  247. addCatboxButton();
  248. }
  249. });
  250. observer.observe(document.body, { childList: true, subtree: true });
  251. fileInput.addEventListener('change', event => {
  252. const file = event.target.files[0];
  253. if (file) uploadFile(file);
  254. });
  255. addCatboxButton();
  256. }
  257.  
  258. init();
  259. })();