海角天涯-解锁海角社区资源

无限制解锁收费资源,包括钻石贴、金币贴,下载视频,复制视频链接,自动展开帖子

// ==UserScript==
// @name         海角天涯-解锁海角社区资源
// @namespace    tianya365.top
// @homepage     https://vip.tianya365.top
// @version      2.1.0
// @description  无限制解锁收费资源,包括钻石贴、金币贴,下载视频,复制视频链接,自动展开帖子
// @icon         data:image/vnd.microsoft.icon;base64,iVBORw0KGgoAAAANSUhEUgAAAEoAAABKCAYAAAAc0MJxAAAKSUlEQVR4Xu2cCZQU1RVA7x8G2VE2WWUbMSiCBDQqiAYVUAkIohIwyCaYnATZHAYwsgnICLLlIMQIRiISECTsgsMSRDGAsguMgkQWCWgiqzow/XPe/OlUdXdNdxXUBKH7nTMHqv5+6/3/33u/uhTRJFWnoGip4D4UtdBUUYoSUctcJolacwrFITSfaUUGAZYxVu3Lq/vKMSFVpyQlMULDLxUkXSZjv6huak22UswOBBjmBCwSVJp+XMHrCopeVMuXaWENZ3Q2nRinFtiHEApqgO6vYKxSOGvaZTp4r93WENABnmWsmhAsawEZoNsoxfx4mWqx4OXA0rTjJfU3yWtApeoUlcRWBcVjVRBP6RpO6SzqM0HtzwGVlKZnAR3jCYKHsc4MpKvOiv66mkpGiMXF7uYBUE5W2Q11FtcrUnXvpCQmeq0gnvIHAjyj1AC9VCkeiqeBex2r1ixSKk3vVlDba+F4yq9hj4A6oaBkPA3c61g1nFRJaVp7LRiP+ROgXD71BKgEKJcEXGZLaFQClEsCLrPlm0Yt6wqbDsGkD+DfZ1325kecLV9AtawNCzuDUnDie5i/A0athgP/+RGTiNE1T6DKFYM/PGwA2GXqBli737rzTid4uE5onknr4cU15l54+bz6KM0cPyOBoUsP2BOo6qVgX1pkp7vPgz9vNvd/Ug529oOkMJjZAbiQ8VZ7EY6eusxAVb0GvhgYHdSoFjCwqX8DqzQS/nXav/outCZPGpUXqKfmweuboVQRODAIil91od2JLFdxJBy70kB1vw1ebecfJKmpwgtmnbrU4ptG/eUTszbVKmsNSdzt9z6DwycjhylpTmtWuIvefwmczrrUmMATqNJFYVzL3E7bBirTLjkJMnqE7mgnv4ca6fDtd/4NtHAyjH7AtCNQZUfM+RdY8zm8m+lfW/aaPIGK1oVl3aDFDaE5vjsHe45HlnI6NAzfJRfshBGrIss+8VOY2T7yvgB7YDrsOgpnz0FWNpzLhuwL2WodBuoLqJQysKMvFEr272lO3wg934msb8Zj0Llh9HaCmiaQzgcMMAGXA++89f8+i2FNnm8bhLbhC6iyRWFia3isLiQX8AfW9E3Qc35oXTK9vxwE5X16TWTwu5C+1l1/PYESy7xvkzDSwNztsOUI3FoFpj8KN1dw13i0XDM2QY8wUM1qwfJu7i37WL148xPoPDdWLpPuCdSN15qdLVw6z4E3t5i7w5rB8/dZOUTtW0yHrPPWvZvKg/zN3ZbbCQVrn4aCNm10AjWyBQwKM2Z3HAXZcZ2kaEEYcn+klxDMu+4LaPrHfABVuxzs6u8NlKwLpYbC9+eh713Q43a4oaxxS6qMtuo6OzJ0jQsHJRtA5gCoWTq0/ZGrYOh7zoPteiu89qhz2spMENfriIPp4lTCk0aJH/dpDFBDm8GQMI0qNQxkB5zUGn7XyHRDdqkaY+DQCXMdC1SDSrCxV+i0kzrqvAyZXzvDmPsEtKsbmiaaPXqNWZvkIboVf0DNhfVfGAh3VoM7qlrNy67T8S3TqTZ1oMutVppEFP4uUQcFczqGTr09x2D1PliyG1ZkQu/GML5V6LAEcpOpzkMtUhA294KiNnfqTBaIASv1iYhWu4XlC6guc2HfN/D+b9w+H/f5hqyE0athax9/Ngl7y794HZbvddcXT6AqlYSJrYzrYXc1pmwACaPkFyjZnfY7RC3cDTHvXGnLYNw6d7V4AhWtykbV8g+UuEgyjfyyn4LjmPkxdH07H0F1rA/1KoIYhZ/lLqSyNq13mHqiebI2BCUvj0JCM06RT5l6EkaufS2s7gElCkORZCuvhGDsRuNd1aHtzVZ7AmPbV+a6ytWhduDGg3DnlHwE9d5TcO/1Zrp9cACmfWRCwdcWh1/fYf6CInZU+RfgbJQIgMA7OSLUPFi4C8RyPnbGOpxoUBnqV4KpbSwPQBb0mmOs9lrfBPM6Wdd9F8OUD8219O/gYAuylJWd102o2fPUK3YVHH4OShQKfRIjMmB4hjHwht4fCqr0MOOoRpNw8yDatPh2uNW+aKx95xKtvMpmuJ4Pc4wlLai5YrKUGQY/uDATPINqmgKiUfZpIk+k8SsgqhwNlGzZMm3vqQkNK0PdCdbT9ALq0GCo6MP7NwL55vHOEY7wh+oZ1Ctt4enbQ6uReNN1o43WiPsibox96pUZbtapEc3huXtNinRS4P7joLn2Amr3s8a690NkMRftjSWeQe3qZxZWu4hT3OEtcycclBicMvUE1OP1YLbtldrnVxgr2SuoTb1A1qugvL0dvrEdsjavBTXLWA9k1hYrSnpLRWMUB+XldTBgWSxMHp3i8sVNmCM8lCIeuNg6TqBkwZ+43qwjZYpCT5s2SsRBfC6R/nebKGlQtn8FUz+Cjw/B1iOhAbg1PeHumlbe5q/Bqs+ta4mApv3cAtVwsrXzhQf+5u2A9vJOdAzxpFGp98CYByNrrD3OMhPCNSpWB2KlyxQVbRF3ZudR4/IMvjc0mmqPXkh98jCmtrVqFm0XrRepVwG29LHSZOo3cmEieAK1qAvIcbld9h43jmnQPvIblBNIgWffTMT0sO9csrPJ7hwUe7qEnK8ubKWJv1d5VKzH5WHqSazoq9+bszu7vJABwzKsO/8PULGH5T6HLA3lRph3JKKJa41qdSMseDLSem7zBizebTUhGidGn12c3hINt9C73Ra6Rn3+NWw+DBJVrVjCmAMlC0GBfPjZQLM/mantCyg5pgoPA4tKy0mul3M3UXsnd2VvKshRVFBkp3pyTmjXBVSN0tCvCfyqgZW27QgsDzum6tIQKuTG1n84D+K4Bw3T+1Lgtuus8qlLYfz7PoHa0tv4d3ZZ+Ck8MtO9mkvOya3ht7nBu2glnUAF80vcS4KAQfnwADSZFlrbWx2g/S3mnrhR8rJHr8YgUdo65eGGclZ+2ZUlTuWLRontJNNPtldpTNas596FMS5PMYKd8AOUABAQQZEwc+mhoQu6PXYvU7/pq+aUyOkhSey+w2yfQAWrkV1D1L9TA/jrVnfmv70LfoASN0pOpe1SfyLIQUNQevwMpj1iXfdeZA4ZJoRFSSVHzgnSZJ9BeZtokbmDoGJ57LO3Rq5RwdpkcX/mLihW0JgBJQubNWbDP632ZHrJSyNBkeiGuFrPNI7sk7he4etheC7Xu97FArrcyydAuXyCCVAJUC4JuMyW0KgEKJcEXGZLaFQClEsCLrMlfirrAlTOT2VVmt6rIOztSxel4yiLhkwBtUJB8zgat+ehaliZ+ECEC2yBAH0UA3V1FWB/vH8KKS9eWqN1NjWCH7GZDnRzATces8wIpKvu5t34fvo6lcx2pbgmHknkqU1wQp+jLuPVQetHBGn6QQVLEl/9MdhyvvKjaEW6Wi7XkZ9uU7wU77Byv0bWl5fU/+KekT9LeVa3VQV4Q3FlfEbS61Ki4bSWj46lq8X2ss4f/UvTVZNglBSIF+3K/bzkrAA8T7r6MiIUHJW4fLA0iYeU5v4r+oOlsArN0mgfLP0vox/zX2L4nPIAAAAASUVORK5CYII=
// @author       tianya365.top
// @exclude      https://*.tianya365.top/*
// @include      https://*.*/*
// @connect      *
// @run-at       document-start
// @grant        none
// @antifeature  payment
// @charset      UTF-8
// ==/UserScript==

