// ==UserScript== // @name My Userscript : 自动匹配显示当前网站所有可用的UserJS脚本 (Optimized) // @name:zh-CN My Userscript : 显示当前网站所有可用的UserJS脚本 (优化版) // @version 4.0 // @description 显示当前网站的所有可用UserJS(Tampermonkey)脚本,一键安装。移除冗余依赖,优化代码结构。 // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3ggEBCQHM3fXsAAAAVdJREFUOMudkz2qwkAUhc/goBaGJBgUtBCZyj0ILkpwAW7Bws4yO3AHLiCtEFD8KVREkoiFxZzX5A2KGfN4F04zMN+ce+5c4LMUgDmANYBnrnV+plBSi+FwyHq9TgA2LQpvCiEiABwMBtzv95RSfoNEHy8DYBzHrNVqVEr9BWKcqNFoxF6vx3a7zc1mYyC73a4MogBg7vs+z+czO50OW60Wt9stK5UKp9Mpj8cjq9WqDTBHnjAdxzGQZrPJw+HA31oulzbAWgLoA0CWZVBKIY5jzGYzdLtdE9DlcrFNrY98zobqOA6TJKHW2jg4nU5sNBpFDp6mhVe5rsvVasUwDHm9Xqm15u12o+/7Hy0gD8KatOd5vN/v1FozTVN6nkchxFuI6hsAAIMg4OPxMJCXdtTbR7JJCMEgCJhlGUlyPB4XfumozInrupxMJpRSRtZlKoNYl+m/6/wDuWAjtPfsQuwAAAAASUVORK5CYII= // @include * // @require https://cdn.jsdelivr.net/npm/psl@1.9.0/dist/psl.min.js // @resource count https://greasyfork.org/scripts/by-site.json // @grant GM_xmlhttpRequest // @grant GM_getResourceText // @grant GM_getValue // @grant GM_setValue // @grant GM_addStyle // @grant GM_openInTab // @connect greasyfork.org // @run-at document-end // @namespace https://github.com/jae-jae/Userscript-Plus // @downloadURL https://update.greasyfork.icu/scripts/548869/My%20Userscript%20%3A%20%E8%87%AA%E5%8A%A8%E5%8C%B9%E9%85%8D%E6%98%BE%E7%A4%BA%E5%BD%93%E5%89%8D%E7%BD%91%E7%AB%99%E6%89%80%E6%9C%89%E5%8F%AF%E7%94%A8%E7%9A%84UserJS%E8%84%9A%E6%9C%AC%20%28Optimized%29.user.js // @updateURL https://update.greasyfork.icu/scripts/548869/My%20Userscript%20%3A%20%E8%87%AA%E5%8A%A8%E5%8C%B9%E9%85%8D%E6%98%BE%E7%A4%BA%E5%BD%93%E5%89%8D%E7%BD%91%E7%AB%99%E6%89%80%E6%9C%89%E5%8F%AF%E7%94%A8%E7%9A%84UserJS%E8%84%9A%E6%9C%AC%20%28Optimized%29.meta.js // ==/UserScript== (function() { 'use strict'; // 样式定义 const CSS = ` #jae_userscript_box { font-family: sans-serif; } .jae-userscript { position: fixed; width: 500px; top: 20px; right: 20px; z-index: 2147483647; height: auto; background: #fff; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); padding: 15px; border: 2px solid #4CAF50; display: none; } .script-list { max-height: 450px; overflow-y: auto; padding: 10px; } .script-item { padding: 15px; margin: 10px 0; border: 1px solid #e0e0e0; border-radius: 6px; background: #fafafa; transition: all 0.3s; } .script-item:hover { background-color: #f0f8ff; border-color: #4CAF50; box-shadow: 0 2px 8px rgba(76,175,80,0.2); } .script-name { font-weight: bold; color: #333; margin-bottom: 8px; font-size: 15px; line-height: 1.4; } .script-desc { font-size: 13px; color: #666; margin-bottom: 10px; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } .script-meta { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; font-size: 12px; } .script-meta-item { background: #e8f5e8; color: #2e7d32; padding: 3px 8px; border-radius: 12px; } .script-meta-item.installs { background: #e3f2fd; color: #1565c0; } .script-meta-item.rating { background: #fff3e0; color: #f57c00; } .script-meta-item.updated { background: #f3e5f5; color: #7b1fa2; } .script-actions { display: flex; gap: 8px; } .script-install { display: inline-block; padding: 8px 12px; background: #4CAF50; color: white; text-decoration: none; border-radius: 4px; font-size: 13px; transition: background-color 0.3s; text-align: center; flex: 1; cursor: pointer; } .script-install:hover { background: #45a049; color: white; } .script-install.secondary { background: #2196F3; } .script-install.secondary:hover { background: #1976D2; } .close-btn { position: absolute; top: 8px; right: 8px; background: #ff4444; color: white; border: none; border-radius: 6px; width: 32px; height: 32px; font-size: 18px; font-weight: bold; cursor: pointer; display: flex; align-items: center; justify-content: center; z-index: 10; } .close-btn:hover { background: #e53935; } .sort-controls { padding: 10px; background: #f8f9fa; border-bottom: 1px solid #eee; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } .sort-select { padding: 5px 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 12px; background: white; cursor: pointer; } /* Float Button & Settings */ #jae_float_container { position: fixed; top: 50%; right: 0; z-index: 2147483646; display: flex; flex-direction: column; align-items: flex-end; transform: translateY(-50%); } .jae-float-btn { width: 40px; color: white; border: none; border-radius: 8px 0 0 8px; cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,0.2); margin-bottom: 10px; display: flex; align-items: center; justify-content: center; transition: transform 0.3s; } .jae-float-btn:hover { transform: translateX(-5px); } #jae_settings_box { position: fixed; top: 50%; left: 50%; transform: translate(-50%,-50%); z-index: 2147483647; width: 400px; background: #fff; border-radius: 8px; box-shadow: 0 4px 16px rgba(0,0,0,0.3); padding: 20px; border: 2px solid #FF9800; } #jae_restore_float_btn { position: fixed; bottom: 20px; right: 20px; z-index: 2147483646; width: 30px; height: 30px; background: #FF9800; color: white; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; } `; class FetchUserjs { constructor() { this.host = this.getMainHost(); this.quietKey = 'jae_fetch_userjs_quiet'; this.countKey = 'jae_fetch_userjs_count'; this.settingsKey = 'jae_fetch_userjs_settings'; this.currentScriptList = []; this.settings = this.loadSettings(); GM_addStyle(CSS); } getMainHost() { const host = window.location.hostname; try { if (typeof psl !== 'undefined' && psl?.get) { return psl.get(host) || host; } return host.split('.').slice(-2).join('.'); } catch (e) { return host; } } getCountData() { try { const countData = GM_getResourceText('count'); if (!countData) return 0; const data = JSON.parse(countData); return data[this.host] || 0; } catch (e) { console.error('Data Parse Error:', e); return 0; } } fetchScriptList(host) { return new Promise((resolve) => { GM_xmlhttpRequest({ method: 'GET', url: `https://greasyfork.org/zh-CN/scripts/by-site/${encodeURIComponent(host)}.json`, headers: { 'User-Agent': 'Mozilla/5.0 (compatible; My Userscript Optimized)' }, timeout: 10000, onload: (res) => { if (res.status === 200) { try { resolve(JSON.parse(res.responseText) || []); } catch { resolve([]); } } else { resolve([]); } }, onerror: () => resolve([]), ontimeout: () => resolve([]) }); }); } formatDate(dateStr) { const date = new Date(dateStr); const diffDays = Math.ceil(Math.abs(new Date() - date) / (86400000)); if (diffDays === 1) return '昨天'; if (diffDays < 7) return `${diffDays}天前`; if (diffDays < 30) return `${Math.ceil(diffDays / 7)}周前`; return `${Math.ceil(diffDays / 30)}个月前`; } formatNumber(num) { if (!num) return '0'; if (num >= 1e6) return (num / 1e6).toFixed(1) + 'M'; if (num >= 1e3) return (num / 1e3).toFixed(1) + 'K'; return num.toString(); } loadSettings() { return GM_getValue(this.settingsKey, { autoShow: false, floatButtonsVisible: true }); } saveSettings(newSettings) { GM_setValue(this.settingsKey, newSettings); this.settings = newSettings; this.render(); // Re-render to reflect changes } createEl(html) { const div = document.createElement('div'); div.innerHTML = html.trim(); return div.firstChild; } renderSettings() { if (document.getElementById('jae_settings_box')) return; const html = `