// ==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 // @downloadURL none // ==/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 = /]*>([\s\S]*?)<\/UploadSettings>/g; const results = []; let match; while ((match = uploadSettingsRegex.exec(responseText)) !== null) { const settingsXml = match[0]; const status = settingsXml.match(/([^<]+)<\/status>/)?.[1]; if (status === 'ok') { const imagePath = settingsXml.match(/([^<]+)<\/imagepath>/)?.[1]; const thumbPath = settingsXml.match(/([^<]+)<\/thumbpath>/)?.[1]; const viewUrl = settingsXml.match(/([^<]+)<\/viewurl>/)?.[1]; const sessionUrl = settingsXml.match(/([^<]+)<\/sessionurl>/)?.[1]; if (imagePath && thumbPath && viewUrl) { results.push({ imagePath, thumbPath, viewUrl, sessionUrl }); } } else { const error = settingsXml.match(/([^<]+)<\/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); } }); })();