(function () {
    'use strict';


    const CONFIG = {
        VERSION: '2.1.0',
        DEFAULT_SERVER: 'https://vip.tianya365.top',
        STORAGE_KEYS: {
            SERVER: 'hjty_server',
            USER_TOKEN: 'hjty_user_token',
            USER_NAME: 'hjty_user_name'
        },
        SELECTORS: {
            TOOLBAR_CONTAINER: '.hjty-toolbar-container',
            UNLOCK_BTN: '.hjty-unlock-btn',
            SETTINGS_BTN: '.hjty-settings-btn',
            USER_BTN: '.hjty-user-btn',
            TOGGLE_BTN: '.hjty-toggle-btn'
        },
        MODAL_IDS: {
            LOADING: 'hjty-loading-modal',
            LOGIN: 'hjty-login-modal',
            SERVER: 'hjty-server-modal',
            USER_INFO: 'hjty-user-info-modal',
            LOGOUT_CONFIRM: 'hjty-logout-confirm-modal',
            UPDATE_CONFIRM: 'hjty-update-confirm-modal'
        }
    };

    let topic = null;
    let newVersion = '';
    let m3u8_url = '';
    let play_url = '';
    let shortVideoUrl = '';
    let freeToken = window.localStorage.getItem('hjty_free_token');
    let video = null;
    let hasPic = false;
    let server = localStorage.getItem(CONFIG.STORAGE_KEYS.SERVER) || CONFIG.DEFAULT_SERVER;


    let toolbarCollapsed = localStorage.getItem('hjty_toolbar_collapsed') === 'true';


    if (!localStorage.getItem(CONFIG.STORAGE_KEYS.SERVER)) {
        localStorage.setItem(CONFIG.STORAGE_KEYS.SERVER, server);
    }

    if (freeToken == null) {
        freeToken = '7a78a8bf4bd2432f93a301bec4a17cf7'
        window.localStorage.setItem('hjty_free_token', freeToken);
    }


    const Utils = {

        debounce(func, wait, immediate = false) {
            let timeout;
            return function executedFunction(...args) {
                const later = () => {
                    timeout = null;
                    if (!immediate) func.apply(this, args);
                };
                const callNow = immediate && !timeout;
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
                if (callNow) func.apply(this, args);
            };
        },

        base64: {
            encode: function (str) {
                try {
                    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
                        return String.fromCharCode(parseInt(p1, 16));
                    }));
                } catch (error) {
                    return '';
                }
            },

            decode: function (base64Str) {
                try {
                    return decodeURIComponent(Array.prototype.map.call(atob(base64Str), function (c) {
                        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
                    }).join(''));
                } catch (error) {
                    return '';
                }
            }
        },


        getUserToken() {
            return localStorage.getItem(CONFIG.STORAGE_KEYS.USER_TOKEN);
        },


        getCookieValue(name) {
            const match = document.cookie.match(new RegExp(name + '=([^;]+)'));
            return match ? match[1] : null;
        },


        checkLoginStatus() {
            return !!this.getUserToken();
        },


        getPid() {
            if (/\/post\/details.*pid=\d+/.test(location.href)) {
                const match = location.href.match(/\/post\/details.*pid=(\d+)/i);
                return match ? match[1] : null;
            }
            return null;
        },


        deleteCookie(name) {
            document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
        },

        decrypt(data) {
            return JSON.parse(this.base64.decode(this.base64.decode(this.base64.decode(data))));
        },

        encrypt(data) {
            return this.base64.encode(this.base64.encode(this.base64.encode(JSON.stringify(data))))
        },


        async copyText(text) {
            try {
                if (navigator.clipboard && window.isSecureContext) {
                    await navigator.clipboard.writeText(text);
                    return true;
                } else {

                    const textArea = document.createElement('textarea');
                    textArea.value = text;
                    textArea.style.position = 'fixed';
                    textArea.style.opacity = '0';
                    document.body.appendChild(textArea);
                    textArea.focus();
                    textArea.select();
                    const success = document.execCommand('copy');
                    document.body.removeChild(textArea);
                    return success;
                }
            } catch (error) {
                return false;
            }
        },


        smoothScrollTo(element, offset = 0) {
            if (!element) return;


            if (this.isMobile()) {
                this.mobileScrollTo(element, offset);
            } else {

                this.tryMultipleScrollMethods(element, offset);
            }
        },


        isMobile() {
            return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
                window.innerWidth <= 768;
        },


        mobileScrollTo(element, offset = 0) {
            try {

                element.scrollIntoView({
                    behavior: 'smooth',
                    block: 'start',
                    inline: 'nearest'
                });


                if (offset !== 0) {
                    setTimeout(() => {
                        const currentPos = this.getScrollTop();
                        const targetPos = currentPos + offset;


                        window.scrollTo({
                            top: targetPos,
                            behavior: 'smooth'
                        });
                    }, 300);
                }
            } catch (error) {

                const targetPosition = element.getBoundingClientRect().top + this.getScrollTop() + offset;
                this.animateScrollTo(targetPosition);
            }
        },


        tryMultipleScrollMethods(element, offset = 0) {
            const targetPosition = element.getBoundingClientRect().top + this.getScrollTop() + offset;


            if (this.tryNativeScroll(targetPosition)) {
                return;
            }


            if (this.tryScrollContainer(targetPosition)) {
                return;
            }


            this.animateScrollTo(targetPosition);
        },


        getScrollTop() {
            return window.pageYOffset ||
                document.documentElement.scrollTop ||
                document.body.scrollTop || 0;
        },


        tryNativeScroll(targetPosition) {
            try {

                window.scrollTo({
                    top: targetPosition,
                    behavior: 'smooth'
                });


                return new Promise(resolve => {
                    const startPos = this.getScrollTop();
                    setTimeout(() => {
                        const currentPos = this.getScrollTop();
                        resolve(Math.abs(currentPos - startPos) > 5);
                    }, 100);
                });
            } catch (error) {
                return false;
            }
        },


        tryScrollContainer(targetPosition) {

            const containerSelectors = [
                'body',
                'html',
                '.app',
                '.main',
                '.container',
                '#app',
                '[data-scroll]',
                '.scroll-container'
            ];

            for (const selector of containerSelectors) {
                const container = document.querySelector(selector);
                if (container && this.tryScrollElement(container, targetPosition)) {
                    return true;
                }
            }
            return false;
        },


        tryScrollElement(element, targetPosition) {
            try {
                if (element.scrollTo) {
                    element.scrollTo({
                        top: targetPosition,
                        behavior: 'smooth'
                    });
                    return true;
                } else if (element.scrollTop !== undefined) {

                    this.animateElementScroll(element, targetPosition);
                    return true;
                }
            } catch (error) {

            }
            return false;
        },


        animateElementScroll(element, targetPosition, duration = 500) {
            const startPosition = element.scrollTop || 0;
            const distance = targetPosition - startPosition;
            let startTime = null;

            function animation(currentTime) {
                if (startTime === null) startTime = currentTime;
                const timeElapsed = currentTime - startTime;
                const progress = Math.min(timeElapsed / duration, 1);


                const ease = progress < 0.5
                    ? 2 * progress * progress
                    : 1 - Math.pow(-2 * progress + 2, 2) / 2;

                element.scrollTop = startPosition + distance * ease;

                if (timeElapsed < duration) {
                    requestAnimationFrame(animation);
                }
            }

            requestAnimationFrame(animation);
        },


        animateScrollTo(targetPosition, duration = 500) {
            const startPosition = this.getScrollTop();
            const distance = targetPosition - startPosition;
            let startTime = null;

            const animation = (currentTime) => {
                if (startTime === null) startTime = currentTime;
                const timeElapsed = currentTime - startTime;
                const progress = Math.min(timeElapsed / duration, 1);


                const ease = progress < 0.5
                    ? 2 * progress * progress
                    : 1 - Math.pow(-2 * progress + 2, 2) / 2;

                const currentPosition = startPosition + distance * ease;


                try {
                    window.scrollTo(0, currentPosition);
                } catch (e) {

                    document.documentElement.scrollTop = currentPosition;
                    document.body.scrollTop = currentPosition;
                }

                if (timeElapsed < duration) {
                    requestAnimationFrame(animation);
                }
            };

            requestAnimationFrame(animation);
        },


        imageDecode(t) {
            const e = "ABCD*EFGHIJKLMNOPQRSTUVWX#YZabcdefghijklmnopqrstuvwxyz1234567890";
            let o, i, a, r, s, c, u, l = "", d = 0;

            function n(e) {
                let t, n = "", o = 0, i = 0, a = 0;
                while (o < e.length)
                    i = e.charCodeAt(o),
                        i < 128 ? (n += String.fromCharCode(i),
                            o++) : i > 191 && i < 224 ? (a = e.charCodeAt(o + 1),
                            n += String.fromCharCode((31 & i) << 6 | 63 & a),
                            o += 2) : (a = e.charCodeAt(o + 1),
                            t = e.charCodeAt(o + 2),
                            n += String.fromCharCode((15 & i) << 12 | (63 & a) << 6 | 63 & t),
                            o += 3);
                return n
            }

            t = t.replace(/[^A-Za-z0-9*#]/g, "");
            while (d < t.length)
                r = e.indexOf(t.charAt(d++)),
                    s = e.indexOf(t.charAt(d++)),
                    c = e.indexOf(t.charAt(d++)),
                    u = e.indexOf(t.charAt(d++)),
                    o = r << 2 | s >> 4,
                    i = (15 & s) << 4 | c >> 2,
                    a = (3 & c) << 6 | u,
                    l += String.fromCharCode(o),
                64 !== c && (l += String.fromCharCode(i)),
                64 !== u && (l += String.fromCharCode(a));

            let reg = new RegExp('', "g");
            l = l.replace(reg, '');
            return l = n(l),
                l
        }
    };


    const UI = {

        showToast(message, type = 'info') {

            const existingToast = document.getElementById('hjty-toast');
            if (existingToast) {
                existingToast.remove();
            }


            const icons = {
                success: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                    <path d="M9 12L11 14L15 10" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                    <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
                </svg>`,
                error: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                    <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
                    <line x1="15" y1="9" x2="9" y2="15" stroke="currentColor" stroke-width="2"/>
                    <line x1="9" y1="9" x2="15" y2="15" stroke="currentColor" stroke-width="2"/>
                </svg>`,
                warning: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                    <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" stroke="currentColor" stroke-width="2"/>
                    <line x1="12" y1="9" x2="12" y2="13" stroke="currentColor" stroke-width="2"/>
                    <line x1="12" y1="17" x2="12.01" y2="17" stroke="currentColor" stroke-width="2"/>
                </svg>`,
                info: `<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
                    <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
                    <path d="M12 16V12" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
                    <path d="M12 8H12.01" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
                </svg>`
            };

            const toast = document.createElement('div');
            toast.id = 'hjty-toast';
            toast.className = `hjty-toast hjty-toast-${type}`;
            toast.innerHTML = `
                <div class="hjty-toast-icon">${icons[type] || icons.info}</div>
                <div class="hjty-toast-message">${message}</div>
            `;

            document.body.appendChild(toast);


            setTimeout(() => toast.classList.add('hjty-toast-show'), 10);


            setTimeout(() => {
                toast.classList.remove('hjty-toast-show');
                setTimeout(() => toast.remove(), 300);
            }, 3000);
        },


        showLoadingModal(message = '加载中...', showCloseBtn = true, onClose = null) {

            const existingModal = document.getElementById(CONFIG.MODAL_IDS.LOADING);
            if (existingModal) {
                existingModal.remove();
            }

            const loadingModal = document.createElement('div');
            loadingModal.id = CONFIG.MODAL_IDS.LOADING;
            loadingModal.className = 'hjty-modal-overlay hjty-loading-overlay';

            if (onClose && typeof onClose === 'function') {
                loadingModal._onCloseCallback = onClose;
            }

            const closeButtonHtml = showCloseBtn ?
                '<button class="hjty-modal-close hjty-loading-close" title="关闭">×</button>' : '';

            loadingModal.innerHTML = `
                <div class="hjty-modal-content hjty-loading-content">
                    <div class="hjty-loading-header">${closeButtonHtml}</div>
                    <div class="hjty-loading-body">
                        <div class="hjty-loading-spinner">
                            <div class="hjty-spinner-ring"></div>
                        </div>
                        <p class="hjty-loading-message">${message}</p>
                    </div>
                </div>
            `;

            document.body.appendChild(loadingModal);


            if (showCloseBtn) {
                const closeBtn = loadingModal.querySelector('.hjty-loading-close');
                closeBtn.addEventListener('click', () => this.hideLoadingModal());
            }


            loadingModal.addEventListener('click', (e) => {

                if (e.target === loadingModal) {
                    e.preventDefault();
                    e.stopPropagation();
                }
            });

            return loadingModal;
        },


        hideLoadingModal(executeCallback = true) {
            const loadingModal = document.getElementById(CONFIG.MODAL_IDS.LOADING);
            if (loadingModal) {
                if (executeCallback && loadingModal._onCloseCallback) {
                    try {
                        loadingModal._onCloseCallback();
                    } catch (error) { }
                }
                loadingModal.remove();
            }
        },


        showActions(title = '操作选项', actions = [], onAction = null) {

            const existingDrawer = document.getElementById('hjty-action-drawer');
            if (existingDrawer) {
                existingDrawer.remove();
            }

            const drawer = document.createElement('div');
            drawer.id = 'hjty-action-drawer';
            drawer.className = 'hjty-action-drawer-overlay';

            const actionsHtml = actions.map(action => `
                <div class="hjty-action-item" data-key="${action.key || ''}" data-url="${action.url || ''}">
                    <div class="hjty-action-content">
                        <div class="hjty-action-name">${action.name || ''}</div>
                        ${action.subname ? `<div class="hjty-action-subname">${action.subname}</div>` : ''}
                    </div>
                    <div class="hjty-action-arrow">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none">
                            <path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                        </svg>
                    </div>
                </div>
            `).join('');

            drawer.innerHTML = `
                <div class="hjty-action-drawer">
                    <div class="hjty-action-header">
                        <h3 class="hjty-action-title">${title}</h3>
                    </div>
                    <div class="hjty-action-list">
                        ${actionsHtml}
                    </div>
                    <div class="hjty-action-footer">
                        <button class="hjty-action-close-btn">关闭</button>
                    </div>
                </div>
            `;

            document.body.appendChild(drawer);


            const actionItems = drawer.querySelectorAll('.hjty-action-item');
            const closeBtn = drawer.querySelector('.hjty-action-close-btn');

            actionItems.forEach(item => {
                item.addEventListener('click', () => {
                    if (onAction && typeof onAction === 'function') {
                        onAction(item.dataset);
                    }
                });
            });

            closeBtn.addEventListener('click', () => this.hideActions());


            drawer.addEventListener('click', (e) => {
                if (e.target === drawer) this.hideActions();
            });


            setTimeout(() => drawer.classList.add('hjty-action-drawer-show'), 10);

            return drawer;
        },


        hideActions() {
            const drawer = document.getElementById('hjty-action-drawer');
            if (drawer) {
                drawer.classList.remove('hjty-action-drawer-show');
                setTimeout(() => drawer.remove(), 300);
            }
        },


        showPlayer(src = '') {

            const existingPlayer = document.getElementById('hjty-player-modal');
            if (existingPlayer) {
                existingPlayer.remove();
            }

            const playerModal = document.createElement('div');
            playerModal.id = 'hjty-player-modal';
            playerModal.className = 'hjty-player-modal-overlay';

            playerModal.innerHTML = `
                <div class="hjty-player-modal-content">
                    <div class="hjty-player-header">
                        <button class="hjty-player-close" title="关闭播放器">×</button>
                    </div>
                    <div class="hjty-player-body">
                        <div id="hjty-play-box">
                            <iframe style="display:block;border:0;width: 100%;height: 500px" allow="autoplay; encrypted-media" allowfullscreen src="${src}"></iframe>
                        </div>
                    </div>
                </div>
            `;

            document.body.appendChild(playerModal);


            const closeBtn = playerModal.querySelector('.hjty-player-close');
            closeBtn.addEventListener('click', () => this.hidePlayer());


            playerModal.addEventListener('click', (e) => {
                if (e.target === playerModal) this.hidePlayer();
            });


            const handleEscKey = (e) => {
                if (e.key === 'Escape') {
                    this.hidePlayer();
                    document.removeEventListener('keydown', handleEscKey);
                }
            };
            document.addEventListener('keydown', handleEscKey);


            setTimeout(() => playerModal.classList.add('hjty-player-modal-show'), 10);

            return playerModal;
        },


        hidePlayer() {
            const playerModal = document.getElementById('hjty-player-modal');
            if (playerModal) {
                playerModal.classList.remove('hjty-player-modal-show');
                setTimeout(() => playerModal.remove(), 300);
            }
        }
    };


    const App = {

        getTopic(pid) {
            return new Promise(async (resolve, reject) => {
                try {
                    const response = await fetch(`/api/topic/${pid}`, {
                        method: 'GET',
                        headers: {
                            'Content-Type': 'application/json'
                        }
                    });

                    if (!response.ok) {
                        throw new Error(`HTTP ${response.status}`);
                    }

                    const res = await response.json();

                    if (res.isEncrypted) {
                        topic = Utils.decrypt(res.data)
                    } else {
                        topic = res.data;
                    }

                    resolve(topic);
                } catch (error) {
                    reject('网络错误: 3');
                }
            });
        },

        showTopic(data, pid) {
            if (!data['attachments']) {
                UI.showToast('没有可解锁的内容', 'warning'); return;
            }

            this.getAttachments(data).then(html => {
                if (html) {
                    const sellBtn = document.querySelector('.sell-btn');
                    const hjsellContainer = document.getElementById('hjsell-container');

                    if (sellBtn) {

                        const newContainer = document.createElement('div');
                        newContainer.id = 'hjsell-container';
                        newContainer.className = 'hjsell-container';
                        newContainer.innerHTML = '<div class="hssell-content">' + html + '</div>';


                        sellBtn.parentNode.replaceChild(newContainer, sellBtn);
                    } else if (hjsellContainer) {

                        const contentElement = hjsellContainer.querySelector('.hssell-content');
                        if (contentElement) {
                            contentElement.innerHTML = html;
                        }
                    }


                    const finalContainer = document.getElementById('hjsell-container');
                    if (!finalContainer) {
                        UI.showToast('请等待页面加载完成!', 'error');
                        return;
                    }


                    Utils.smoothScrollTo(finalContainer, -100);

                    if (hasPic) {
                        this.showImages();
                    }
                }

                if (video !== null) {
                    if (!data['sale'] || data['sale']['money_type'] === 0 || data['sale']['is_buy']) {
                        this.getVideo(video, pid);
                    } else {
                        this.queryTopic(pid);
                    }
                } else {
                    UI.showToast('解锁成功', 'success');
                    UI.hideLoadingModal(false)
                }
            })
        },

        queryTopic(pid) {
            fetch(server + '/api/topic/' + pid + '?v=' + CONFIG.VERSION, {
                method: 'GET',
                headers: {
                    'token': Utils.getUserToken(),
                    'Content-Type': 'application/json'
                }
            })
                .then(response => {
                    if (!response.ok) {
                        throw new Error(`HTTP ${response.status}`);
                    }
                    return response.json();
                })
                .then(data => {
                    UI.hideLoadingModal(false)
                    if (data.code) {
                        if (data.msg === '有新版本') {
                            newVersion = data.data;
                            this.showUpdateConfirm();
                            return;
                        }

                        if (data.data['m3u8_url'] !== '') {
                            m3u8_url = server + data.data['m3u8_url'];
                            play_url = server + '/play?url=' + Utils.base64.encode(m3u8_url);
                            this.showVideoActions();
                        } else {
                            UI.showToast('没有可解锁的内容', 'error');
                        }
                    } else {
                        UI.showToast(data.msg, 'error');
                        if (data.data['confirmButtonText'] === '重新登录') {
                            localStorage.removeItem(CONFIG.STORAGE_KEYS.USER_TOKEN);
                            localStorage.removeItem(CONFIG.STORAGE_KEYS.USER_NAME);
                            this.updateToolbarButtons(false);
                            showLoginModal();
                        } else if (data.data['confirmButtonText'] === '打开官网') {
                            setTimeout(() => {
                                window.open(server + '/');
                            }, 1500)
                        }
                    }
                })
                .catch(error => { });
        },

        getVideo(item, pid) {
            if (item.remoteUrl.includes('haijiao.live')) {
                m3u8_url = item.remoteUrl;
                play_url = server + '/play?url=' + Utils.base64.encode(item.remoteUrl);
                this.showVideoActions()
                UI.hideLoadingModal(false)
            } else {

                const uid = Utils.getCookieValue('uid');
                const token = Utils.getCookieValue('token');


                const xhr = new XMLHttpRequest();
                xhr.open('POST', '/api/attachment', true);
                xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
                xhr.setRequestHeader('Mver', '211112203214');
                xhr.setRequestHeader('X-User-Id', uid && token ? uid : '172561377002');
                xhr.setRequestHeader('X-User-Token', uid && token ? token : freeToken);

                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        if (xhr.status === 200) {
                            try {
                                const res = JSON.parse(xhr.responseText);

                                let data = {};
                                if (res.isEncrypted) {
                                    data = Utils.decrypt(res.data)
                                } else {
                                    data = res.data;
                                }


                                if (!data.remoteUrl.startsWith('http')) {
                                    m3u8_url = play_url = window.location.origin + data.remoteUrl;
                                } else {
                                    m3u8_url = play_url = data.remoteUrl;
                                }


                                play_url = server + '/play?url=' + btoa(play_url);

                                App.showVideoActions();

                                UI.hideLoadingModal(false);
                            } catch (error) {

                                const accXhr = new XMLHttpRequest();
                                accXhr.open('GET', server + '/acc', true);

                                accXhr.onreadystatechange = function () {
                                    if (accXhr.readyState === 4) {
                                        if (accXhr.status === 200) {
                                            try {
                                                const accRes = JSON.parse(accXhr.responseText);

                                                if (accRes.code) {
                                                    freeToken = accRes.data;
                                                    localStorage.setItem('hjty_free_token', freeToken);
                                                    UI.showToast('网络错误: 请重试', 'error');
                                                } else {
                                                    UI.showToast('网络错误: 2', 'error');
                                                }
                                            } catch (error) {
                                                UI.showToast('网络错误: 2', 'error');
                                            }
                                        } else {
                                            UI.showToast('网络错误: 2', 'error');
                                        }
                                    }


                                    UI.hideLoadingModal(false);
                                };

                                accXhr.onerror = function () {
                                    UI.showToast('网络错误: 2', 'error');


                                    UI.hideLoadingModal(false);
                                };

                                accXhr.send();
                            }
                        } else {
                            UI.showToast('网络错误: 2', 'error');

                            UI.hideLoadingModal(false);
                        }
                    }
                };

                xhr.onerror = function () {
                    UI.showToast('网络连接失败', 'error');
                };


                xhr.send(JSON.stringify({
                    id: item.id,
                    is_ios: 0,
                    resource_id: parseInt(pid),
                    resource_type: 'topic',
                    line: 'normal1'
                }));
            }
        },

        showImages() {
            document.querySelectorAll('#hjsell-container img').forEach(async img => {
                try {
                    const response = await fetch(img.dataset.url);

                    if (!response.ok) {
                        throw new Error(`HTTP ${response.status}`);
                    }

                    const data = await response.text();
                    img.src = Utils.imageDecode(data);
                } catch (error) { }
            });
        },


        showVideoActions() {
            const actions = [
                {
                    name: '播放视频(站内)',
                    key: 'play',
                    subname: '如无法在线播放,可尝试其他在线播放器,或下载后再观看'
                },
                {
                    name: '复制视频地址',
                    key: 'copy',
                    subname: '可复制视频地址到其他地方播放或下载'
                },
                {
                    name: '在线播放器1',
                    key: 'open',
                    subname: '可正常播放',
                    url: 'https://www.m3u8player.online/m3u8?url=' + encodeURIComponent(m3u8_url)
                },
                {
                    name: '在线播放器2',
                    key: 'open',
                    subname: '不支持播放收费视频',
                    url: 'https://m3u8player.org/player.html?url=' + m3u8_url
                },
                {
                    name: '在线播放器3',
                    key: 'open',
                    subname: '不支持播放收费视频',
                    url: 'https://m3u8play.dev/?url=' + m3u8_url
                },
                {
                    name: '视频下载通道1',
                    key: 'open',
                    subname: '【推荐】支持自动下载和在线播放',
                    url: 'https://getm3u8.com/?source=' + m3u8_url + (m3u8_url.includes('?') ? '&' : '?') + 'title=' + topic.title
                },
                {
                    name: '视频下载通道2',
                    key: 'open',
                    subname: '推荐在电脑端操作',
                    url: 'https://blog.luckly-mjw.cn/tool-show/m3u8-downloader/index.html?source=' + m3u8_url + (m3u8_url.includes('?') ? '&' : '?') + 'title=' + topic.title
                },
                {
                    name: '视频下载通道3',
                    key: 'open',
                    subname: '需要手动点击下载,推荐在电脑端操作',
                    url: 'https://tools.thatwind.com/tool/m3u8downloader#m3u8=' + encodeURIComponent(m3u8_url)
                },
                {
                    name: '海角天涯官网',
                    key: 'open',
                    subname: '点击访问',
                    url: server + '/'
                }
            ];

            UI.showActions('帖子解锁成功,下滑查看更多操作', actions, (item) => {
                this.handleVideoAction(item)
            });
        },


        handleVideoAction(item) {
            switch (item.key) {
                case 'play':

                    UI.showPlayer(play_url);
                    UI.showToast('视频加载中,请稍后...', 'info');
                    break;

                case 'copy':

                    Utils.copyText(m3u8_url).then(success => {
                        if (success) {
                            UI.showToast('视频地址已复制', 'success');
                        } else {
                            UI.showToast('复制失败', 'error');
                        }
                    });
                    break;

                case 'open':

                    if (item.url) {
                        UI.showToast('正在打开链接...', 'info');
                        setTimeout(() => {
                            window.open(item.url, '_blank');
                        }, 500);
                    }
                    break;

                default:
                    console.log('未知操作:', key);
            }
        },

        getAttachments(data) {
            return new Promise((resolve, reject) => {
                let html = '';

                if (!data || !data.attachments) {
                    resolve(html);
                    return;
                }

                data.attachments.forEach(item => {
                    switch (item.category) {
                        case 'video':
                            video = item;
                            break;
                        case 'audio':
                            html += '<p style="text-align: center"><audio src="' + item.remoteUrl + '" controls="true" id="showaudio"></audio></p>';
                            break;
                        case 'images':
                            hasPic = true;
                            if (!data.content.includes(item.remoteUrl)) {
                                html += '<p><img data-url="' + item.remoteUrl + '" src="/images/common/project/loading.gif" alt="" data-id="' + item.id + '" lazy="loaded"></p>';
                            }
                            break;
                    }
                });

                resolve(html);
            });
        },


        async checkUpdate() {
            const updateUrl = `${server}/api/update?v=${CONFIG.VERSION}`;
            const token = Utils.getUserToken();

            try {
                const response = await fetch(updateUrl, {
                    method: 'GET',
                    headers: {
                        'token': token,
                        'Content-Type': 'application/json'
                    }
                });

                const data = await response.json();
                if (data.msg === '有新版本') {
                    newVersion = data.data;
                    this.showUpdateConfirm();
                }
            } catch (error) {
                UI.showToast('检查更新失败,请切换其他服务器', 'error');
            }
        },


        showUpdateConfirm() {
            const updateModal = document.createElement('div');
            updateModal.id = CONFIG.MODAL_IDS.UPDATE_CONFIRM;
            updateModal.className = 'hjty-modal-overlay';
            updateModal.innerHTML = `
                <div class="hjty-modal-content hjty-update-content">
                    <div class="hjty-modal-header">
                        <h3>脚本升级</h3>
                        <button class="hjty-modal-close" onclick="this.closest('.hjty-modal-overlay').remove()">×</button>
                    </div>
                    <div class="hjty-modal-body">
                        <div class="hjty-update-info">
                            <div class="hjty-update-icon">
                                <svg width="48" height="48" viewBox="0 0 24 24" fill="none">
                                    <circle cx="12" cy="12" r="10" stroke="#3b82f6" stroke-width="2"/>
                                    <path d="M8 12L12 8L16 12" stroke="#3b82f6" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                                    <path d="M12 8V16" stroke="#3b82f6" stroke-width="2" stroke-linecap="round"/>
                                    <path d="M16 16H8" stroke="#60a5fa" stroke-width="2" stroke-linecap="round"/>
                                </svg>
                            </div>
                            <p class="hjty-update-message">检测到新版本,请更新后再使用!</p>
                            <p class="hjty-update-details">当前版本: ${CONFIG.VERSION}</p>
                            ${newVersion ? `<p class="hjty-update-details">最新版本: ${newVersion}</p>` : ''}
                        </div>
                    </div>
                    <div class="hjty-modal-footer">
                        <button class="hjty-btn hjty-btn-primary hjty-confirm-update-btn">立即更新</button>
                    </div>
                </div>
            `;

            document.body.appendChild(updateModal);


            const confirmBtn = updateModal.querySelector('.hjty-confirm-update-btn');

            confirmBtn.addEventListener('click', () => {
                updateModal.remove();
                window.open(`${server}/js/script.user.js?v=${Math.random()}`, '_blank');
            });


            updateModal.addEventListener('click', (e) => {
                if (e.target === updateModal) updateModal.remove();
            });
        },


        logout() {
            localStorage.removeItem(CONFIG.STORAGE_KEYS.USER_TOKEN);
            localStorage.removeItem(CONFIG.STORAGE_KEYS.USER_NAME);
            this.updateToolbarButtons(false);
            UI.showToast('已退出登录', 'info');
        },


        updateToolbarButtons(isLoggedIn) {
            const toolbarContainer = document.querySelector(CONFIG.SELECTORS.TOOLBAR_CONTAINER);
            if (!toolbarContainer) return;

            let userBtn = toolbarContainer.querySelector(CONFIG.SELECTORS.USER_BTN);

            if (isLoggedIn) {
                if (!userBtn) {
                    userBtn = document.createElement('button');
                    userBtn.className = 'hjty-toolbar-btn hjty-user-btn';
                    userBtn.title = '用户信息';
                    userBtn.innerHTML = `
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none">
                            <path d="M20 21V19C20 17.9391 19.5786 16.9217 18.8284 16.1716C18.0783 15.4214 17.0609 15 16 15H8C6.93913 15 5.92172 15.4214 5.17157 16.1716C4.42143 16.9217 4 17.9391 4 19V21" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                            <circle cx="12" cy="7" r="4" stroke="currentColor" stroke-width="2"/>
                        </svg>
                    `;

                    userBtn.addEventListener('click', () => this.showUserInfoModal());

                    const unlockBtn = toolbarContainer.querySelector(CONFIG.SELECTORS.UNLOCK_BTN);
                    unlockBtn.insertAdjacentElement('afterend', userBtn);
                }
            } else {
                if (userBtn) userBtn.remove();
            }
        },


        showUserInfoModal() {
            const userName = localStorage.getItem(CONFIG.STORAGE_KEYS.USER_NAME) || '未知用户';

            const userModal = document.createElement('div');
            userModal.id = CONFIG.MODAL_IDS.USER_INFO;
            userModal.className = 'hjty-modal-overlay';
            userModal.innerHTML = `
                <div class="hjty-modal-content hjty-user-info-content">
                    <div class="hjty-modal-header">
                        <h3>用户信息</h3>
                        <button class="hjty-modal-close" onclick="this.closest('.hjty-modal-overlay').remove()">×</button>
                    </div>
                    <div class="hjty-modal-body">
                        <div class="hjty-user-info">
                            <div class="hjty-user-avatar">
                                <svg width="64" height="64" viewBox="0 0 24 24" fill="none">
                                    <circle cx="12" cy="12" r="10" fill="#8b5cf6" opacity="0.1"/>
                                    <path d="M18 19V17C18 15.3431 16.6569 14 15 14H9C7.34315 14 6 15.3431 6 17V19" stroke="#8b5cf6" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
                                    <circle cx="12" cy="8" r="3" stroke="#8b5cf6" stroke-width="1.8"/>
                                </svg>
                            </div>
                            <div class="hjty-user-details">
                                <p class="hjty-user-name">${userName}</p>
                                <p class="hjty-user-status">已登录</p>
                            </div>
                        </div>
                    </div>
                    <div class="hjty-modal-footer">
                        <button class="hjty-btn hjty-btn-secondary hjty-visit-website-btn">访问官网</button>
                        <button class="hjty-btn hjty-btn-danger hjty-logout-btn">退出登录</button>
                    </div>
                </div>
            `;

            document.body.appendChild(userModal);


            const visitWebsiteBtn = userModal.querySelector('.hjty-visit-website-btn');
            const logoutBtn = userModal.querySelector('.hjty-logout-btn');

            visitWebsiteBtn.addEventListener('click', () => window.open(server, '_blank'));
            logoutBtn.addEventListener('click', () => {
                userModal.remove();
                this.showLogoutConfirm();
            });


            userModal.addEventListener('click', (e) => {
                if (e.target === userModal) userModal.remove();
            });
        },


        showLogoutConfirm() {
            const confirmModal = document.createElement('div');
            confirmModal.id = CONFIG.MODAL_IDS.LOGOUT_CONFIRM;
            confirmModal.className = 'hjty-modal-overlay';
            confirmModal.innerHTML = `
                <div class="hjty-modal-content hjty-confirm-content">
                    <div class="hjty-modal-header">
                        <h3>确认退出</h3>
                        <button class="hjty-modal-close" onclick="this.closest('.hjty-modal-overlay').remove()">×</button>
                    </div>
                    <div class="hjty-modal-body">
                        <p class="hjty-confirm-message">确定要退出登录吗?</p>
                    </div>
                    <div class="hjty-modal-footer">
                        <button class="hjty-btn hjty-btn-secondary hjty-cancel-btn">取消</button>
                        <button class="hjty-btn hjty-btn-primary hjty-confirm-btn">确认退出</button>
                    </div>
                </div>
            `;

            document.body.appendChild(confirmModal);


            const cancelBtn = confirmModal.querySelector('.hjty-cancel-btn');
            const confirmBtn = confirmModal.querySelector('.hjty-confirm-btn');

            cancelBtn.addEventListener('click', () => confirmModal.remove());
            confirmBtn.addEventListener('click', () => {
                confirmModal.remove();
                this.logout();
            });


            confirmModal.addEventListener('click', (e) => {
                if (e.target === confirmModal) confirmModal.remove();
            });
        },

        formatTitle(data) {
            data.results.forEach(item => {
                const tips = [];
                tips.push('money_type' in item ? ['', '💰', '💎'][item.money_type] : '');
                item.hasVideo && tips.push('🎥');
                item.hasAudio && tips.push('🎵');
                item.title = `${tips.join(' ')} ${item.title}`;
            });
            return data;
        },

        getShortVideoUrl(responseText) {
            try {
                let res = JSON.parse(responseText);
                if (res['isEncrypted']) {
                    let data = Utils.decrypt(res.data);
                    if (data['category'] && data['category'] === 'video' && data['remoteUrl']) {
                        if (!data['remoteUrl'].startsWith('http')) {
                            shortVideoUrl = window.location.origin + data['remoteUrl'];
                        } else {
                            shortVideoUrl = data['remoteUrl'];
                        }
                    }
                }
            } catch (e) { }
        },

        fixShortVideo(responseText) {
            try {
                responseText = JSON.parse(responseText);
                let video = Utils.decrypt(responseText.data);
                video.type = 1;
                video.amount = 0;
                video.money_type = 0;
                video.vip = 0;
                video.message = '';
                responseText.data = Utils.encrypt(video);
                return JSON.stringify(responseText);
            } catch (e) {
                return responseText;
            }
        }
    };


    let buttonInitialized = false;

    function checkTitleAndInitButton() {
        if (buttonInitialized) return true;

        const currentTitle = document.title;
        if (currentTitle === "海角社区") {
            console.log('海角社区助手已启动,版本:', CONFIG.VERSION);
            buttonInitialized = true;
            start();
            return true;
        }
        return false;
    }

    function setupTitleObserver() {
        const titleObserver = new MutationObserver((mutations) => {
            if (!buttonInitialized && document.title === "海角社区") {
                buttonInitialized = true;
                console.log('海角社区助手已启动,版本:', CONFIG.VERSION);
                start();
                titleObserver.disconnect();
            }
        });

        const titleElement = document.querySelector('title');
        if (titleElement) {
            titleObserver.observe(titleElement, {
                childList: true,
                characterData: true,
                subtree: true
            });
        }

        let checkCount = 0;
        const maxChecks = 10;
        const checkInterval = setInterval(() => {
            if (buttonInitialized || checkCount >= maxChecks) {
                clearInterval(checkInterval);
                return;
            }

            if (checkTitleAndInitButton()) {
                buttonInitialized = true;
                clearInterval(checkInterval);
            }

            checkCount++;
        }, 1000);
    }

    function start() {
        initStyles();
        initFloatingButton();


        if (Utils.checkLoginStatus()) {
            App.checkUpdate();
        }
    }


    function initStyles() {
        if (document.getElementById('hjty-global-styles')) return;

        const style = document.createElement('style');
        style.id = 'hjty-global-styles';
        style.textContent = `
            /* 浮动工具栏样式 */
            #hjty-floating-toolbar {
                position: fixed;
                top: 50%;
                right: 20px;
                transform: translateY(-50%);
                z-index: 10000;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            }

            #hjty-floating-toolbar.hjty-collapsed {
                right: -48px; /* 隐藏主体,只露出切换按钮 */
            }

            .hjty-toolbar-container {
                display: flex;
                flex-direction: column;
                gap: 8px;
                padding: 8px;
                background: rgba(255, 255, 255, 0.95);
                backdrop-filter: blur(10px);
                border-radius: 12px;
                box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
                border: 1px solid rgba(255, 255, 255, 0.2);
                position: relative;
            }

            /* 切换按钮样式 */
            .hjty-toggle-btn {
                position: absolute;
                left: -20px;
                top: 50%;
                transform: translateY(-50%);
                width: 24px;
                height: 48px;
                border: none;
                border-radius: 12px 0 0 12px;
                background: rgba(255, 255, 255, 0.95);
                backdrop-filter: blur(10px);
                color: #374151;
                cursor: pointer;
                display: flex;
                align-items: center;
                justify-content: center;
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                z-index: 1;
            }

            .hjty-toggle-btn:hover {
                background: rgba(255, 255, 255, 1);
                transform: translateY(-50%) scale(1.05);
                color: #1f2937;
            }

            .hjty-toggle-btn:active {
                transform: translateY(-50%) scale(0.95);
            }

            .hjty-toggle-btn svg {
                transition: transform 0.3s ease;
            }

            #hjty-floating-toolbar.hjty-collapsed .hjty-toggle-btn svg {
                transform: rotate(180deg);
            }

            .hjty-toolbar-btn {
                width: 32px;
                height: 32px;
                border: none;
                border-radius: 8px;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                cursor: pointer;
                display: flex;
                align-items: center;
                justify-content: center;
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                position: relative;
                overflow: hidden;
            }

            .hjty-toolbar-btn:hover {
                box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
            }

            .hjty-toolbar-btn:active {
                transform: translateY(0);
                box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
            }

            .hjty-unlock-btn {
                background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
            }

            .hjty-unlock-btn:hover {
                box-shadow: 0 8px 25px rgba(17, 153, 142, 0.4);
            }

            .hjty-settings-btn {
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            }

            .hjty-settings-btn:hover {
                box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
            }

            .hjty-user-btn {
                background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);
            }

            .hjty-user-btn:hover {
                box-shadow: 0 8px 25px rgba(139, 92, 246, 0.4);
            }

            .hjty-toolbar-btn svg {
                transition: transform 0.3s ease;
            }

            .hjty-toolbar-btn:hover svg {
                transform: scale(1.1);
            }

            /* Modal 通用样式 */
            .hjty-modal-overlay {
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.5);
                backdrop-filter: blur(5px);
                display: flex;
                align-items: center;
                justify-content: center;
                animation: hjty-fadeIn 0.3s ease;
                z-index: 20000;
            }

            .hjty-modal-content {
                background: white;
                border-radius: 16px;
                box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
                width: 90%;
                max-width: 600px;
                max-height: 80vh;
                overflow: hidden;
                animation: hjty-slideUp 0.3s ease;
            }

            .hjty-modal-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 20px 24px;
                border-bottom: 1px solid #e5e7eb;
            }

            .hjty-modal-header h3 {
                margin: 0;
                font-size: 18px;
                font-weight: 600;
                color: #1f2937;
            }

            .hjty-modal-close {
                background: none;
                border: none;
                font-size: 24px;
                color: #6b7280;
                cursor: pointer;
                padding: 0;
                width: 32px;
                height: 32px;
                display: flex;
                align-items: center;
                justify-content: center;
                border-radius: 8px;
                transition: all 0.2s ease;
            }

            .hjty-modal-close:hover {
                background: #f3f4f6;
                color: #374151;
            }

            .hjty-modal-body {
                padding: 16px 24px;
                max-height: 350px;
                overflow-y: auto;
            }

            .hjty-modal-footer {
                padding: 16px 24px;
                border-top: 1px solid #e5e7eb;
                display: flex;
                justify-content: space-between;
                gap: 12px;
            }

            /* 登录Modal样式 */
            .hjty-login-content {
                max-width: 400px;
                width: 90%;
            }

            .hjty-login-content .hjty-modal-body {
                padding: 24px;
            }

            .hjty-login-form {
                padding: 0;
            }

            .hjty-form-group {
                margin-bottom: 20px;
            }

            .hjty-form-group:last-of-type {
                margin-bottom: 0;
            }

            .hjty-form-group label {
                display: block;
                margin-bottom: 8px;
                font-size: 14px;
                font-weight: 500;
                color: #374151;
            }

            .hjty-form-input {
                display: block;
                width: 100%;
                padding: 12px 16px;
                border: 1px solid #d1d5db;
                border-radius: 8px;
                font-size: 14px;
                transition: all 0.2s ease;
                background: white;
                box-sizing: border-box;
            }

            .hjty-form-input:focus {
                outline: none;
                border-color: #3b82f6;
                box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
            }

            .hjty-form-input::placeholder {
                color: #9ca3af;
            }

            .hjty-form-actions {
                display: flex;
                gap: 12px;
                margin-top: 32px;
            }

            /* 按钮样式 */
            .hjty-btn {
                flex: 1;
                padding: 12px 20px;
                border: none;
                border-radius: 8px;
                font-size: 14px;
                font-weight: 500;
                cursor: pointer;
                transition: all 0.2s ease;
                display: flex;
                align-items: center;
                justify-content: center;
                gap: 8px;
            }

            .hjty-btn-primary {
                background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
                color: white;
            }

            .hjty-btn-primary:hover {
                background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
                box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
            }

            .hjty-btn-primary:disabled {
                background: #9ca3af;
                cursor: not-allowed;
                transform: none;
                box-shadow: none;
                min-height: 44px;
            }

            .hjty-btn-secondary {
                background: white;
                color: #374151;
                border: 1px solid #d1d5db;
            }

            .hjty-btn-secondary:hover {
                background: #f9fafb;
                border-color: #9ca3af;
            }

            .hjty-btn-danger {
                background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
                color: white;
            }

            .hjty-btn-danger:hover {
                background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
                box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
            }

            /* 按钮内加载spinner样式 */
            .hjty-btn .hjty-loading-spinner {
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 16px;
                height: 16px;
                margin: 0;
                flex-shrink: 0;
            }

            .hjty-btn .hjty-spinner-ring {
                width: 14px;
                height: 14px;
                border: 2px solid rgba(255, 255, 255, 0.3);
                border-top: 2px solid white;
                border-radius: 50%;
                animation: hjty-spin 1s linear infinite;
            }

            /* 加载框样式 */
            #hjty-loading-modal {
                z-index: 40000;
            }

            .hjty-loading-overlay {
                background: rgba(0, 0, 0, 0.6);
                backdrop-filter: blur(8px);
            }

            .hjty-loading-content {
                max-width: 320px;
                width: 90%;
            }

            .hjty-loading-header {
                position: relative;
                height: 20px;
                padding: 16px 16px 0 16px;
            }

            .hjty-loading-close {
                position: absolute;
                top: 16px;
                right: 16px;
                width: 24px;
                height: 24px;
                font-size: 20px;
                border-radius: 6px;
            }

            .hjty-loading-body {
                padding: 20px 24px 32px 24px;
                text-align: center;
            }

            .hjty-loading-spinner {
                margin: 0 auto 20px auto;
                width: 40px;
                height: 40px;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            .hjty-spinner-ring {
                width: 32px;
                height: 32px;
                border: 3px solid #e5e7eb;
                border-top: 3px solid #3b82f6;
                border-radius: 50%;
                animation: hjty-spin 1s linear infinite;
            }

            .hjty-loading-message {
                margin: 0;
                font-size: 16px;
                color: #374151;
                font-weight: 500;
                line-height: 1.5;
            }

            /* 用户信息对话框样式 */
            .hjty-user-info-content {
                max-width: 400px;
                width: 90%;
            }

            .hjty-user-info {
                display: flex;
                align-items: center;
                gap: 16px;
                padding: 20px 0;
            }

            .hjty-user-avatar {
                flex-shrink: 0;
            }

            .hjty-user-details {
                flex: 1;
            }

            .hjty-user-name {
                margin: 0 0 8px 0;
                font-size: 18px;
                font-weight: 600;
                color: #1f2937;
            }

            .hjty-user-status {
                margin: 0;
                font-size: 14px;
                color: #10b981;
                font-weight: 500;
            }

            /* 确认对话框样式 */
            .hjty-confirm-content {
                max-width: 400px;
                width: 90%;
            }

            .hjty-confirm-message {
                margin: 0;
                font-size: 16px;
                color: #374151;
                text-align: center;
                line-height: 1.5;
            }

            /* 服务器切换Modal样式 */
            .hjty-server-list {
                display: flex;
                flex-direction: column;
                gap: 8px;
            }

            .hjty-server-item {
                display: flex;
                align-items: center;
                padding: 12px 16px;
                border: 1px solid #e5e7eb;
                border-radius: 8px;
                transition: all 0.2s ease;
                background: #fafafa;
                cursor: pointer;
            }

            .hjty-server-item:hover {
                border-color: #d1d5db;
                box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
                background: #f9fafb;
            }

            .hjty-server-item.hjty-online {
                border-color: #10b981;
                background: #f0fdf4;
            }

            .hjty-server-item.hjty-offline {
                border-color: #ef4444;
                background: #fef2f2;
            }

            .hjty-server-item.hjty-selected {
                border-color: #3b82f6;
                background: #eff6ff;
            }

            .hjty-server-item:not(.hjty-selected):hover {
                border-color: #3b82f6;
                background: #f1f5f9;
            }

            .hjty-server-info {
                flex: 1;
                min-width: 0;
            }

            .hjty-server-name {
                font-weight: 500;
                color: #1f2937;
                font-size: 14px;
                position: relative;
            }

            .hjty-server-item.hjty-selected .hjty-server-name {
                color: #1e40af;
                font-weight: 600;
            }

            .hjty-radio-indicator {
                width: 16px;
                height: 16px;
                border: 2px solid #d1d5db;
                border-radius: 50%;
                margin-right: 12px;
                flex-shrink: 0;
                position: relative;
                transition: all 0.2s ease;
            }

            .hjty-radio-indicator.hjty-radio-selected {
                border-color: #3b82f6;
                background: #3b82f6;
            }

            .hjty-radio-indicator.hjty-radio-selected::after {
                content: '';
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                width: 6px;
                height: 6px;
                background: white;
                border-radius: 50%;
            }

            .hjty-server-status {
                display: flex;
                align-items: center;
                gap: 6px;
                margin: 0 12px;
                flex-shrink: 0;
            }

            .hjty-status-indicator {
                width: 8px;
                height: 8px;
                border-radius: 50%;
                position: relative;
                flex-shrink: 0;
            }

            .hjty-status-indicator.hjty-checking {
                background: #f59e0b;
            }

            .hjty-status-indicator.hjty-online {
                background: #10b981;
            }

            .hjty-status-indicator.hjty-offline {
                background: #ef4444;
            }

            .hjty-status-text {
                font-size: 11px;
                color: #374151;
                min-width: 40px;
                font-weight: 600;
            }

            .hjty-latency {
                font-size: 11px;
                color: #10b981;
                font-weight: 600;
                min-width: 35px;
            }

            .hjty-refresh-btn {
                padding: 10px 20px;
                border: none;
                border-radius: 8px;
                background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
                color: white;
                font-size: 14px;
                font-weight: 500;
                cursor: pointer;
                transition: all 0.2s ease;
            }

            .hjty-refresh-btn:hover:not(:disabled) {
                background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
                box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
            }

            .hjty-refresh-btn:disabled {
                background: #9ca3af;
                cursor: not-allowed;
                transform: none;
                box-shadow: none;
            }

            .hjty-switch-btn {
                padding: 10px 20px;
                border: none;
                border-radius: 8px;
                background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
                color: white;
                font-size: 14px;
                font-weight: 500;
                cursor: pointer;
                transition: all 0.2s ease;
            }

            .hjty-switch-btn:hover:not(:disabled) {
                background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
                box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
            }

            .hjty-switch-btn:disabled {
                background: #9ca3af;
                cursor: not-allowed;
                transform: none;
                box-shadow: none;
            }

            /* 升级确认框样式 */
            .hjty-update-content {
                max-width: 450px;
                width: 90%;
            }

            .hjty-update-info {
                text-align: center;
                padding: 20px 0;
            }

            .hjty-update-icon {
                margin-bottom: 16px;
                display: flex;
                justify-content: center;
            }

            .hjty-update-message {
                margin: 0 0 16px 0;
                font-size: 18px;
                font-weight: 600;
                color: #1f2937;
            }

            .hjty-update-details {
                margin: 8px 0;
                font-size: 14px;
                color: #6b7280;
            }

            .hjty-update-description {
                margin: 16px 0 0 0;
                font-size: 14px;
                color: #374151;
                background: #f8fafc;
                padding: 12px;
                border-radius: 8px;
                border-left: 4px solid #3b82f6;
                text-align: left;
            }

            /* Toast 提示样式 */
            .hjty-toast {
                position: fixed;
                top: 20px;
                right: 20px;
                display: flex;
                align-items: center;
                gap: 12px;
                padding: 16px 20px;
                border-radius: 8px;
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
                backdrop-filter: blur(10px);
                z-index: 100000;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                font-size: 14px;
                font-weight: 500;
                max-width: 400px;
                min-width: 300px;
                transform: translateX(100%);
                opacity: 0;
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            }

            .hjty-toast-show {
                transform: translateX(0);
                opacity: 1;
            }

            .hjty-toast-success {
                background: rgba(16, 185, 129, 0.95);
                color: white;
                border: 1px solid rgba(16, 185, 129, 0.3);
            }

            .hjty-toast-error {
                background: rgba(239, 68, 68, 0.95);
                color: white;
                border: 1px solid rgba(239, 68, 68, 0.3);
            }

            .hjty-toast-warning {
                background: rgba(245, 158, 11, 0.95);
                color: white;
                border: 1px solid rgba(245, 158, 11, 0.3);
            }

            .hjty-toast-info {
                background: rgba(59, 130, 246, 0.95);
                color: white;
                border: 1px solid rgba(59, 130, 246, 0.3);
            }

            .hjty-toast-icon {
                flex-shrink: 0;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            .hjty-toast-message {
                flex: 1;
                line-height: 1.4;
            }

            /* 操作抽屉样式 */
            .hjty-action-drawer-overlay {
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.5);
                backdrop-filter: blur(5px);
                z-index: 30000;
                display: flex;
                align-items: flex-end;
                justify-content: center;
                opacity: 0;
                transition: opacity 0.3s ease;
            }

            .hjty-action-drawer-overlay.hjty-action-drawer-show {
                opacity: 1;
            }

            .hjty-action-drawer {
                background: #f8fafc;
                border-radius: 16px 16px 0 0;
                width: 100%;
                max-height: 80vh;
                display: flex;
                flex-direction: column;
                transform: translateY(100%);
                transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.2);
            }

            .hjty-action-drawer-show .hjty-action-drawer {
                transform: translateY(0);
            }

            .hjty-action-header {
                padding: 20px 24px 16px 24px;
                border-bottom: 1px solid #e5e7eb;
                text-align: center;
                flex-shrink: 0;
                background: white;
                border-radius: 16px 16px 0 0;
            }

            .hjty-action-title {
                margin: 0;
                font-size: 18px;
                font-weight: 600;
                color: #1f2937;
            }

            .hjty-action-list {
                flex: 1;
                overflow-y: auto;
                padding: 8px 0;
                background: white;
            }

            .hjty-action-item {
                display: flex;
                align-items: center;
                padding: 16px 24px;
                cursor: pointer;
                transition: background-color 0.2s ease;
                border-bottom: 1px solid #f3f4f6;
            }

            .hjty-action-item:hover {
                background: #f9fafb;
            }

            .hjty-action-item:active {
                background: #f3f4f6;
            }

            .hjty-action-item:last-child {
                border-bottom: none;
            }

            .hjty-action-content {
                flex: 1;
                min-width: 0;
            }

            .hjty-action-name {
                font-size: 16px;
                font-weight: 500;
                color: #1f2937;
                margin-bottom: 4px;
                line-height: 1.4;
            }

            .hjty-action-subname {
                font-size: 13px;
                color: #6b7280;
                line-height: 1.4;
                word-break: break-all;
            }

            .hjty-action-arrow {
                flex-shrink: 0;
                margin-left: 12px;
                color: #9ca3af;
                transition: transform 0.2s ease;
                display: flex;
                align-items: center;
                align-self: center;
            }

            .hjty-action-item:hover .hjty-action-arrow {
                transform: translateX(2px);
                color: #6b7280;
            }

            .hjty-action-footer {
                padding: 12px 16px;
                border-top: 1px solid #e5e7eb;
                flex-shrink: 0;
                background: #f8fafc;
            }

            .hjty-action-close-btn {
                display: block;
                width: 100%;
                padding: 10px 20px;
                border: none;
                border-radius: 6px;
                background: #f3f4f6;
                color: #374151;
                font-size: 14px;
                font-weight: 500;
                cursor: pointer;
                transition: all 0.2s ease;
            }

            .hjty-action-close-btn:hover {
                background: #e5e7eb;
                color: #1f2937;
            }

            .hjty-action-close-btn:active {
                background: #d1d5db;
                transform: translateY(1px);
            }

            /* 播放器弹窗样式 */
            .hjty-player-modal-overlay {
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.45);
                backdrop-filter: blur(5px);
                z-index: 40000;
                display: flex;
                align-items: center;
                justify-content: center;
                opacity: 0;
                transition: opacity 0.3s ease;
            }

            .hjty-player-modal-overlay.hjty-player-modal-show {
                opacity: 1;
            }

            .hjty-player-modal-content {
                background: #000000;
                border-radius: 12px;
                width: 95%;
                max-width: 1200px;
                height: 90%;
                max-height: 800px;
                display: flex;
                flex-direction: column;
                transform: scale(0.9);
                transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
                overflow: hidden;
            }

            .hjty-player-modal-show .hjty-player-modal-content {
                transform: scale(1);
            }

            .hjty-player-header {
                display: flex;
                justify-content: flex-end;
                align-items: center;
                padding: 16px 20px;
                background: #000000;
                flex-shrink: 0;
            }

            .hjty-player-close {
                background: none;
                border: none;
                font-size: 28px;
                color: #ffffff;
                cursor: pointer;
                padding: 0;
                width: 40px;
                height: 40px;
                display: flex;
                align-items: center;
                justify-content: center;
                border-radius: 8px;
                transition: all 0.2s ease;
                font-weight: 300;
            }

            .hjty-player-close:hover {
                background: rgba(255, 255, 255, 0.1);
                color: #ff4757;
                transform: scale(1.1);
            }

            .hjty-player-close:active {
                transform: scale(0.95);
            }

            .hjty-player-body {
                flex: 1;
                background: #000000;
                display: flex;
                align-items: center;
                justify-content: center;
                overflow: hidden;
            }

            #hjty-play-box {
                width: 100%;
                height: 100%;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            /* 动画 */
            @keyframes hjty-fadeIn {
                from { opacity: 0; }
                to { opacity: 1; }
            }

            @keyframes hjty-slideUp {
                from { transform: translateY(20px); opacity: 0; }
                to { transform: translateY(0); opacity: 1; }
            }

            @keyframes hjty-spin {
                from { transform: rotate(0deg); }
                to { transform: rotate(360deg); }
            }

            /* 移动端适配 */
            @media (max-width: 768px) {
                #hjty-floating-toolbar {
                    right: 15px;
                    top: auto;
                    bottom: 180px;
                    transform: none;
                }

                #hjty-floating-toolbar.hjty-collapsed {
                    right: -54px; /* 移动端收起时的位置 */
                }

                .hjty-toggle-btn {
                    left: -20px;
                    width: 20px;
                    height: 40px;
                }

                .hjty-toolbar-btn {
                    width: 36px;
                    height: 36px;
                }

                .hjty-modal-content {
                    width: 95%;
                    margin: 20px;
                }

                .hjty-modal-body {
                    padding: 12px 16px;
                }

                .hjty-server-item {
                    padding: 10px 12px;
                }

                .hjty-server-name {
                    font-size: 13px;
                }

                .hjty-server-status {
                    margin: 0 8px;
                }

                .hjty-login-content {
                    width: 95%;
                    margin: 20px;
                }

                .hjty-form-actions {
                    flex-direction: column;
                }

                .hjty-toast {
                    top: 10px;
                    right: 10px;
                    left: 10px;
                    max-width: none;
                    min-width: auto;
                }

                /* 播放器移动端适配 */
                .hjty-player-modal-content {
                    width: 100%;
                    height: 100%;
                    max-width: none;
                    max-height: none;
                    border-radius: 0;
                }

                .hjty-player-header {
                    padding: 12px 16px;
                }

                .hjty-player-close {
                    width: 36px;
                    height: 36px;
                    font-size: 24px;
                }
            }

            /* 暗色模式适配 */
            @media (prefers-color-scheme: dark) {
                .hjty-toolbar-container {
                    background: rgba(30, 30, 30, 0.95);
                    border: 1px solid rgba(255, 255, 255, 0.1);
                }

                .hjty-toggle-btn {
                    background: rgba(30, 30, 30, 0.95);
                    backdrop-filter: blur(10px);
                    color: #f3f4f6;
                }

                .hjty-toggle-btn:hover {
                    background: rgba(30, 30, 30, 1);
                    color: #ffffff;
                }

                .hjty-modal-content {
                    background: #1f2937;
                }

                .hjty-modal-header {
                    border-bottom-color: #374151;
                }

                .hjty-modal-header h3 {
                    color: #f9fafb;
                }

                .hjty-modal-close {
                    color: #9ca3af;
                }

                .hjty-modal-close:hover {
                    background: #374151;
                    color: #f3f4f6;
                }

                .hjty-modal-footer {
                    border-top-color: #374151;
                }

                .hjty-btn-secondary {
                    background: #374151;
                    color: #f3f4f6;
                    border-color: #4b5563;
                }

                .hjty-btn-secondary:hover {
                    background: #4b5563;
                    border-color: #6b7280;
                }

                .hjty-loading-content {
                    background: #1f2937;
                }

                .hjty-loading-close:hover {
                    background: #374151;
                    color: #f3f4f6;
                }

                .hjty-loading-message {
                    color: #f3f4f6;
                }

                .hjty-user-name {
                    color: #f9fafb;
                }

                .hjty-user-status {
                    color: #34d399;
                }

                .hjty-confirm-message {
                    color: #f3f4f6;
                }

                .hjty-update-message {
                    color: #f9fafb;
                }

                .hjty-update-details {
                    color: #9ca3af;
                }

                .hjty-update-description {
                    color: #f3f4f6;
                    background: #374151;
                    border-left-color: #60a5fa;
                }

                .hjty-server-item {
                    border-color: #374151;
                    background: #1f2937;
                }

                .hjty-server-item:hover {
                    border-color: #4b5563;
                    background: #374151;
                }

                .hjty-server-item.hjty-online {
                    background: #064e3b;
                    border-color: #059669;
                }

                .hjty-server-item.hjty-offline {
                    background: #7f1d1d;
                    border-color: #dc2626;
                }

                .hjty-server-item.hjty-selected {
                    background: #1e3a8a;
                    border-color: #3b82f6;
                }

                .hjty-server-item.hjty-selected .hjty-server-name {
                    color: #93c5fd;
                }

                .hjty-server-name {
                    color: #f9fafb;
                }

                .hjty-radio-indicator {
                    border-color: #4b5563;
                }

                .hjty-radio-indicator.hjty-radio-selected {
                    border-color: #60a5fa;
                    background: #60a5fa;
                }

                .hjty-status-text {
                    color: #d1d5db;
                }

                .hjty-refresh-btn:disabled {
                    background: #4b5563;
                }

                .hjty-switch-btn:disabled {
                    background: #4b5563;
                }

                .hjty-form-group label {
                    color: #f3f4f6;
                }

                .hjty-form-input {
                    background: #374151;
                    border-color: #4b5563;
                    color: #f3f4f6;
                }

                .hjty-form-input:focus {
                    border-color: #60a5fa;
                    box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.1);
                }

                .hjty-form-input::placeholder {
                    color: #6b7280;
                }

                /* 操作抽屉暗色模式 */
                .hjty-action-drawer {
                    background: #111827;
                }

                .hjty-action-header {
                    border-bottom-color: #374151;
                    background: #1f2937;
                }

                .hjty-action-title {
                    color: #f9fafb;
                }

                .hjty-action-item {
                    border-bottom-color: #374151;
                }

                .hjty-action-item:hover {
                    background: #374151;
                }

                .hjty-action-item:active {
                    background: #4b5563;
                }

                .hjty-action-name {
                    color: #f9fafb;
                }

                .hjty-action-subname {
                    color: #9ca3af;
                }

                .hjty-action-arrow {
                    color: #6b7280;
                }

                .hjty-action-item:hover .hjty-action-arrow {
                    color: #9ca3af;
                }

                .hjty-action-list {
                    background: #1f2937;
                }

                .hjty-action-footer {
                    border-top-color: #374151;
                    background: #111827;
                }

                .hjty-action-close-btn {
                    background: #374151;
                    color: #f3f4f6;
                }

                .hjty-action-close-btn:hover {
                    background: #4b5563;
                    color: #f9fafb;
                }

                .hjty-action-close-btn:active {
                    background: #6b7280;
                }
            }
            
            #play-box {height: 100%;display: flex;align-items: center;background-color: #000;}
            .van-popup.van-popup--center.play-box {width: 100%;height: 100%;max-width: 100%;}
            #bbs_float_menu{z-index:1!important;}
            #body.el-popup-parent--hidden{overflow: auto;}
            .van-list .van-list__loading,
            .sell-btn:before,
            .containeradvertising,
            .ishide,
            #tidio-chat{display: none !important;}
        `;

        document.head.appendChild(style);
    }


    function initFloatingButton() {
        if (document.getElementById('hjty-floating-toolbar')) return;

        const floatingToolbar = document.createElement('div');
        floatingToolbar.id = 'hjty-floating-toolbar';
        floatingToolbar.innerHTML = `
            <div class="hjty-toolbar-container">
                <button class="hjty-toggle-btn" title="收起工具栏">
                    <svg width="12" height="12" viewBox="0 0 24 24" fill="none">
                        <path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                    </svg>
                </button>
                <button class="hjty-toolbar-btn hjty-unlock-btn" title="解锁">
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none">
                        <path d="M6 10V8C6 5.79086 7.79086 4 10 4H14C16.2091 4 18 5.79086 18 8V10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
                        <rect x="4" y="10" width="16" height="10" rx="2" stroke="currentColor" stroke-width="2" fill="none"/>
                        <circle cx="12" cy="15" r="1" fill="currentColor"/>
                    </svg>
                </button>
                <button class="hjty-toolbar-btn hjty-settings-btn" title="切换服务器">
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none">
                        <rect x="2" y="3" width="20" height="4" rx="1" stroke="currentColor" stroke-width="2"/>
                        <rect x="2" y="10" width="20" height="4" rx="1" stroke="currentColor" stroke-width="2"/>
                        <rect x="2" y="17" width="20" height="4" rx="1" stroke="currentColor" stroke-width="2"/>
                        <circle cx="6" cy="5" r="1" fill="currentColor"/>
                        <circle cx="6" cy="12" r="1" fill="currentColor"/>
                        <circle cx="6" cy="19" r="1" fill="currentColor"/>
                        <path d="M16 8L18 10L16 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                        <path d="M8 15L10 17L8 19" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                    </svg>
                </button>
            </div>
        `;

        document.body.appendChild(floatingToolbar);


        const unlockBtn = floatingToolbar.querySelector(CONFIG.SELECTORS.UNLOCK_BTN);
        const settingsBtn = floatingToolbar.querySelector(CONFIG.SELECTORS.SETTINGS_BTN);
        const toggleBtn = floatingToolbar.querySelector(CONFIG.SELECTORS.TOGGLE_BTN);

        unlockBtn.addEventListener('click', handleUnlockClick);

        const debouncedSwitchServer = Utils.debounce(() => switchServer(), 300);
        settingsBtn.addEventListener('click', debouncedSwitchServer);


        const debouncedToggleToolbar = Utils.debounce(() => toggleToolbar(), 200);
        toggleBtn.addEventListener('click', debouncedToggleToolbar);


        if (toolbarCollapsed) {
            floatingToolbar.classList.add('hjty-collapsed');
        }


        toggleBtn.title = toolbarCollapsed ? '展开工具栏' : '收起工具栏';


        App.updateToolbarButtons(Utils.checkLoginStatus());


        document.addEventListener('keydown', (e) => {
            if (e.ctrlKey && e.shiftKey && e.key === 'H') {
                e.preventDefault();
                toggleToolbar();
            }
        });
    }


    function toggleToolbar() {
        const toolbar = document.getElementById('hjty-floating-toolbar');
        if (!toolbar) return;

        toolbarCollapsed = !toolbarCollapsed;

        if (toolbarCollapsed) {
            toolbar.classList.add('hjty-collapsed');
        } else {
            toolbar.classList.remove('hjty-collapsed');
        }


        const toggleBtn = toolbar.querySelector(CONFIG.SELECTORS.TOGGLE_BTN);
        if (toggleBtn) {
            toggleBtn.title = toolbarCollapsed ? '展开工具栏' : '收起工具栏';
        }


        localStorage.setItem('hjty_toolbar_collapsed', toolbarCollapsed.toString());
    }


    function handleUnlockClick() {
        if (newVersion !== '') {
            App.showUpdateConfirm();
            return;
        }

        if (!Utils.checkLoginStatus()) {
            showLoginModal();
            return;
        }

        Utils.deleteCookie('NOTLOGIN');
        const pid = Utils.getPid();
        if (!pid) {
            if (/\/videoplay/.test(location.href)) {
                Utils.copyText(shortVideoUrl).then(success => {
                    if (success) {
                        UI.showToast('短视频地址复制成功', 'success');
                    } else {
                        UI.showToast('短视频地址复制失败', 'error');
                    }
                });
            } else {
                UI.showToast('请进入帖子再解锁!', 'error');
            }
            return;
        }

        if (m3u8_url !== '') {
            App.showVideoActions();
            return;
        }


        UI.showLoadingModal('解锁中...', true, function () {
            UI.showToast('解锁已取消', 'warning');
        });

        App.getTopic(pid).then(topic => {
            App.showTopic(topic, pid);
        }).catch((err) => {
            UI.showToast(err, 'warning');
        });
    }


    function showLoginModal() {
        if (document.getElementById(CONFIG.MODAL_IDS.LOGIN)) return;

        const loginModal = document.createElement('div');
        loginModal.id = CONFIG.MODAL_IDS.LOGIN;
        loginModal.className = 'hjty-modal-overlay';
        loginModal.innerHTML = `
            <div class="hjty-modal-content hjty-login-content">
                <div class="hjty-modal-header">
                    <h3>用户登录</h3>
                    <button class="hjty-modal-close" onclick="this.closest('.hjty-modal-overlay').remove()">×</button>
                </div>
                <div class="hjty-modal-body">
                    <form class="hjty-login-form">
                        <div class="hjty-form-group">
                            <label for="hjty-username">账号</label>
                            <input type="text" id="hjty-username" class="hjty-form-input" placeholder="请输入账号" required>
                        </div>
                        <div class="hjty-form-group">
                            <label for="hjty-password">密码</label>
                            <input type="password" id="hjty-password" class="hjty-form-input" placeholder="请输入密码" required>
                        </div>
                        <div class="hjty-form-actions">
                            <button type="submit" class="hjty-btn hjty-btn-primary hjty-login-btn">登录</button>
                            <button type="button" class="hjty-btn hjty-btn-secondary hjty-register-btn">注册</button>
                        </div>
                    </form>
                </div>
            </div>
        `;

        document.body.appendChild(loginModal);


        const loginForm = loginModal.querySelector('.hjty-login-form');
        const loginBtn = loginModal.querySelector('.hjty-login-btn');
        const registerBtn = loginModal.querySelector('.hjty-register-btn');

        loginForm.addEventListener('submit', async (e) => {
            e.preventDefault();
            const username = document.getElementById('hjty-username').value.trim();
            const password = document.getElementById('hjty-password').value.trim();

            if (!username || !password) {
                UI.showToast('请填写完整信息', 'warning');
                return;
            }

            await handleLogin(username, password, loginBtn, loginModal);
        });

        registerBtn.addEventListener('click', () => {
            window.open(`${server}/register`, '_blank');
        });


        loginModal.addEventListener('click', (e) => {
            if (e.target === loginModal) loginModal.remove();
        });
    }


    async function handleLogin(username, password, loginBtn, loginModal) {
        try {
            loginBtn.disabled = true;
            loginBtn.innerHTML = '<div class="hjty-loading-spinner"><div class="hjty-spinner-ring"></div></div>登录中...';

            const response = await fetch(`${server}/api/login`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ username, password })
            });

            const result = await response.json();

            if (!result.code) {
                localStorage.setItem(CONFIG.STORAGE_KEYS.USER_TOKEN, result.token);
                localStorage.setItem(CONFIG.STORAGE_KEYS.USER_NAME, username);

                UI.showToast('登录成功', 'success');
                loginModal.remove();
                App.updateToolbarButtons(true);
            } else {
                UI.showToast(result.msg || '登录失败', 'error');
            }
        } catch (error) {
            UI.showToast('网络错误,请重试', 'error');
        } finally {
            loginBtn.disabled = false;
            loginBtn.innerHTML = '登录';
        }
    }


    function switchServer() {

        const servers = [
            { id: 'vip', name: '服务器A', url: 'https://vip.tianya365.top' },
            { id: 'b', name: '服务器B', url: 'https://haijiao.tianya365.top' },
            { id: 'c', name: '服务器C', url: 'https://new.tianya365.top' },
            { id: 'd', name: '服务器D', url: 'https://hj.tianya365.top' }
        ];


        function getServerIdByUrl(url) {
            const foundServer = servers.find(s => s.url === url);
            return foundServer ? foundServer.id : 'vip';
        }

        const currentServerId = getServerIdByUrl(server);

        const modal = document.createElement('div');
        modal.id = CONFIG.MODAL_IDS.SERVER;
        modal.className = 'hjty-modal-overlay';
        modal.style.zIndex = '25000';
        modal.innerHTML = `
            <div class="hjty-modal-content">
                <div class="hjty-modal-header">
                    <h3>服务器节点切换</h3>
                    <button class="hjty-modal-close" onclick="this.closest('.hjty-modal-overlay').remove()">×</button>
                </div>
                <div class="hjty-modal-body">
                    <div class="hjty-server-list">
                        ${servers.map(srv => `
                            <div class="hjty-server-item ${srv.id === currentServerId ? 'hjty-selected' : ''}" data-server-id="${srv.id}">
                                <div class="hjty-radio-indicator ${srv.id === currentServerId ? 'hjty-radio-selected' : ''}"></div>
                                <div class="hjty-server-info">
                                    <div class="hjty-server-name">${srv.name}</div>
                                </div>
                                <div class="hjty-server-status">
                                    <div class="hjty-status-indicator hjty-checking"></div>
                                    <span class="hjty-status-text">检测中</span>
                                    <span class="hjty-latency"></span>
                                </div>
                            </div>
                        `).join('')}
                    </div>
                </div>
                <div class="hjty-modal-footer">
                    <button class="hjty-refresh-btn">重新检测</button>
                    <button class="hjty-switch-btn" disabled>立即切换</button>
                </div>
            </div>
        `;

        document.body.appendChild(modal);

        let isChecking = false;
        let selectedServerId = currentServerId;


        async function checkServer(server) {
            const startTime = Date.now();
            try {
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 60000);

                await fetch(`${server.url}/api/login`, {
                    method: 'HEAD',
                    mode: 'no-cors',
                    signal: controller.signal
                });

                clearTimeout(timeoutId);
                const latency = Date.now() - startTime;
                return { success: true, latency };
            } catch (error) {
                return { online: false, latency: 0 };
            }
        }


        function updateServerStatus(serverId, result) {
            const serverItem = modal.querySelector(`[data-server-id="${serverId}"]`);
            const statusIndicator = serverItem.querySelector('.hjty-status-indicator');
            const statusText = serverItem.querySelector('.hjty-status-text');
            const latencySpan = serverItem.querySelector('.hjty-latency');

            statusIndicator.className = `hjty-status-indicator ${result.success ? 'hjty-online' : 'hjty-offline'}`;
            statusText.textContent = result.success ? '正常' : '异常';

            if (result.success) {
                latencySpan.textContent = `${result.latency}ms`;
                serverItem.classList.add('hjty-online');
                serverItem.classList.remove('hjty-offline');
            } else {
                latencySpan.textContent = '';
                serverItem.classList.add('hjty-offline');
                serverItem.classList.remove('hjty-online');
            }
        }


        function selectServer(serverId) {

            modal.querySelectorAll('.hjty-server-item').forEach(item => {
                item.classList.remove('hjty-selected');
                item.querySelector('.hjty-radio-indicator').classList.remove('hjty-radio-selected');
            });


            const selectedItem = modal.querySelector(`[data-server-id="${serverId}"]`);
            selectedItem.classList.add('hjty-selected');
            selectedItem.querySelector('.hjty-radio-indicator').classList.add('hjty-radio-selected');

            selectedServerId = serverId;


            const switchBtn = modal.querySelector('.hjty-switch-btn');
            switchBtn.disabled = false;
        }


        function switchToServer(serverId) {
            const selectedServer = servers.find(s => s.id === serverId);
            if (selectedServer) {
                server = selectedServer.url;
                localStorage.setItem(CONFIG.STORAGE_KEYS.SERVER, server);
                UI.showToast(`已切换到:${selectedServer.name}`, 'success');
                modal.remove();


                App.updateToolbarButtons(Utils.checkLoginStatus());
            }
        }


        async function checkAllServers() {
            if (isChecking) return;

            isChecking = true;
            const refreshBtn = modal.querySelector('.hjty-refresh-btn');
            refreshBtn.disabled = true;
            refreshBtn.textContent = '检测中...';


            modal.querySelectorAll('.hjty-server-item').forEach(item => {
                const statusIndicator = item.querySelector('.hjty-status-indicator');
                const statusText = item.querySelector('.hjty-status-text');
                const latencySpan = item.querySelector('.hjty-latency');

                statusIndicator.className = 'hjty-status-indicator hjty-checking';
                statusText.textContent = '检测中';
                latencySpan.textContent = '';
                item.classList.remove('hjty-online', 'hjty-offline');
            });


            const checkPromises = servers.map(async (srv) => {
                const result = await checkServer(srv);
                updateServerStatus(srv.id, result);
            });

            await Promise.all(checkPromises);

            refreshBtn.disabled = false;
            refreshBtn.textContent = '重新检测';
            isChecking = false;
        }


        modal.querySelectorAll('.hjty-server-item').forEach(item => {
            item.addEventListener('click', () => {
                const serverId = item.dataset.serverId;
                selectServer(serverId);
            });
        });

        const refreshBtn = modal.querySelector('.hjty-refresh-btn');
        const switchBtn = modal.querySelector('.hjty-switch-btn');

        refreshBtn.addEventListener('click', checkAllServers);
        switchBtn.addEventListener('click', () => switchToServer(selectedServerId));


        modal.addEventListener('click', (e) => {
            if (e.target === modal) modal.remove();
        });


        checkAllServers();
    }


    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            buttonInitialized = checkTitleAndInitButton();
            if (!buttonInitialized) {
                setupTitleObserver();
            }
        });
    } else {
        buttonInitialized = checkTitleAndInitButton();
        if (!buttonInitialized) {
            setupTitleObserver();
        }
    }

    (function () {
        const originOpen = XMLHttpRequest.prototype.open;
        XMLHttpRequest.prototype.open = function (method, url) {
            if (/\/api\/topic\/(hot\/topics\?|node\/(topics|news)|idol_list)/.test(url)) {
                const xhr = this;
                const getter = Object.getOwnPropertyDescriptor(
                    XMLHttpRequest.prototype,
                    "response"
                ).get;
                Object.defineProperty(xhr, "responseText", {
                    get: () => {
                        let result = getter.call(xhr);

                        try {
                            let res = JSON.parse(result);
                            if (res['isEncrypted']) {
                                res.data = Utils.encrypt(App.formatTitle(Utils.decrypt(res.data)))
                            } else {
                                res.data = App.formatTitle(res.data)
                            }
                            return JSON.stringify(res);
                        } catch (e) {
                            return result;
                        }
                    },
                });
            } else if (/\/api\/topic\/\d+/.test(url) && /tianya365/.test(url) === false) {
                m3u8_url = '';
            } else if (/\/api\/attachment/.test(url)) {
                const xhr = this;
                const getter = Object.getOwnPropertyDescriptor(
                    XMLHttpRequest.prototype,
                    "response"
                ).get;
                Object.defineProperty(xhr, "responseText", {
                    get: () => {
                        let result = getter.call(xhr);
                        App.getShortVideoUrl(result);
                        return result;
                    }
                });
            } else if (/\/api\/video\/checkVideoCanPlay/.test(url)) {
                const xhr = this;
                const getter = Object.getOwnPropertyDescriptor(
                    XMLHttpRequest.prototype,
                    "response"
                ).get;
                Object.defineProperty(xhr, "responseText", {
                    get: () => {
                        return App.fixShortVideo(getter.call(xhr));
                    },
                });
            } else if (/\/api\/topic\/like/.test(url)) {
                const xhr = this;
                const getter = Object.getOwnPropertyDescriptor(
                    XMLHttpRequest.prototype,
                    "response"
                ).get;
                Object.defineProperty(xhr, "responseText", {
                    get: () => {
                        let result = getter.call(xhr);
                        let res = JSON.parse(result);
                        if (res.errorCode == 1) {
                            res.errorCode = -1;
                        }
                        return JSON.stringify(res);
                    },
                });
            }

            originOpen.apply(this, arguments);
        };
    })();
})();