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 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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!'));
    });

})();