Catbox File Uploader with Hidden Circular Button, Minimize Support, Drag-and-Drop

A button to upload files to Catbox, hidden until clicked, with minimize support, drag-and-drop functionality, and a copy URL button.

  1. // ==UserScript==
  2. // @name Catbox File Uploader with Hidden Circular Button, Minimize Support, Drag-and-Drop
  3. // @namespace https://catbox.moe/
  4. // @version 1.2
  5. // @description A button to upload files to Catbox, hidden until clicked, with minimize support, drag-and-drop functionality, and a copy URL button.
  6. // @author heapsofjoy
  7. // @match *://*/*
  8. // @icon https://catbox.moe/pictures/favicon.ico
  9. // @grant GM_addStyle
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. // Add a hidden button at the bottom of the page
  16. const uploadButton = document.createElement('div');
  17. uploadButton.id = 'uploadButton';
  18. uploadButton.innerHTML = '⬆'; // Up arrow to indicate sliding up
  19. document.body.appendChild(uploadButton);
  20.  
  21. // Create an invisible file input element
  22. const fileInput = document.createElement('input');
  23. fileInput.type = 'file';
  24. fileInput.style.display = 'none';
  25. document.body.appendChild(fileInput);
  26.  
  27. // Create a text box to display the URL after uploading
  28. const urlTextBox = document.createElement('input');
  29. urlTextBox.type = 'text';
  30. urlTextBox.id = 'fileUrl';
  31. urlTextBox.placeholder = 'URL will appear here';
  32. urlTextBox.readOnly = true;
  33. urlTextBox.style.display = 'none';
  34. document.body.appendChild(urlTextBox);
  35.  
  36. // Create a copy button for the URL
  37. const copyButton = document.createElement('div');
  38. copyButton.id = 'copyButton';
  39. copyButton.innerHTML = '📋'; // Clipboard icon
  40. copyButton.style.display = 'none';
  41. document.body.appendChild(copyButton);
  42.  
  43. // Create a drop zone area for drag-and-drop
  44. const dropZone = document.createElement('div');
  45. dropZone.id = 'dropZone';
  46. dropZone.innerText = 'Drag & Drop File Here';
  47. dropZone.style.display = 'none';
  48. document.body.appendChild(dropZone);
  49.  
  50. // Minimize button
  51. const minimizeButton = document.createElement('div');
  52. minimizeButton.id = 'minimizeButton';
  53. minimizeButton.innerHTML = '—'; // Minimize symbol
  54. minimizeButton.style.display = 'none';
  55. document.body.appendChild(minimizeButton);
  56.  
  57. // Styling for the circular button, text box, drop zone, minimize button, and copy button
  58. GM_addStyle(`
  59. #uploadButton {
  60. position: fixed;
  61. bottom: 0;
  62. left: 20px;
  63. width: 50px;
  64. height: 50px;
  65. background-color: #333; /* Dark grey */
  66. color: white;
  67. border: none;
  68. border-radius: 50%;
  69. cursor: pointer;
  70. font-family: Arial, sans-serif;
  71. font-size: 24px;
  72. text-align: center;
  73. line-height: 50px;
  74. box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
  75. transition: bottom 0.4s ease;
  76. z-index: 10000; /* Ensure it's on top */
  77. }
  78. #uploadButton.minimized {
  79. bottom: 0;
  80. width: 50px;
  81. height: 10px;
  82. border-radius: 50px 50px 0 0;
  83. font-size: 10px;
  84. line-height: 10px;
  85. }
  86. #minimizeButton {
  87. position: fixed;
  88. bottom: 0;
  89. left: 80px;
  90. width: 30px;
  91. height: 30px;
  92. background-color: #333;
  93. color: white;
  94. border: none;
  95. border-radius: 50%;
  96. cursor: pointer;
  97. font-family: Arial, sans-serif;
  98. font-size: 16px;
  99. text-align: center;
  100. line-height: 30px;
  101. box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
  102. z-index: 10000;
  103. }
  104. #fileUrl {
  105. position: fixed;
  106. bottom: 70px;
  107. left: 20px;
  108. width: 270px; /* Adjusted to accommodate the copy button */
  109. padding: 10px;
  110. font-size: 14px;
  111. border: none;
  112. border-radius: 5px;
  113. background-color: #333;
  114. color: white;
  115. box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
  116. display: block;
  117. z-index: 10000;
  118. }
  119. #copyButton {
  120. position: fixed;
  121. bottom: 70px;
  122. left: 295px; /* Position next to URL text box */
  123. width: 30px;
  124. height: 30px;
  125. background-color: #333;
  126. color: white;
  127. border: none;
  128. border-radius: 5px;
  129. cursor: pointer;
  130. font-family: Arial, sans-serif;
  131. font-size: 16px;
  132. text-align: center;
  133. line-height: 30px;
  134. box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
  135. z-index: 10000;
  136. }
  137. #dropZone {
  138. position: fixed;
  139. bottom: 120px;
  140. left: 20px;
  141. width: 300px;
  142. height: 150px;
  143. border: 2px dashed #aaa;
  144. background-color: #444;
  145. color: white;
  146. text-align: center;
  147. line-height: 150px;
  148. font-family: Arial, sans-serif;
  149. font-size: 14px;
  150. border-radius: 5px;
  151. z-index: 10000;
  152. }
  153. #dropZone.dragover {
  154. border-color: #fff;
  155. background-color: #555;
  156. }
  157. `);
  158.  
  159. // Start minimized
  160. let isMinimized = true;
  161. uploadButton.classList.add('minimized');
  162.  
  163. // Show the button when clicked
  164. uploadButton.addEventListener('click', () => {
  165. if (isMinimized) {
  166. // Show the full button
  167. uploadButton.classList.remove('minimized');
  168. isMinimized = false;
  169. minimizeButton.style.display = 'block';
  170. } else {
  171. // Open file explorer on single click when button is expanded
  172. fileInput.click();
  173. }
  174. });
  175.  
  176. // Minimize the button when clicking the minimize button
  177. minimizeButton.addEventListener('click', () => {
  178. uploadButton.classList.add('minimized');
  179. isMinimized = true;
  180. minimizeButton.style.display = 'none';
  181. // Hide URL text box and copy button when minimizing
  182. urlTextBox.style.display = 'none';
  183. copyButton.style.display = 'none';
  184. });
  185.  
  186. // Listen for file selection from the file input
  187. fileInput.addEventListener('change', () => {
  188. const file = fileInput.files[0];
  189. if (file) {
  190. uploadFile(file);
  191. }
  192. });
  193.  
  194. let dragCounter = 0; // To keep track of drag events
  195.  
  196. // Disable drag-and-drop if minimized
  197. document.addEventListener('dragenter', (e) => {
  198. if (!isMinimized) {
  199. e.preventDefault();
  200. dragCounter++; // Increment the drag counter
  201. dropZone.style.display = 'block';
  202. }
  203. });
  204.  
  205. // Handle drag over events to allow dropping
  206. document.addEventListener('dragover', (e) => {
  207. if (!isMinimized) {
  208. e.preventDefault();
  209. dropZone.classList.add('dragover');
  210. }
  211. });
  212.  
  213. // Handle drag leave to hide the drop zone only when all drags leave
  214. document.addEventListener('dragleave', (e) => {
  215. e.preventDefault();
  216. dragCounter--; // Decrement the drag counter
  217. if (dragCounter === 0) {
  218. dropZone.classList.remove('dragover');
  219. dropZone.style.display = 'none';
  220. }
  221. });
  222.  
  223. // Handle drop events to upload the file
  224. dropZone.addEventListener('drop', (e) => {
  225. if (!isMinimized) {
  226. e.preventDefault();
  227. dragCounter = 0; // Reset the counter when a file is dropped
  228. dropZone.classList.remove('dragover');
  229. dropZone.style.display = 'none';
  230. const file = e.dataTransfer.files[0];
  231. if (file) {
  232. uploadFile(file);
  233. }
  234. }
  235. });
  236.  
  237. // Upload file and fetch URL
  238. function uploadFile(file) {
  239. const formData = new FormData();
  240. formData.append('reqtype', 'fileupload');
  241. formData.append('time', '1h');
  242. formData.append('fileToUpload', file);
  243.  
  244. fetch('https://litterbox.catbox.moe/resources/internals/api.php', {
  245. method: 'POST',
  246. body: formData
  247. })
  248. .then(response => response.text())
  249. .then(url => {
  250. // Display the URL in the text box and show copy button
  251. urlTextBox.style.display = 'block';
  252. urlTextBox.value = url;
  253. copyButton.style.display = 'block';
  254. })
  255. .catch(error => {
  256. urlTextBox.value = 'Upload failed!';
  257. console.error('Error:', error);
  258. });
  259. }
  260.  
  261. // Copy URL to clipboard when copy button is clicked
  262. copyButton.addEventListener('click', () => {
  263. navigator.clipboard.writeText(urlTextBox.value).then(() => {
  264. copyButton.innerHTML = '✔'; // Change to a check mark to indicate success
  265. setTimeout(() => {
  266. copyButton.innerHTML = '📋'; // Revert back to clipboard icon
  267. }, 1000);
  268. }).catch(error => {
  269. console.error('Copy failed:', error);
  270. });
  271. });
  272. })();