// ==UserScript== // @name Imgbox图片上传助手增强版 // @namespace http://tampermonkey.net/ // @version 0.6 // @description 给 imgbox 添加在线链接上传功能, 支持图片格式转换, 添加直链获取功能 // @author huanfeng // @match *://imgbox.com/* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant unsafeWindow // @grant GM_addStyle // @connect * // @homepage https://github.com/huanfeng/imgbox_upload_helper // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/532206/Imgbox%E5%9B%BE%E7%89%87%E4%B8%8A%E4%BC%A0%E5%8A%A9%E6%89%8B%E5%A2%9E%E5%BC%BA%E7%89%88.user.js // @updateURL https://update.greasyfork.icu/scripts/532206/Imgbox%E5%9B%BE%E7%89%87%E4%B8%8A%E4%BC%A0%E5%8A%A9%E6%89%8B%E5%A2%9E%E5%BC%BA%E7%89%88.meta.js // ==/UserScript== (function() { 'use strict'; // 添加全局样式 GM_addStyle(` /* 浮动通知样式 */ #toast-container { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); z-index: 10000; text-align: center; } /* 导航栏图标样式 */ .helper-icon { display: inline-block; margin-right: 5px; width: 16px; height: 16px; vertical-align: middle; } .toast { background-color: #333; color: white; padding: 10px 15px; border-radius: 4px; margin-bottom: 10px; box-shadow: 0 2px 5px rgba(0,0,0,0.3); display: inline-block; animation: fadeIn 0.3s, fadeOut 0.3s 2.7s; opacity: 0; min-width: 200px; max-width: 400px; } .toast.success { background-color: #4CAF50; border-left: 5px solid #45a049; } .toast.error { background-color: #f44336; border-left: 5px solid #d32f2f; color: white !important; } .toast.info { background-color: #2196F3; border-left: 5px solid #1976D2; } @keyframes fadeIn { from {opacity: 0; transform: translateY(-20px);} to {opacity: 1; transform: translateY(0);} } @keyframes fadeOut { from {opacity: 1; transform: translateY(0);} to {opacity: 0; transform: translateY(-20px);} } /* 导航栏助手按钮样式 */ .nav.pull-right a[title="打开图片上传助手"]:hover { color: #45a049 !important; text-decoration: underline; } #custom-imgbox-container { margin: 20px 0; padding: 15px; border: 1px solid #444; border-radius: 5px; background-color: #222; color: #ddd; display: none; } #custom-imgbox-container h3 { margin: 0 0 15px 0; font-size: 16px; color: #fff; } #custom-imgbox-container textarea { width: 100%; height: 100px; margin-bottom: 15px; padding: 8px; box-sizing: border-box; border: 1px solid #444; border-radius: 4px; background-color: #333; color: #fff; } #custom-imgbox-container button:not(.tab-button) { background-color: #4CAF50; color: white; border: none; padding: 8px 15px; text-align: center; text-decoration: none; display: inline-block; font-size: 14px; margin-right: 10px; margin-bottom: 10px; cursor: pointer; border-radius: 4px; } #custom-imgbox-container button.blue-btn { background-color: #2196F3; } #custom-imgbox-container button.orange-btn { background-color: #ff9800; } #custom-imgbox-container button.red-btn { background-color: #f44336; } #custom-imgbox-container button.gray-btn { background-color: #444; } #imgbox-status { margin-top: 15px; padding: 10px; border-radius: 4px; background-color: #333; display: none; } #imgbox-results, #imgbox-extracted-links { width: 100%; max-height: 200px; overflow-y: auto; margin-bottom: 15px; padding: 8px; box-sizing: border-box; border: 1px solid #444; border-radius: 4px; background-color: #333; } .result-item { margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #444; } .result-item img { max-width: 50px; max-height: 50px; margin-right: 10px; border: 1px solid #555; } .result-item a { color: #4CAF50; text-decoration: none; } .result-item a:hover { text-decoration: underline; } .error { color: #f44336; } .section-title { margin-top: 15px; margin-bottom: 5px; font-weight: bold; color: #fff; } /* 标签页样式 */ .tab-container { width: 100%; margin-bottom: 15px; border-radius: 5px; overflow: hidden; background-color: #222; border: 1px solid #444; } .tab-buttons { display: flex; background-color: #2a2a2a; } .tab-button { padding: 12px 20px; background-color: #2a2a2a; border: none; color: #aaa; cursor: pointer; position: relative; transition: all 0.2s ease; font-weight: bold; flex: 1; text-align: center; border-right: 1px solid #333; border-bottom: 3px solid transparent; } .tab-button:last-child { border-right: none; } .tab-button:hover { color: white; background-color: #333; } .tab-button.active { color: white; background-color: #222; border-bottom: none; } .tab-button.active::after { content: ''; position: absolute; bottom: 0; left: 0; width: 100%; height: 3px; background-color: #4CAF50; } .tab-content { padding: 20px; background-color: #222; display: none; border-radius: 0 0 5px 5px; } .tab-content.active { display: block; } `); // 监听页面加载 window.addEventListener('load', function() { // 检查是否在imgbox网站 if (window.location.hostname.includes('imgbox.com')) { // 初始化脚本 init(); // 检查是否有从其他页面传递过来的图片链接 const imageLinks = GM_getValue('HDB_images', ''); if (imageLinks) { console.log('发现图片链接:', imageLinks); // 清空存储的链接,避免重复使用 GM_setValue('HDB_images', ''); // 延迟一下,确保页面完全加载 setTimeout(() => { // 添加UI并填充链接 addImgboxUI(imageLinks); // 显示界面 document.getElementById('custom-imgbox-container').style.display = 'block'; GM_setValue('uiVisible', true); // 激活上传标签页 activateTab('upload-tab'); }, 1000); } } }); // 将助手按钮添加到导航栏 // 初始化脚本 function init() { // 等待导航栏加载 const waitForNav = setInterval(() => { const navUl = document.querySelector('.nav.pull-right'); if (navUl) { clearInterval(waitForNav); // 获取保存的UI显示状态 const uiVisible = GM_getValue('uiVisible', false); // 创建新的导航项 const navItem = document.createElement('li'); const navLink = document.createElement('a'); navLink.href = 'javascript:void(0);'; // 创建图标 const icon = document.createElement('span'); icon.className = 'helper-icon'; icon.innerHTML = ``; // 添加图标和文本 navLink.appendChild(icon); navLink.appendChild(document.createTextNode('图片助手')); navLink.title = '打开图片上传助手'; navLink.style.color = '#4CAF50'; // 使其稍微突出 navLink.onclick = function(e) { e.preventDefault(); const customContainer = document.getElementById('custom-imgbox-container'); if (customContainer) { // 切换显示状态 const newDisplayState = customContainer.style.display === 'none' ? 'block' : 'none'; customContainer.style.display = newDisplayState; // 保存状态 GM_setValue('uiVisible', newDisplayState === 'block'); // 更新图标颜色 navLink.style.color = newDisplayState === 'block' ? '#4CAF50' : '#999'; } else { // 初次创建界面 addImgboxUI(); GM_setValue('uiVisible', true); } }; navItem.appendChild(navLink); // 将导航项添加到导航栏 navUl.appendChild(navItem); // 根据保存的UI状态设置导航栏图标颜色 if (uiVisible) { navLink.style.color = '#4CAF50'; } else { navLink.style.color = '#999'; } // 如果之前设置了显示,则自动创建界面 if (uiVisible) { addImgboxUI(); } } }, 100); } // 激活标签页 function activateTab(tabId) { // 隐藏所有标签内容 const tabContents = document.querySelectorAll('.tab-content'); tabContents.forEach(content => { content.classList.remove('active'); content.style.display = 'none'; }); // 重置所有标签按钮样式 const tabButtons = document.querySelectorAll('.tab-button'); tabButtons.forEach(button => { button.classList.remove('active'); }); // 激活选中的标签页 const selectedTab = document.getElementById(tabId); if (selectedTab) { selectedTab.classList.add('active'); selectedTab.style.display = 'block'; } // 激活对应的标签按钮 const activeButton = document.querySelector(`.tab-button[data-tab-id="${tabId}"]`) || document.querySelector(`.tab-button[onclick*="'${tabId}'"]`); if (activeButton) { activeButton.classList.add('active'); } // 将当前标签页ID保存到本地存储 GM_setValue('activeTab', tabId); } // 检测页面类型并选择默认标签页 function detectPageTypeAndSetDefaultTab() { // 检测是否有 BBCode 内容 const hasBBCode = document.body.textContent.includes('[img]') || document.body.textContent.includes('[IMG]'); // 如果有BBCode内容,默认打开提取标签页 if (hasBBCode) { return 'extract-tab'; } // 如果是上传页面 if (document.querySelector('form[action*="upload"]') || document.querySelector('input[type="file"]')) { return 'upload-tab'; } // 如果都不是,返回上次保存的标签页或默认值 return GM_getValue('activeTab', 'upload-tab'); } // 添加Imgbox界面UI function addImgboxUI(initialLinks) { // 查找上传表单区域 const uploadForm = document.querySelector('form[action*="upload"]') || document.querySelector('form#new_gallery') || document.querySelector('.container form'); if (!uploadForm) { console.error('未找到上传表单'); return; } // 创建自定义UI容器 const customContainer = document.createElement('div'); customContainer.id = 'custom-imgbox-container'; // 根据保存的状态决定是否显示 const uiVisible = GM_getValue('uiVisible', false); customContainer.style.display = uiVisible ? 'block' : 'none'; // 创建标签页容器 const tabContainer = document.createElement('div'); tabContainer.className = 'tab-container'; customContainer.appendChild(tabContainer); // 创建标签按钮 const tabButtons = document.createElement('div'); tabButtons.className = 'tab-buttons'; tabContainer.appendChild(tabButtons); // 上传标签按钮 const uploadTabButton = document.createElement('button'); uploadTabButton.className = 'tab-button'; uploadTabButton.textContent = '图片链接上传'; uploadTabButton.dataset.tabId = 'upload-tab'; uploadTabButton.onclick = function() { activateTab('upload-tab'); }; tabButtons.appendChild(uploadTabButton); // 提取标签按钮 const extractTabButton = document.createElement('button'); extractTabButton.className = 'tab-button'; extractTabButton.textContent = 'BB代码链接提取'; extractTabButton.dataset.tabId = 'extract-tab'; extractTabButton.onclick = function() { activateTab('extract-tab'); }; tabButtons.appendChild(extractTabButton); // 创建上传标签内容 const uploadTabContent = document.createElement('div'); uploadTabContent.id = 'upload-tab'; uploadTabContent.className = 'tab-content'; tabContainer.appendChild(uploadTabContent); // 创建链接输入区域 const inputLabel = document.createElement('div'); inputLabel.textContent = '请输入图片链接(每行一个):'; inputLabel.className = 'section-title'; uploadTabContent.appendChild(inputLabel); const linksInput = document.createElement('textarea'); linksInput.id = 'imgbox-links-input'; linksInput.placeholder = '请输入图片链接,每行一个链接'; uploadTabContent.appendChild(linksInput); // 创建格式转换选项 const formatContainer = document.createElement('div'); formatContainer.className = 'format-container'; formatContainer.style.cssText = 'margin: 10px 0; display: flex; align-items: center;'; const formatLabel = document.createElement('label'); formatLabel.textContent = '图片格式转换: '; formatLabel.style.marginRight = '10px'; formatContainer.appendChild(formatLabel); const formatSelect = document.createElement('select'); formatSelect.id = 'imgbox-format-select'; formatSelect.style.cssText = 'padding: 5px; background-color: #333; color: white; border: 1px solid #444; border-radius: 4px;'; const formats = [ { value: 'original', text: '保持原始格式' }, { value: 'png', text: '转换为 PNG' }, { value: 'jpeg', text: '转换为 JPEG' } ]; formats.forEach(format => { const option = document.createElement('option'); option.value = format.value; option.textContent = format.text; formatSelect.appendChild(option); }); // 从本地存储中读取默认格式 const savedFormat = GM_getValue('imageFormat', 'original'); formatSelect.value = savedFormat; // 保存选择的格式 formatSelect.onchange = function() { GM_setValue('imageFormat', this.value); }; formatContainer.appendChild(formatSelect); uploadTabContent.appendChild(formatContainer); // 创建自动上传选项 const autoUploadContainer = document.createElement('div'); autoUploadContainer.className = 'auto-upload-container'; autoUploadContainer.style.cssText = 'margin: 10px 0; display: flex; align-items: center;'; const autoUploadCheckbox = document.createElement('input'); autoUploadCheckbox.type = 'checkbox'; autoUploadCheckbox.id = 'imgbox-auto-upload'; autoUploadCheckbox.style.marginRight = '5px'; // 从本地存储中读取自动上传设置 const autoUploadEnabled = GM_getValue('autoUpload', false); autoUploadCheckbox.checked = autoUploadEnabled; // 保存自动上传设置 autoUploadCheckbox.onchange = function() { GM_setValue('autoUpload', this.checked); }; const autoUploadLabel = document.createElement('label'); autoUploadLabel.textContent = '自动上传'; autoUploadLabel.htmlFor = 'imgbox-auto-upload'; autoUploadLabel.style.cursor = 'pointer'; autoUploadContainer.appendChild(autoUploadCheckbox); autoUploadContainer.appendChild(autoUploadLabel); uploadTabContent.appendChild(autoUploadContainer); // 创建按钮容器 const uploadButtonContainer = document.createElement('div'); uploadButtonContainer.style.cssText = 'display: flex; gap: 10px; margin-top: 10px;'; uploadTabContent.appendChild(uploadButtonContainer); // 创建下载按钮 const downloadButton = document.createElement('button'); downloadButton.textContent = '下载图片并添加到上传列表'; downloadButton.type = 'button'; // 防止触发表单提交 downloadButton.className = 'orange-btn'; downloadButton.onclick = function() { processImageLinks(linksInput.value); }; uploadButtonContainer.appendChild(downloadButton); // 创建清空按钮 const clearUploadButton = document.createElement('button'); clearUploadButton.textContent = '清空'; clearUploadButton.type = 'button'; clearUploadButton.className = 'gray-btn'; clearUploadButton.onclick = function() { linksInput.value = ''; const statusDiv = document.getElementById('imgbox-status'); if (statusDiv) statusDiv.innerHTML = ''; }; uploadButtonContainer.appendChild(clearUploadButton); // 创建状态显示区域 const statusDiv = document.createElement('div'); statusDiv.id = 'imgbox-status'; uploadTabContent.appendChild(statusDiv); // 创建提取标签内容 const extractTabContent = document.createElement('div'); extractTabContent.id = 'extract-tab'; extractTabContent.className = 'tab-content'; tabContainer.appendChild(extractTabContent); // 创建链接提取区域 const extractLabel = document.createElement('div'); extractLabel.textContent = 'BB代码链接提取:'; extractLabel.className = 'section-title'; extractTabContent.appendChild(extractLabel); const extractTextarea = document.createElement('textarea'); extractTextarea.id = 'imgbox-bbcode-input'; extractTextarea.placeholder = '粘贴包含[IMG]标签的BB代码...'; extractTabContent.appendChild(extractTextarea); // 创建按钮容器 const buttonContainer = document.createElement('div'); buttonContainer.style.cssText = 'display: flex; gap: 10px; margin-top: 10px;'; extractTabContent.appendChild(buttonContainer); // 创建提取按钮 const extractButton = document.createElement('button'); extractButton.textContent = '提取图片链接'; extractButton.type = 'button'; extractButton.className = 'orange-btn'; extractButton.onclick = function() { extractImageLinks(); }; buttonContainer.appendChild(extractButton); // 创建自动获取按钮 const autoGetButton = document.createElement('button'); autoGetButton.textContent = '从页面BB-Code获取大图直链'; autoGetButton.type = 'button'; autoGetButton.className = 'blue-btn'; autoGetButton.onclick = function() { getPageBBCode(); }; buttonContainer.appendChild(autoGetButton); // 创建提取结果区域 const extractedLinksLabel = document.createElement('div'); extractedLinksLabel.textContent = '提取结果:'; extractedLinksLabel.className = 'section-title'; extractTabContent.appendChild(extractedLinksLabel); const extractedLinksArea = document.createElement('div'); extractedLinksArea.id = 'imgbox-extracted-links'; extractTabContent.appendChild(extractedLinksArea); // 创建按钮容器 const extractButtonContainer = document.createElement('div'); extractButtonContainer.style.cssText = 'display: flex; gap: 10px; margin-top: 10px;'; extractTabContent.appendChild(extractButtonContainer); // 创建复制提取结果按钮 const copyExtractedButton = document.createElement('button'); copyExtractedButton.textContent = '复制链接'; copyExtractedButton.type = 'button'; copyExtractedButton.className = 'blue-btn'; copyExtractedButton.onclick = function() { copyExtractedLinks(); }; extractButtonContainer.appendChild(copyExtractedButton); // 创建清空按钮 const clearAllButton = document.createElement('button'); clearAllButton.textContent = '清空'; clearAllButton.type = 'button'; clearAllButton.className = 'gray-btn'; clearAllButton.onclick = function() { extractTextarea.value = ''; const extractResultsDiv = document.getElementById('extract-results'); const extractedLinksArea = document.getElementById('imgbox-extracted-links'); if (extractResultsDiv) extractResultsDiv.innerHTML = ''; if (extractedLinksArea) extractedLinksArea.innerHTML = ''; }; extractButtonContainer.appendChild(clearAllButton); // 将自定义容器插入到上传表单之前 uploadForm.parentNode.insertBefore(customContainer, uploadForm); // 如果有初始链接,自动处理 if (initialLinks && typeof initialLinks === 'string' && initialLinks.trim()) { setTimeout(() => { processImageLinks(initialLinks); }, 1500); } // 检测页面类型并设置默认标签页 const defaultTabId = detectPageTypeAndSetDefaultTab(); activateTab(defaultTabId); } // 处理图片链接 async function processImageLinks(linksText) { const statusDiv = document.getElementById('imgbox-status'); statusDiv.style.display = 'block'; statusDiv.textContent = '准备处理图片链接...'; // 解析链接 const links = linksText.trim().split(/[\n,]/).filter(link => link.trim() !== ''); if (links.length === 0) { statusDiv.textContent = '请输入至少一个图片链接!'; statusDiv.style.color = 'red'; return; } // 查找文件输入元素 const fileInput = document.querySelector('input[type="file"][name*="file"]'); if (!fileInput) { statusDiv.textContent = '未找到文件上传输入框!'; statusDiv.style.color = 'red'; return; } // 先收集所有文件 statusDiv.textContent = `开始处理 ${links.length} 个图片链接...`; statusDiv.style.color = '#4CAF50'; // 设置为统一的颜色 const files = []; for (let i = 0; i < links.length; i++) { const link = links[i].trim(); if (!link) continue; statusDiv.textContent = `下载第 ${i+1}/${links.length} 个图片: ${link}`; statusDiv.style.color = '#4CAF50'; // 设置为统一的颜色 try { // 下载图片 const file = await getImage(link); files.push(file); statusDiv.textContent = `已下载 ${files.length}/${links.length} 张图片`; statusDiv.style.color = '#4CAF50'; // 设置为统一的颜色 } catch (error) { console.error(`下载链接 ${link} 失败:`, error); statusDiv.textContent = `下载链接 ${link} 失败: ${error.message}`; } } if (files.length === 0) { statusDiv.textContent = '没有成功下载任何图片!'; statusDiv.style.color = 'red'; return; } // 一次性添加所有文件到输入框 statusDiv.textContent = `正在添加 ${files.length} 张图片到上传列表...`; statusDiv.style.color = '#4CAF50'; // 设置为统一的颜色 addFilesToInput(fileInput, files); statusDiv.textContent = `已添加 ${files.length} 张图片到上传列表,请点击网站的上传按钮开始上传`; statusDiv.style.color = 'green'; } // 提取图片链接 function extractImageLinks() { const bbcodeInput = document.getElementById('imgbox-bbcode-input'); const extractedLinksArea = document.getElementById('imgbox-extracted-links'); const bbcode = bbcodeInput.value.trim(); if (!bbcode) { showToast('请输入包含[IMG]标签的BB代码!', 'error'); return; } // 提取[IMG]标签中的链接 const imgRegex = /\[IMG\](.*?)\[\/IMG\]/gi; const matches = []; let match; while ((match = imgRegex.exec(bbcode)) !== null) { if (match[1]) { matches.push(match[1]); } } // 清空结果区域 extractedLinksArea.innerHTML = ''; if (matches.length === 0) { extractedLinksArea.innerHTML = '