My Userscript : 自动匹配显示当前网站所有可用的UserJS脚本,Show Site All UserJS

显示当前网站的所有可用UserJS(Tampermonkey)脚本,一键安装。Show current site all UserJS,The easier way to install UserJs for Tampermonkey.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         My Userscript : 自动匹配显示当前网站所有可用的UserJS脚本,Show Site All UserJS
// @name:zh      My Userscript : 自动匹配显示当前网站所有可用的UserJS脚本 
// @name:zh-CN   My Userscript : 显示当前网站所有可用的UserJS脚本 
// @name:zh-TW   My Userscript : 顯示當前網站所有可用的UserJS腳本 
// @name:ja      My Userscript:現在のサイトの利用可能なすべてのUserJSスクリプトを表示する
// @name:ru-RU   My Userscript : Показать пользовательские скрипты (UserJS) для сайта. 
// @name:ru      My Userscript : Показать пользовательские скрипты (UserJS) для сайта. 
// @name:en      My Userscript : Show All Available UserJS Scripts for Current Site
// @name:es      My Userscript : Mostrar todos los scripts UserJS disponibles para el sitio actual
// @name:fr      My Userscript : Afficher tous les scripts UserJS disponibles pour le site actuel
// @name:de      My Userscript : Zeige alle verfügbaren UserJS-Skripte für die aktuelle Seite
// @name:it      My Userscript : Mostra tutti gli script UserJS disponibili per il sito corrente
// @name:ko      My Userscript : 현재 사이트의 모든 사용 가능한 UserJS 스크립트 보기
// @version      3.1.2
// @description         显示当前网站的所有可用UserJS(Tampermonkey)脚本,一键安装。Show current site all UserJS,The easier way to install UserJs for Tampermonkey.
// @description:zh      显示当前网站的所有可用UserJS(Tampermonkey)脚本,一键安装。
// @description:zh-CN   显示当前网站的所有可用UserJS(Tampermonkey)脚本,一键安装。
// @description:zh-TW   顯示當前網站的所有可用UserJS(Tampermonkey)腳本,一键安装。
// @description:ja      現在のサイトで利用可能なすべてのUserJS(Tampermonkey)スクリプトを表示します。一括インストール可能。
// @description:ru-RU   Показывает пользовательские скрипты (UserJS) для сайта. Легкий способ установить пользовательские скрипты для Tampermonkey.
// @description:ru      Показывает пользовательские скрипты (UserJS) для сайта. Легкий способ установить пользовательские скрипты для Tampermonkey.
// @description:en      Show all available UserJS (Tampermonkey) scripts for the current website. One-click installation.
// @description:es      Muestra todos los scripts UserJS (Tampermonkey) disponibles para el sitio web actual. Instalación con un solo clic.
// @description:fr      Affiche tous les scripts UserJS (Tampermonkey) disponibles pour le site web actuel. Installation en un clic.
// @description:de      Zeigt alle verfügbaren UserJS (Tampermonkey)-Skripte für die aktuelle Website an. Ein-Klick-Installation.
// @description:it      Mostra tutti gli script UserJS (Tampermonkey) disponibili per il sito web corrente. Installazione con un clic.
// @description:ko      현재 웹사이트의 모든 사용 가능한 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://code.jquery.com/jquery-3.6.0.min.js
// @require     https://cdn.jsdelivr.net/npm/[email protected]/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        unsafeWindow
// @noframes
// @connect     cdn.bootcss.com
// @connect     raw.githubusercontent.com
// @connect     gist.githubusercontent.com
// @connect     cdnjs.cloudflare.com
// @connect     greasyfork.org
// @connect     cdn.jsdelivr.net
// @run-at      document-end
// @namespace https://github.com/jae-jae/Userscript-Plus
// ==/UserScript==

unsafeWindow.GmAjax = GM_xmlhttpRequest;

