Greasy Fork

FastPic Upload for RuTracker

Автоматическая загрузка изображений на FastPic при перетаскивании в текстовое поле

目前为 2025-02-18 提交的版本。查看 最新版本

// ==UserScript==
// @name         FastPic Upload for RuTracker
// @name:en      FastPic Upload for RuTracker
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Автоматическая загрузка изображений на FastPic при перетаскивании в текстовое поле
// @description:en  Automatic image uploading to FastPic when dragging and dropping into a text box
// @author       С
// @license MIT
// @match        https://rutracker.org/forum/viewtopic.php?t=*
// @match        https://rutracker.org/forum/posting.php?mode=reply&t=*
// @match        https://rutracker.org/forum/posting.php?mode=editpost&p=*
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function() {
    'use strict';

    const textarea = document.querySelector('#post-textarea');
    if (!textarea) return;

    const style = document.createElement('style');
    style.textContent = `
        .fastpic-upload-progress {
            position: fixed;
            top: 20px;
            right: 20px;
            background: #fff;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            z-index: 9999;
        }
    `;
    document.head.appendChild(style);

    function parseFastPicResponse(responseText) {
        const uploadSettingsRegex = /<UploadSettings[^>]*>([\s\S]*?)<\/UploadSettings>/g;
        const results = [];
        let match;

        while ((match = uploadSettingsRegex.exec(responseText)) !== null) {
            const settingsXml = match[0];

            const status = settingsXml.match(/<status>([^<]+)<\/status>/)?.[1];

            if (status === 'ok') {
                const imagePath = settingsXml.match(/<imagepath>([^<]+)<\/imagepath>/)?.[1];
                const thumbPath = settingsXml.match(/<thumbpath>([^<]+)<\/thumbpath>/)?.[1];
                const viewUrl = settingsXml.match(/<viewurl>([^<]+)<\/viewurl>/)?.[1];
                const sessionUrl = settingsXml.match(/<sessionurl>([^<]+)<\/sessionurl>/)?.[1];

                if (imagePath && thumbPath && viewUrl) {
                    results.push({
                        imagePath,
                        thumbPath,
                        viewUrl,
                        sessionUrl
                    });
                }
            } else {
                const error = settingsXml.match(/<error>([^<]+)<\/error>/)?.[1] || 'Неизвестная ошибка';
                throw new Error(error);
            }
        }

        if (results.length === 0) {
            throw new Error('Не получено информации о загруженных изображениях');
        }

        return results;
    }

    async function uploadImages(files) {
        const formData = new FormData();

        for (let i = 0; i < files.length; i++) {
            formData.append(`file${i + 1}`, files[i]);
        }

        formData.append('uploading', files.length.toString());
        formData.append('submit', 'Загрузить');

        const response = await new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'POST',
                url: 'https://fastpic.org/upload?api=1',
                data: formData,
                onload: (response) => {
                    console.log('FastPic response:', response.responseText);
                    resolve(response);
                },
                onerror: (error) => reject(error)
            });
        });

        return parseFastPicResponse(response.responseText);
    }

    textarea.addEventListener('dragover', (e) => {
        e.preventDefault();
        e.stopPropagation();
        textarea.style.border = '2px dashed #4a90e2';
    });

    textarea.addEventListener('dragleave', (e) => {
        textarea.style.border = '';
    });

    textarea.addEventListener('drop', async (e) => {
        e.preventDefault();
        e.stopPropagation();
        textarea.style.border = '';

        const files = Array.from(e.dataTransfer.files).filter(file => file.type.startsWith('image/'));
        if (files.length === 0) return;

        const progressDiv = document.createElement('div');
        progressDiv.className = 'fastpic-upload-progress';
        document.body.appendChild(progressDiv);

        const cursorPos = textarea.selectionStart;
        let bbCode = '';

        try {
            progressDiv.textContent = `Загрузка ${files.length} изображений...`;

            const images = await uploadImages(files);

            bbCode = images.map(({ thumbPath, viewUrl }) =>
                `[url=${viewUrl}][img]${thumbPath}[/img][/url]`
            ).join(' ');

            const textBefore = textarea.value.substring(0, cursorPos);
            const textAfter = textarea.value.substring(cursorPos);
            textarea.value = textBefore + bbCode + textAfter;

            textarea.selectionStart = textarea.selectionEnd = cursorPos + bbCode.length;

            progressDiv.textContent = `Успешно загружено ${images.length} изображений`;
        } catch (error) {
            console.error('Ошибка при загрузке изображений:', error);
            alert(`Ошибка при загрузке изображений на FastPic: ${error.message}`);
            progressDiv.textContent = 'Ошибка при загрузке изображений';
        } finally {
            setTimeout(() => progressDiv.remove(), 3000);
        }
    });
})();