ESJ文章点赞动画自动注入脚本

通过自动或手动方式,将一个可交互的点赞动画HTML代码块精确注入到ESJ文章编辑器中。

// ==UserScript==
// @name         ESJ文章点赞动画自动注入脚本
// @namespace    http://tampermonkey.net/
// @version      3.2
// @description  通过自动或手动方式,将一个可交互的点赞动画HTML代码块精确注入到ESJ文章编辑器中。
// @author       Lilyyu & Gemini
// @match        *://*.esjzone.one/*
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 1. 动画HTML代码 (保持不变)
    const animationHtml = `
<section>
    <img src="none" alt="点赞提示动画" onerror="
        window.addEventListener('load', (e) => {
            const btn = document.querySelector('.btn.btn-likes.btn-secondary');
            if(!btn) return;
            const originalBtnStyle = {
                position: btn.style.position,
                overflow: btn.style.overflow
            };
            btn.style.position = 'relative';
            btn.style.overflow = 'visible';
            const arrowTip = document.createElement('div');
            arrowTip.innerHTML = '⇩ 点赞谢谢喵';
            arrowTip.style.cssText = 'position:absolute; bottom:100%; left:50%; transform:translateX(-50%); margin-bottom:1px; color:#ff69b4; font-size:12px; animation:bounceUp 1s infinite; white-space:nowrap;';
            btn.appendChild(arrowTip);
            const pulseElements = [];
            for(let i = 0; i < 2; i++) {
                const pulse = document.createElement('div');
                pulse.style.cssText = 'position:absolute; border:2px solid rgba(255, 105, 180, 0.8); border-radius:50%; width:0; height:0; left:50%; top:50%; transform:translate(-50%, -50%); opacity:0; pointer-events:none;';
                btn.appendChild(pulse);
                pulseElements.push(pulse);
                pulse.animate([
                    { width: '0', height: '0', opacity: 0.8 },
                    { width: '120%', height: '120%', opacity: 0 }
                ], {
                    duration: 2000,
                    delay: i * 1000,
                    iterations: Infinity,
                    easing: 'cubic-bezier(0.4, 0, 0.2, 1)'
                });
            }
            const style = document.createElement('style');
            style.textContent = \`
                @keyframes bounceUp {
                    0%, 100% { transform: translateX(-50%) translateY(0); }
                    50% { transform: translateX(-50%) translateY(-5px); }
                }\`;
            document.head.appendChild(style);
            btn.addEventListener('click', function handleClick() {
                if (arrowTip.parentNode === btn) btn.removeChild(arrowTip);
                pulseElements.forEach(pulse => { if (pulse.parentNode === btn) btn.removeChild(pulse); });
                const btnRect = btn.getBoundingClientRect();
                const btnCenterX = btnRect.left + btnRect.width / 2;
                const btnCenterY = btnRect.top + btnRect.height / 2;
                const thankYou = document.createElement('div');
                thankYou.textContent = '(づ ̄3 ̄)づ❤️喜欢你';
                thankYou.style.cssText = \`position:fixed; left:\${btnCenterX}px; top:\${btnCenterY}px; transform:translate(-50%, -50%); color:white; font-weight:bold; font-size:14px; pointer-events:none; z-index:999999; text-shadow:0 0 5px #ff69b4, 1px 1px 1px #ffb4d9, -1px 1px 1px #ffb4d9, 1px -1px 1px #ffb4d9, -1px -1px 1px #ffb4d9; white-space:nowrap;\`;
                document.body.appendChild(thankYou);
                thankYou.animate([
                    { transform: 'translate(-50%, -50%) scale(0.8)', opacity: 0 },
                    { transform: 'translate(-50%, -50%) scale(1.1)', opacity: 1, offset: 0.2 },
                    { transform: 'translate(-50%, -50%) scale(0.95)', offset: 0.4 },
                    { transform: 'translate(-50%, -50%) scale(1.05)', offset: 0.6 },
                    { transform: 'translate(-50%, -50%) scale(0.98)', offset: 0.8 },
                    { transform: 'translate(-50%, -50%) scale(1)', opacity: 1 }
                ], { duration: 1000, easing: 'cubic-bezier(0.4, 0, 0.2, 1)' });
                setTimeout(() => {
                    thankYou.animate([
                        { transform: 'translate(-50%, -50%)', opacity: 1 },
                        { transform: 'translate(-50%, -200%)', opacity: 0 }
                    ], { duration: 1200, easing: 'ease-out' }).onfinish = () => { if (thankYou.parentNode === document.body) document.body.removeChild(thankYou); };
                }, 1000);
                if (style.parentNode === document.head) document.head.removeChild(style);
                btn.removeEventListener('click', handleClick);
                btn.style.position = originalBtnStyle.position;
                btn.style.overflow = originalBtnStyle.overflow;
            }, { once: true });
        });
        if(this?.parentNode?.parentNode?.className !== undefined){
            if(this.parentNode.parentNode.className !== 'fr-element fr-view'){
                this.parentNode.removeChild(this);
            }
        }
    ">
</section>
    `;

    // 2. 注入功能 (已更新选择器)
    function injectContent(isAuto = false) {
        // 使用ID选择器 `#artEditor .fr-element.fr-view` 来精确定位小说编辑器
        const editor = document.querySelector('#artEditor .fr-element.fr-view');

        if (!editor) {
            if (!isAuto) {
                alert('未找到小说编辑器!\n请确认你正在文章编辑页面。');
            }
            return;
        }

        if (editor.innerHTML.includes('alt="点赞提示动画"')) {
            console.log('检测到动画代码已存在,取消注入。');
            if (!isAuto) {
                alert('动画代码已存在,无需重复注入!');
            }
            return;
        }

        editor.innerHTML += animationHtml;
        console.log('动画代码已成功注入。');
        if (!isAuto) {
            alert('动画代码已成功注入到文章末尾!\n请检查后保存文章。');
        }
    }

    // --- 脚本设置与执行逻辑 ---

    const currentMode = GM_getValue('injectionMode', 'auto');
    const currentModeText = currentMode === 'auto' ? '自动' : '手动';

    GM_registerMenuCommand(`模式切换 (当前: ${currentModeText})`, () => {
        const newMode = currentMode === 'auto' ? 'manual' : 'auto';
        const newModeText = newMode === 'auto' ? '自动' : '手动';
        GM_setValue('injectionMode', newMode);
        alert(`模式已切换为: ${newModeText}。\n页面将刷新以应用设置。`);
        location.reload();
    });

    GM_registerMenuCommand('✅ 手动注入动画到文章', () => injectContent(false), 'i');

    if (currentMode === 'auto') {
        window.addEventListener('load', () => injectContent(true));
    } else {
        console.log('文章内嵌动画脚本处于手动模式。请点击油猴菜单执行注入。');
    }

})();