Enhanced Catbox File Uploader with Auto-Close Drop Zone and Duration Option

Upload files to Catbox with URL history, customizable duration, minimize support, middle-click to open in new tab, auto-close drop zone if no file is dropped within 3 seconds.

目前为 2024-11-01 提交的版本。查看 最新版本

// ==UserScript==
// @name         Enhanced Catbox File Uploader with Auto-Close Drop Zone and Duration Option
// @namespace    https://catbox.moe/
// @version      1.1
// @description  Upload files to Catbox with URL history, customizable duration, minimize support, middle-click to open in new tab, auto-close drop zone if no file is dropped within 3 seconds.
// @match        *://litterbox.catbox.moe/*
// @match        *://catbox.moe/*
// @match        *://*/*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==
(function() {
    'use strict';

    // Create necessary DOM elements
    const uploadButton = document.createElement('div');
    uploadButton.id = 'uploadButton';
    uploadButton.innerHTML = '⬆';
    document.body.appendChild(uploadButton);

    const fileInput = document.createElement('input');
    fileInput.type = 'file';
    fileInput.style.display = 'none';
    document.body.appendChild(fileInput);

    const urlTextBox = document.createElement('input');
    urlTextBox.type = 'text';
    urlTextBox.id = 'fileUrl';
    urlTextBox.placeholder = 'URL will appear here';
    urlTextBox.readOnly = true;
    urlTextBox.style.display = 'none';
    document.body.appendChild(urlTextBox);

    const copyButton = document.createElement('div');
    copyButton.id = 'copyButton';
    copyButton.innerHTML = '📋';
    copyButton.style.display = 'none';
    document.body.appendChild(copyButton);

    const dropZone = document.createElement('div');
    dropZone.id = 'dropZone';
    dropZone.innerText = 'Drag & Drop File Here';
    dropZone.style.display = 'none';
    document.body.appendChild(dropZone);

    const minimizeButton = document.createElement('div');
    minimizeButton.id = 'minimizeButton';
    minimizeButton.innerHTML = '—';
    minimizeButton.style.display = 'none';
    document.body.appendChild(minimizeButton);

    const historyButton = document.createElement('div');
    historyButton.id = 'historyButton';
    historyButton.innerHTML = '📜';
    historyButton.style.display = 'none';
    document.body.appendChild(historyButton);

    const clearHistoryButton = document.createElement('div');
    clearHistoryButton.id = 'clearHistoryButton';
    clearHistoryButton.innerHTML = '🗑️';
    clearHistoryButton.style.display = 'none';
    document.body.appendChild(clearHistoryButton);

    const historyList = document.createElement('div');
    historyList.id = 'historyList';
    historyList.style.display = 'none';
    document.body.appendChild(historyList);

    const durationButton = document.createElement('div');
    durationButton.id = 'durationButton';
    durationButton.innerHTML = GM_getValue('uploadDuration', '1h');  // Display initial duration
    durationButton.style.display = 'none';
    document.body.appendChild(durationButton);

    const durationMenu = document.createElement('div');
    durationMenu.id = 'durationMenu';
    durationMenu.style.display = 'none';
    durationMenu.innerHTML = `
        <div data-duration="1h">1 hour</div>
        <div data-duration="12h">12 hours</div>
        <div data-duration="24h">24 hours</div>
        <div data-duration="72h">72 hours</div>
    `;
    document.body.appendChild(durationMenu);

    GM_addStyle(`
        #uploadButton, #historyButton, #clearHistoryButton, #minimizeButton, #durationButton {
            position: fixed;
            bottom: 20px;
            width: 50px;
            height: 50px;
            background-color: #333;
            color: white;
            border: none;
            border-radius: 50%;
            cursor: pointer;
            font-family: Arial, sans-serif;
            font-size: 24px;
            text-align: center;
            line-height: 50px;
            box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
            z-index: 10000;
        }
        #uploadButton { left: 20px; }
        #uploadButton.minimized {
            bottom: 0;
            width: 50px;
            height: 10px;
            border-radius: 50px 50px 0 0;
            font-size: 10px;
            line-height: 10px;
        }
        #minimizeButton, #historyButton, #clearHistoryButton, #durationButton {
            width: 40px;
            height: 40px;
            font-size: 20px;
            line-height: 40px;
        }
        #minimizeButton { left: 80px; }
        #historyButton { left: 140px; }
        #clearHistoryButton { left: 200px; }
        #durationButton { left: 260px; }

        #fileUrl, #historyList, #durationMenu {
            position: fixed;
            bottom: 80px;
            left: 20px;
            width: 270px;
            background-color: #333;
            color: white;
            padding: 10px;
            border: none;
            border-radius: 5px;
            font-size: 14px;
            box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
            z-index: 10000;
            overflow-y: auto;
        }
        #fileUrl { display: block; }
        #historyList {
            height: 200px;
            display: none;
        }
        #historyList div {
            margin-bottom: 10px;
        }
        #historyList div span.timestamp {
            display: block;
            color: #aaa;
            font-size: 12px;
            margin-top: 4px;
            border-top: 1px solid #555;
            padding-top: 2px;
        }
        #historyList a {
            color: #66ccff;
            text-decoration: none;
        }
        #copyButton {
            position: fixed;
            bottom: 80px;
            left: 300px;
            width: 30px;
            height: 30px;
            background-color: #333;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-family: Arial, sans-serif;
            font-size: 16px;
            text-align: center;
            line-height: 30px;
            box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2);
            z-index: 10000;
        }
        #dropZone {
            position: fixed;
            bottom: 150px;
            left: 20px;
            width: 300px;
            height: 150px;
            border: 2px dashed #aaa;
            background-color: #444;
            color: white;
            text-align: center;
            line-height: 150px;
            font-family: Arial, sans-serif;
            font-size: 14px;
            border-radius: 5px;
            z-index: 10000;
        }
        #dropZone.dragover {
            border-color: #fff;
            background-color: #555;
        }
        #durationMenu div:hover {
            background-color: #555;
        }
    `);

    let isMinimized = true;
    let uploadDuration = GM_getValue('uploadDuration', '1h');
    uploadButton.classList.add('minimized');

    uploadButton.addEventListener('click', () => {
        if (isMinimized) {
            uploadButton.classList.remove('minimized');
            isMinimized = false;
            minimizeButton.style.display = 'block';
            historyButton.style.display = 'block';
            clearHistoryButton.style.display = 'block';
            durationButton.style.display = 'block';
        } else {
            fileInput.click();
        }
    });

    minimizeButton.addEventListener('click', () => {
        uploadButton.classList.add('minimized');
        isMinimized = true;
        minimizeButton.style.display = 'none';
        urlTextBox.style.display = 'none';
        copyButton.style.display = 'none';
        historyList.style.display = 'none';
        historyButton.style.display = 'none';
        clearHistoryButton.style.display = 'none';
        durationButton.style.display = 'none';
        dropZone.style.display = 'none';
        durationMenu.style.display = 'none';
    });

    durationButton.addEventListener('click', () => {
        durationMenu.style.display = durationMenu.style.display === 'none' ? 'block' : 'none';
    });

    durationMenu.addEventListener('click', (e) => {
        if (e.target.dataset.duration) {
            uploadDuration = e.target.dataset.duration;
            GM_setValue('uploadDuration', uploadDuration);
            durationButton.innerHTML = uploadDuration;
            durationMenu.style.display = 'none';
        }
    });

    fileInput.addEventListener('change', () => {
        const file = fileInput.files[0];
        if (file) uploadFile(file);
    });

    const uploadedUrlsKey = 'globalUploadedUrls';
    const urlLimit = 10;

    let savedUrls = GM_getValue(uploadedUrlsKey, []);

    function updateHistoryList() {
        historyList.innerHTML = savedUrls.map(item => `<div><a href="${item.url}" target="_blank">${item.url}</a><span class="timestamp">${item.timestamp}</span></div>`).join('');
    }

    historyButton.addEventListener('click', () => {
        historyList.style.display = historyList.style.display === 'none' ? 'block' : 'none';
        updateHistoryList();
    });

    clearHistoryButton.addEventListener('click', () => {
        if (confirm("Are you sure you want to clear the URL history? This action cannot be undone.")) {
            savedUrls = [];
            GM_setValue(uploadedUrlsKey, savedUrls);
            updateHistoryList();
        }
    });

    function handleFileDrop(e) {
        e.preventDefault();
        dropZone.classList.remove('dragover');
        const file = e.dataTransfer.files[0];
        if (file) uploadFile(file);
    }

    document.addEventListener('dragover', e => {
        e.preventDefault();
        dropZone.style.display = 'block';
        dropZone.classList.add('dragover');
    });

    document.addEventListener('dragleave', () => dropZone.style.display = 'none');
    dropZone.addEventListener('drop', handleFileDrop);

    async function uploadFile(file) {
        const timestamp = new Date().toLocaleString('en-GB');
        try {
            const formData = new FormData();
            formData.append('reqtype', 'fileupload');
            formData.append('fileToUpload', file);

            const response = await fetch('https://litterbox.catbox.moe/resources/internals/api.php', {
                method: 'POST',
                body: formData
            });

            const url = await response.text();
            const newEntry = { url, timestamp };
            savedUrls.push(newEntry);
            if (savedUrls.length > urlLimit) savedUrls.shift();
            GM_setValue(uploadedUrlsKey, savedUrls);

            urlTextBox.value = url;
            urlTextBox.style.display = 'block';
            copyButton.style.display = 'block';

            updateHistoryList();
        } catch (error) {
            console.error("Upload failed:", error);
        }
    }

    copyButton.addEventListener('click', () => {
        navigator.clipboard.writeText(urlTextBox.value).then(() => alert('Copied to clipboard!'));
    });

})();