// ==UserScript== // @name ScriptHub - 🧲 高效查找当前网站可用油猴脚本 🔍 // @name:zh ScriptHub - 🧲 高效查找当前网站可用油猴脚本 🔍 // @name:en ScriptHub - Available Scripts Finder // @namespace http://tampermonkey.net/ // @version 1.3 // @description 在页面右下角显示当前网站可用的油猴脚本, Shows available userscripts for the current website from Greasy Fork // @description:zh 在页面右下角显示当前网站可用的油猴脚本数量,点击查看详情 // @description:en Shows available userscripts for the current website from Greasy Fork // @author Musk // @match *://*/* // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_getResourceText // @resource SITE_DATA https://greasyfork.org/scripts/by-site.json // @connect greasyfork.org // @connect www.greasyfork.org // @connect * // @run-at document-end // @noframes // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; GM_addStyle(` .script-hub-button { position: fixed; right: 20px; bottom: 20px; padding: 6px 12px; background: rgba(255, 255, 255, 0.15); border-radius: 20px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); cursor: move; user-select: none; z-index: 9999; display: flex; align-items: center; gap: 8px; font-size: 12px; transition: all 0.2s ease; } .script-hub-button:hover { background: rgba(255, 255, 255, 0.7); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } .script-hub-button .close { margin-left: 4px; cursor: pointer; opacity: 0.6; font-size: 12px; padding: 2px; } .script-hub-button .close:hover { opacity: 1; } .script-hub-sidebar { position: fixed; top: 0; right: -400px; width: 400px; height: 100vh; background: #f8f9fa; box-shadow: -2px 0 5px rgba(0,0,0,0.1); transition: right 0.3s ease; z-index: 10000; overflow-y: auto; } .script-hub-sidebar.active { right: 0; } .script-list { padding: 12px; } .script-item { margin: 0 0 12px; padding: 12px; border-radius: 8px; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,0.1); transition: all 0.2s ease; } .script-item:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.15); transform: translateY(-1px); } .script-item h3 { margin: 0 0 6px 0; font-size: 16px; } .script-item h3 a { color: #1a73e8; text-decoration: none; } .script-item h3 a:hover { text-decoration: underline; } .script-description { color: #666; font-size: 0.9em; line-height: 1.4; margin: 6px 0; } .script-meta { display: flex; justify-content: flex-start; align-items: center; padding: 6px 0 0; color: #666; font-size: 0.9em; border-top: 1px solid #eee; margin-top: 6px; gap: 16px; white-space: nowrap; overflow: hidden; } .script-meta span { flex-shrink: 0; display: flex; align-items: center; gap: 4px; background: #f5f7fa; padding: 2px 8px; border-radius: 4px; font-size: 0.9em; } .script-meta .author { flex-shrink: 1; overflow: hidden; text-overflow: ellipsis; min-width: 0; } .script-meta .author a { color: inherit; text-decoration: none; overflow: hidden; text-overflow: ellipsis; display: block; } .script-meta .author a:hover { text-decoration: underline; color: #1a73e8; } .sidebar-header { display: flex; justify-content: space-between; align-items: center; padding: 12px 15px; border-bottom: 1px solid #eee; background: #f8f9fa; } .sidebar-header-tools { display: flex; align-items: center; gap: 12px; font-size: 14px; color: #666; } .sidebar-header-tools a { color: #666; text-decoration: none; display: flex; align-items: center; gap: 4px; padding: 4px 8px; border-radius: 4px; transition: all 0.2s ease; white-space: nowrap; } .sidebar-header-tools a:hover { background: #f5f7fa; color: #1a73e8; } .close-button { cursor: pointer; padding: 4px 8px; color: #666; font-size: 16px; border-radius: 4px; transition: all 0.2s ease; } .close-button:hover { background: #f5f7fa; color: #1a73e8; } .loading, .error, .no-scripts { padding: 20px; text-align: center; color: #666; } .error { color: #f44336; } `); function extractTLD(domain) { domain = domain.replace(/^(https?:\/\/)?(www\.)?/, '').split('/')[0]; const parts = domain.split('.'); if (parts.length >= 2) { return parts.slice(-2).join('.').toLowerCase(); } return domain.toLowerCase(); } function formatDate(dateString) { const date = new Date(dateString); const now = new Date(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); if (date.getFullYear() === now.getFullYear()) { return `${month}月${day}日`; } else { return `${date.getFullYear().toString().slice(-2)}年${month}月${day}日`; } } function createUI() { const button = document.createElement('div'); button.className = 'script-hub-button'; const text = document.createElement('span'); text.textContent = '0'; const close = document.createElement('span'); close.className = 'close'; close.textContent = '×'; close.onclick = (e) => { e.stopPropagation(); const currentDomain = window.location.hostname; if (typeof GM_getValue !== 'undefined' && typeof GM_setValue !== 'undefined') { const excludedDomains = GM_getValue('excludedDomains', []); if (!excludedDomains.includes(currentDomain)) { excludedDomains.push(currentDomain); GM_setValue('excludedDomains', excludedDomains); } } button.remove(); }; button.appendChild(text); button.appendChild(close); let isDragging = false; let startX = 0; let startY = 0; let startLeft = 0; let startTop = 0; function handleMouseDown(e) { if (e.target === close) return; isDragging = true; startX = e.clientX; startY = e.clientY; const rect = button.getBoundingClientRect(); startLeft = rect.left; startTop = rect.top; button.style.transition = 'none'; button.style.cursor = 'grabbing'; } function handleMouseMove(e) { if (!isDragging) return; const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; const newLeft = startLeft + deltaX; const newTop = startTop + deltaY; const buttonWidth = button.offsetWidth; const buttonHeight = button.offsetHeight; const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const finalLeft = Math.min(Math.max(0, newLeft), viewportWidth - buttonWidth); const finalTop = Math.min(Math.max(0, newTop), viewportHeight - buttonHeight); button.style.left = finalLeft + 'px'; button.style.top = finalTop + 'px'; button.style.right = 'auto'; button.style.bottom = 'auto'; } function handleMouseUp() { if (!isDragging) return; isDragging = false; button.style.transition = ''; button.style.cursor = 'move'; } button.addEventListener('mousedown', handleMouseDown); document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); document.body.appendChild(button); const sidebar = document.createElement('div'); sidebar.className = 'script-hub-sidebar'; document.body.appendChild(sidebar); document.addEventListener('click', (e) => { if (!sidebar.contains(e.target) && !button.contains(e.target) && sidebar.classList.contains('show')) { sidebar.classList.remove('show'); button.classList.remove('active'); } }); sidebar.addEventListener('click', (e) => { e.stopPropagation(); }); button.addEventListener('click', (e) => { if (e.target === close) return; sidebar.classList.toggle('show'); button.classList.toggle('active'); e.stopPropagation(); }); sidebar.innerHTML = `
`; document.body.appendChild(sidebar); button.addEventListener('click', async () => { sidebar.classList.add('active'); const scriptList = sidebar.querySelector('.script-list'); if (!scriptList.children.length) { const rawDomain = document.location.hostname; const domain = extractTLD(rawDomain); await loadScriptDetails(domain, scriptList); } }); sidebar.querySelector('.close-button').addEventListener('click', () => { sidebar.classList.remove('active'); }); return { button, sidebar }; } async function loadScriptDetails(domain, container, retryCount = 0) { container.innerHTML = '