(function() {

    'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var FetchUserjs = function () {
    function FetchUserjs() {
        _classCallCheck(this, FetchUserjs);

        this.host = this.getMainHost();
        this.showTime = 10;
        this.quietKey = 'jae_fetch_userjs_quiet';
        this.countKey = 'jae_fetch_userjs_count';
        this.settingsKey = 'jae_fetch_userjs_settings';
        this.isVisible = false;
        this.currentScriptList = []; // 存储当前的脚本列表
        this.settings = this.loadSettings();
        this.tplBox = '<div id="jae_userscript_box"><style>.jae-userscript{position:fixed;width:500px;top:20px;right:20px;z-index:9999999999;height:auto;background:#fff;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.15);padding:15px;border: 2px solid #4CAF50;}.jae-userscript-shadow{box-shadow:0 1px 4px rgba(0,0,0,.3), 0px 0 20px rgba(0,0,0,.1) inset}.jae-userscript-shadow::before,.jae-userscript-shadow::after{content:"";position:absolute;z-index:-1}.jae-userscript-shadow::before,.jae-userscript-shadow::after{content:"";position:absolute;z-index:-1;bottom:15px;left:10px;width:50%;height:20%}.jae-userscript-shadow::before,.jae-userscript-shadow::after{content:"";position:absolute;z-index:-1;bottom:15px;left:10px;width:50%;height:20%;box-shadow:0 15px 10px rgba(0,0,0,.7);transform:rotate(-3deg)}.jae-userscript-shadow::after{right:10px;left:auto;transform:rotate(3deg)}.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-item:last-child{border-bottom:1px solid #e0e0e0}.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;}.script-install:hover{background:#45a049;color:white;text-decoration:none;}.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;transition:all 0.3s;display:flex;align-items:center;justify-content:center;box-shadow:0 2px 8px rgba(255,68,68,0.3);z-index:10;}.close-btn:hover{background:#e53935;transform:scale(1.1);box-shadow:0 4px 12px rgba(255,68,68,0.4);}.close-btn:active{transform:scale(0.95);}.sort-controls{padding:10px;background:#f8f9fa;border-bottom:1px solid #eee;display:flex;align-items:center;gap:10px;flex-wrap:wrap;}.sort-label{font-size:13px;color:#666;font-weight:bold;}.sort-select{padding:5px 8px;border:1px solid #ddd;border-radius:4px;font-size:12px;background:white;cursor:pointer;transition:border-color 0.3s;}.sort-select:hover{border-color:#4CAF50;}.sort-select:focus{outline:none;border-color:#4CAF50;box-shadow:0 0 0 2px rgba(76,175,80,0.2);}</style><div class="jae-userscript"><div class="script-header" style="padding:10px;background:#f8f9fa;border-bottom:1px solid #eee;position:relative;"><div style="font-weight:bold;font-size:16px;margin-bottom:5px;">可匹配的脚本</div><div style="font-size:12px;color:#666;">当前网站可用脚本: <span id="script-count">0</span> 个</div><div style="font-size:12px;color:#666;">网站: ' + this.host + '</div><button class="close-btn" id="close-script-box" title="关闭脚本列表" aria-label="关闭脚本列表">✕</button></div><div class="sort-controls"><span class="sort-label">排序方式:</span><select class="sort-select" id="sort-method"><option value="default">默认排序</option><option value="installs_desc">安装量(高到低)</option><option value="installs_asc">安装量(低到高)</option><option value="daily_desc">今日安装(高到低)</option><option value="updated_desc">更新时间(最新)</option><option value="updated_asc">更新时间(最旧)</option><option value="rating_desc">好评率(高到低)</option><option value="name_asc">名称(A-Z)</option></select></div><div class="script-list"></div></div></div>';
        this.tplFloatBtn = '<div id="jae_float_buttons_container" style="position:fixed;top:50%;right:0;z-index:9999999998;display:flex;flex-direction:column;align-items:flex-end;"><div id="jae_userscript_float_btn" style="width:40px;height:80px;background:#4CAF50;color:white;border:none;border-radius:8px 0 0 8px;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,0.2);transition:all 0.3s;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;writing-mode:vertical-lr;margin-bottom:10px;" title="显示UserJS脚本">UserJS</div><div id="jae_settings_btn" style="width:40px;height:40px;background:#FF9800;color:white;border:none;border-radius:8px 0 0 8px;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,0.2);transition:all 0.3s;display:flex;align-items:center;justify-content:center;font-size:16px;margin-bottom:10px;" title="设置">⚙️</div><div id="jae_close_float_buttons" style="width:40px;height:30px;background:#ff0000;color:white;border:none;border-radius:8px 0 0 8px;cursor:pointer;box-shadow:0 2px 8px rgba(255,0,0,0.4);transition:all 0.3s;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;" title="隐藏浮动按钮">✕</div></div>';
        this.tplSettings = '<div id="jae_settings_box" style="position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:9999999999;width:400px;background:#fff;border-radius:8px;box-shadow:0 4px 16px rgba(0,0,0,0.3);padding:20px;border:2px solid #FF9800;"><div style="font-weight:bold;font-size:18px;margin-bottom:15px;color:#333;text-align:center;">My Userscript 设置</div><div style="margin-bottom:20px;"><label style="display:flex;align-items:center;cursor:pointer;padding:10px;border-radius:4px;transition:background-color 0.3s;" onmouseover="this.style.backgroundColor=\'#f5f5f5\'" onmouseout="this.style.backgroundColor=\'transparent\'"><input type="checkbox" id="auto-show-setting" style="margin-right:10px;transform:scale(1.2);"><div><div style="font-weight:bold;color:#333;margin-bottom:3px;">自动显示脚本浮窗</div><div style="font-size:12px;color:#666;">在有可用脚本的网站上自动显示浮窗</div></div></label></div><div style="display:flex;gap:10px;justify-content:center;"><button id="save-settings" style="padding:8px 20px;background:#4CAF50;color:white;border:none;border-radius:4px;cursor:pointer;font-weight:bold;transition:background-color 0.3s;" onmouseover="this.style.backgroundColor=\'#45a049\'" onmouseout="this.style.backgroundColor=\'#4CAF50\'">保存</button><button id="cancel-settings" style="padding:8px 20px;background:#f44336;color:white;border:none;border-radius:4px;cursor:pointer;font-weight:bold;transition:background-color 0.3s;margin-left:10px;" onmouseover="this.style.backgroundColor=\'#da190b\'" onmouseout="this.style.backgroundColor=\'#f44336\'">取消</button></div></div>';
    }

    _createClass(FetchUserjs, [{
        key: 'getMainHost',
        value: function getMainHost() {
            var host = window.location.hostname;
            try {
                // 检查psl是否可用
                if (typeof psl !== 'undefined' && psl && typeof psl.get === 'function') {
                    return psl.get(host) || host.split('.').splice(-2).join('.');
                } else {
                    // 如果psl不可用,使用备用方法
                    return host.split('.').splice(-2).join('.');
                }
            } catch (e) {
                // 发生错误时使用备用方法
                return host.split('.').splice(-2).join('.');
            }
        }
    }, {
        key: 'getCountData',
        value: function getCountData(host) {
            try {
                var countData = GM_getResourceText('count');
                if (!countData) {
                    console.warn('无法获取脚本数量数据');
                    return 0;
                }
                countData = JSON.parse(countData);
                var count = countData[host] || 0;
                sessionStorage.setItem(this.countKey, count);
                return count;
            } catch (e) {
                console.error('获取脚本数量数据失败:', e);
                return 0;
            }
        }
    }, {
        key: 'fetchScriptList',
        value: function fetchScriptList(host) {
            try {
                // 使用Greasy Fork API获取脚本列表
                var apiUrl = 'https://greasyfork.org/zh-CN/scripts/by-site/' + encodeURIComponent(host) + '.json';

                return new Promise(function(resolve, reject) {
                    GM_xmlhttpRequest({
                        method: 'GET',
                        url: apiUrl,
                        headers: {
                            'User-Agent': 'Mozilla/5.0 (compatible; My Userscript)'
                        },
                        timeout: 10000,
                        onload: function(response) {
                            try {
                                if (response.status === 200) {
                                    var scriptList = JSON.parse(response.responseText);
                                    // 确保返回的是数组
                                    if (Array.isArray(scriptList)) {
                                        resolve(scriptList);
                                    } else {
                                        console.warn('API返回数据格式不正确');
                                        resolve([]);
                                    }
                                } else {
                                    console.error('获取脚本列表失败,状态码:', response.status);
                                    resolve([]);
                                }
                            } catch (e) {
                                console.error('解析脚本列表失败:', e);
                                resolve([]);
                            }
                        },
                        onerror: function(error) {
                            console.error('请求脚本列表失败:', error);
                            resolve([]);
                        },
                        ontimeout: function() {
                            console.error('请求脚本列表超时');
                            resolve([]);
                        }
                    });
                });
            } catch (e) {
                console.error('获取脚本列表异常:', e);
                return Promise.resolve([]);
            }
        }
    }, {
        key: 'formatDate',
        value: function formatDate(dateStr) {
            try {
                var date = new Date(dateStr);
                var now = new Date();
                var diffTime = Math.abs(now - date);
                var diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));

                if (diffDays === 1) {
                    return '昨天';
                } else if (diffDays < 7) {
                    return diffDays + '天前';
                } else if (diffDays < 30) {
                    return Math.ceil(diffDays / 7) + '周前';
                } else if (diffDays < 365) {
                    return Math.ceil(diffDays / 30) + '个月前';
                } else {
                    return Math.ceil(diffDays / 365) + '年前';
                }
            } catch (e) {
                return dateStr;
            }
        }
    }, {
        key: 'formatNumber',
        value: function formatNumber(num) {
            if (!num) return '0';
            if (num >= 1000000) {
                return (num / 1000000).toFixed(1) + 'M';
            } else if (num >= 1000) {
                return (num / 1000).toFixed(1) + 'K';
            }
            return num.toString();
        }
    }, {
        key: 'loadSettings',
        value: function loadSettings() {
            try {
                var settings = localStorage.getItem(this.settingsKey);
                if (settings) {
                    return JSON.parse(settings);
                } else {
                    // 默认设置:不自动显示浮窗
                    return {
                        autoShow: false
                    };
                }
            } catch (e) {
                console.error('加载设置失败:', e);
                return {
                    autoShow: false
                };
            }
        }
    }, {
        key: 'saveSettings',
        value: function saveSettings(settings) {
            try {
                localStorage.setItem(this.settingsKey, JSON.stringify(settings));
                this.settings = settings;
                return true;
            } catch (e) {
                console.error('保存设置失败:', e);
                return false;
            }
        }
    }, {
        key: 'showSettings',
        value: function showSettings() {
            var _this = this;

            // 检查是否已存在设置窗口
            if (document.getElementById('jae_settings_box')) {
                return;
            }

            document.body.insertAdjacentHTML('beforeend', this.tplSettings);

            var settingsBox = document.getElementById('jae_settings_box');
            var autoShowCheckbox = document.getElementById('auto-show-setting');
            var saveBtn = document.getElementById('save-settings');
            var cancelBtn = document.getElementById('cancel-settings');

            // 设置当前值
            autoShowCheckbox.checked = this.settings.autoShow;

            // 保存设置
            saveBtn.addEventListener('click', function() {
                var newSettings = {
                    autoShow: autoShowCheckbox.checked
                };

                if (_this.saveSettings(newSettings)) {
                    alert('设置已保存!');
                    settingsBox.remove();
                } else {
                    alert('保存设置失败!');
                }
            });

            // 取消设置
            cancelBtn.addEventListener('click', function() {
                settingsBox.remove();
            });

            // 点击背景关闭
            settingsBox.addEventListener('click', function(e) {
                if (e.target === settingsBox) {
                    settingsBox.remove();
                }
            });
        }
    }, {
        key: 'sortScripts',
        value: function sortScripts(scriptList, sortMethod) {
            var sorted = scriptList.slice(); // 创建副本避免修改原数组

            switch (sortMethod) {
                case 'installs_desc':
                    sorted.sort(function(a, b) {
                        return (b.total_installs || 0) - (a.total_installs || 0);
                    });
                    break;
                case 'installs_asc':
                    sorted.sort(function(a, b) {
                        return (a.total_installs || 0) - (b.total_installs || 0);
                    });
                    break;
                case 'daily_desc':
                    sorted.sort(function(a, b) {
                        return (b.daily_installs || 0) - (a.daily_installs || 0);
                    });
                    break;
                case 'updated_desc':
                    sorted.sort(function(a, b) {
                        var dateA = new Date(a.code_updated_at || 0);
                        var dateB = new Date(b.code_updated_at || 0);
                        return dateB - dateA;
                    });
                    break;
                case 'updated_asc':
                    sorted.sort(function(a, b) {
                        var dateA = new Date(a.code_updated_at || 0);
                        var dateB = new Date(b.code_updated_at || 0);
                        return dateA - dateB;
                    });
                    break;
                case 'rating_desc':
                    sorted.sort(function(a, b) {
                        var ratingA = 0;
                        var ratingB = 0;

                        if (a.good_ratings && a.ok_ratings && a.bad_ratings) {
                            var totalA = a.good_ratings + a.ok_ratings + a.bad_ratings;
                            ratingA = totalA > 0 ? (a.good_ratings / totalA) * 100 : 0;
                        }

                        if (b.good_ratings && b.ok_ratings && b.bad_ratings) {
                            var totalB = b.good_ratings + b.ok_ratings + b.bad_ratings;
                            ratingB = totalB > 0 ? (b.good_ratings / totalB) * 100 : 0;
                        }

                        return ratingB - ratingA;
                    });
                    break;
                case 'name_asc':
                    sorted.sort(function(a, b) {
                        var nameA = (a.name || '').toLowerCase();
                        var nameB = (b.name || '').toLowerCase();
                        return nameA.localeCompare(nameB);
                    });
                    break;
                default:
                    // 默认排序,不做任何操作
                    break;
            }

            return sorted;
        }
    }, {
        key: 'renderScriptList',
        value: function renderScriptList(scriptList, container) {
            var _this = this;

            if (!scriptList || scriptList.length === 0) {
                container.innerHTML = '<div style="padding:20px;text-align:center;color:#666;">未找到可用的脚本</div>';
                return;
            }

            var listHtml = '';
            scriptList.forEach(function(script) {
                listHtml += '<div class="script-item">';

                // 脚本名称
                listHtml += '<div class="script-name">' + (script.name || '未知脚本').replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</div>';

                // 脚本描述
                listHtml += '<div class="script-desc">' + (script.description || '无描述').replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</div>';

                // 脚本元信息
                listHtml += '<div class="script-meta">';

                // 总安装量
                if (script.total_installs) {
                    listHtml += '<span class="script-meta-item installs">总安装: ' + _this.formatNumber(script.total_installs) + '</span>';
                }

                // 今日安装量
                if (script.daily_installs) {
                    listHtml += '<span class="script-meta-item installs">今日: ' + _this.formatNumber(script.daily_installs) + '</span>';
                }

                // 评分
                if (script.good_ratings && script.ok_ratings && script.bad_ratings) {
                    var totalRatings = script.good_ratings + script.ok_ratings + script.bad_ratings;
                    var goodPercent = Math.round((script.good_ratings / totalRatings) * 100);
                    listHtml += '<span class="script-meta-item rating">好评: ' + goodPercent + '%</span>';
                }

                // 更新时间
                if (script.code_updated_at) {
                    listHtml += '<span class="script-meta-item updated">更新: ' + _this.formatDate(script.code_updated_at) + '</span>';
                }

                // 版本信息
                if (script.version) {
                    listHtml += '<span class="script-meta-item">v' + script.version + '</span>';
                }

                // 作者信息
                if (script.users && script.users.length > 0) {
                    listHtml += '<span class="script-meta-item">作者: ' + script.users[0].name + '</span>';
                }

                listHtml += '</div>';

                // 操作按钮
                listHtml += '<div class="script-actions">';
                listHtml += '<a href="https://greasyfork.org/zh-CN/scripts/' + script.id + '" target="_blank" class="script-install secondary">查看详情</a>';
                if (script.code_url) {
                    listHtml += '<a href="' + script.code_url + '" target="_blank" class="script-install">安装脚本</a>';
                }
                listHtml += '</div>';

                listHtml += '</div>';
            });

            container.innerHTML = listHtml;
        }
    }, {
        key: 'setSize',
        value: function setSize(w, h) {
            var element = document.querySelector('.jae-userscript');
            if (element) {
                element.style.width = w + 'px';
                element.style.height = h + 'px';
            }
        }
    }, {
        key: 'addEventListener',
        value: function addEventListener(eventName, handler) {
            document.getElementById('jae_userscript_box').addEventListener(eventName, handler);
        }
    }, {
        key: 'bindEvent',
        value: function bindEvent() {
            var _this = this;

            // 移除自动消失功能,改为手动关闭
            // this.timeId = setTimeout(function () {
            //     var box = document.getElementById('jae_userscript_box');
            //     if (box) {
            //         box.remove();
            //     }
            // }, this.showTime * 1000);

            this.addEventListener('max', function () {
                _this.setSize(860, 492);
                var element = document.querySelector('.jae-userscript');
                if (element) {
                    element.classList.add('jae-userscript-shadow');
                }
                // clearTimeout(_this.timeId);
            });

            this.addEventListener('min', function () {
                setTimeout(function () {
                    var element = document.querySelector('.jae-userscript');
                    if (element) {
                        element.classList.remove('jae-userscript-shadow');
                    }
                    _this.setSize(370, 56);
                }, 500);
            });

            this.addEventListener('close', function () {
                var box = document.getElementById('jae_userscript_box');
                if (box) {
                    box.style.display = 'none';
                    _this.isVisible = false;
                }
            });

            this.addEventListener('loading', function () {
                // clearTimeout(_this.timeId);
            });
        }
    }, {
        key: 'createFloatButton',
        value: function createFloatButton() {
            var _this = this;

            // 检查是否已存在浮动按钮
            if (document.getElementById('jae_userscript_float_btn')) {
                return;
            }

            document.body.insertAdjacentHTML('beforeend', this.tplFloatBtn);

            var floatBtn = document.getElementById('jae_userscript_float_btn');
            var settingsBtn = document.getElementById('jae_settings_btn');

            if (floatBtn) {
                floatBtn.addEventListener('click', function() {
                    _this.showScriptBox();
                });

                // 鼠标悬停效果
                floatBtn.addEventListener('mouseenter', function() {
                    this.style.backgroundColor = '#45a049';
                    this.style.transform = 'translateX(-5px)';
                });

                floatBtn.addEventListener('mouseleave', function() {
                    this.style.backgroundColor = '#4CAF50';
                    this.style.transform = 'translateX(0)';
                });
            }

            if (settingsBtn) {
                settingsBtn.addEventListener('click', function() {
                    _this.showSettings();
                });

                // 鼠标悬停效果
                settingsBtn.addEventListener('mouseenter', function() {
                    this.style.backgroundColor = '#F57C00';
                    this.style.transform = 'translateX(-5px)';
                });

                settingsBtn.addEventListener('mouseleave', function() {
                    this.style.backgroundColor = '#FF9800';
                    this.style.transform = 'translateX(0)';
                });
            }
            
            // 为关闭按钮添加点击事件
            if (closeFloatBtn) {
                closeFloatBtn.addEventListener('click', function() {
                    var container = document.getElementById('jae_float_buttons_container');
                    if (container) {
                        container.style.display = 'none';
                    }
                });

                // 鼠标悬停效果
                closeFloatBtn.addEventListener('mouseenter', function() {
                    this.style.backgroundColor = '#cc0000';
                    this.style.transform = 'translateX(-5px)';
                });

                closeFloatBtn.addEventListener('mouseleave', function() {
                    this.style.backgroundColor = '#ff0000';
                    this.style.transform = 'translateX(0)';
                });
            }

            // 添加关闭按钮事件
            var closeFloatBtn = document.getElementById('jae_close_float_buttons');
            if (closeFloatBtn) {
                closeFloatBtn.addEventListener('click', function() {
                    var container = document.getElementById('jae_float_buttons_container');
                    if (container) {
                        container.style.display = 'none';
                    }
                });

                // 鼠标悬停效果
                closeFloatBtn.addEventListener('mouseenter', function() {
                    this.style.backgroundColor = '#d32f2f';
                    this.style.transform = 'translateX(-5px)';
                });

                closeFloatBtn.addEventListener('mouseleave', function() {
                    this.style.backgroundColor = '#f44336';
                    this.style.transform = 'translateX(0)';
                });
            }
        }
    }, {
        key: 'showScriptBox',
        value: function showScriptBox() {
            var box = document.getElementById('jae_userscript_box');
            if (box) {
                box.style.display = 'block';
                this.isVisible = true;
            } else {
                this.renderScriptBox();
            }
        }
    }, {
        key: 'execFrameJs',
        value: function execFrameJs(frameWindow) {
            // 此方法已移除,因为不再使用外部UI框架
            console.log('execFrameJs method deprecated');
        }
    }, {
        key: 'render',
        value: function render() {
            var _this = this;

            // 始终创建浮动按钮
            this.createFloatButton();

            // 根据设置决定是否自动显示浮窗
            if (this.settings.autoShow && !this.isQuiet) {
                var count = this.getCountData(this.host);
                if (count > 0) {
                    this.renderScriptBox();
                }
            }
        }
    }, {
        key: 'renderScriptBox',
        value: function renderScriptBox() {
            var _this = this;

            // 如果已存在则直接显示
            var existingBox = document.getElementById('jae_userscript_box');
            if (existingBox) {
                existingBox.style.display = 'block';
                this.isVisible = true;
                return;
            }

            document.body.insertAdjacentHTML('beforeend', this.tplBox);
            this.isVisible = true;

            // 更新脚本计数
            var count = this.getCountData(this.host);
            document.getElementById('script-count').textContent = count;

            // 获取并显示脚本列表
            var dom = document.getElementById('jae_userscript_box');
            var listContainer = dom.querySelector('.script-list');
            var sortSelect = dom.querySelector('#sort-method');
            listContainer.innerHTML = '加载中...';

            this.fetchScriptList(this.host).then(function(scriptList) {
                if (scriptList && scriptList.length > 0) {
                    // 更新实际脚本数量并存储脚本列表
                    document.getElementById('script-count').textContent = scriptList.length;
                    _this.currentScriptList = scriptList;

                    // 初始渲染(默认排序)
                    _this.renderScriptList(scriptList, listContainer);
                } else {
                    document.getElementById('script-count').textContent = '0';
                    _this.currentScriptList = [];
                    listContainer.innerHTML = '<div style="padding:20px;text-align:center;color:#666;">未找到可用的脚本</div>';
                }
            }).catch(function(error) {
                console.error('获取脚本列表失败:', error);
                listContainer.innerHTML = '<div style="padding:20px;text-align:center;color:#666;">获取脚本列表失败</div>';
            });

            // 添加排序选择器事件
            sortSelect.addEventListener('change', function() {
                var sortMethod = this.value;
                if (_this.currentScriptList.length > 0) {
                    var sortedList = _this.sortScripts(_this.currentScriptList, sortMethod);
                    _this.renderScriptList(sortedList, listContainer);
                }
            });

            // 添加关闭按钮事件
            // 为大红色X按钮添加点击事件
                document.getElementById('close-script-box').addEventListener('click', function() {
                    _this.isVisible = false;
                    document.getElementById('jae_userscript_box').style.display = 'none';
                });
                
                // 为文本关闭按钮添加点击事件
                if (document.getElementById('close-text-btn')) {
                    document.getElementById('close-text-btn').addEventListener('click', function() {
                        _this.isVisible = false;
                        document.getElementById('jae_userscript_box').style.display = 'none';
                    });
                }

            this.bindEvent();
        }
    }, {
        key: 'isQuiet',
        get: function get() {
            var quiet = sessionStorage.getItem(this.quietKey);
            return quiet ? true : false;
        }
    }]);

    return FetchUserjs;
}();

// 确保页面加载完成后执行
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', function() {
        var fu = new FetchUserjs();
        fu.render();
    });
} else {
    var fu = new FetchUserjs();
    fu.render();
}

})();