// ==UserScript== // @name 批改网解除粘贴限制 // @namespace http://tampermonkey.net/ // @version 91 // @description 解锁禁用的作文文本框,自动填充并提交(回车) // @author Rito // @match *://*.pigai.org/* // @match *://pigai.org/* // @grant none // ==/UserScript== (function () { 'use strict'; const STORAGE_KEY = 'pigai_custom_text'; let myText = localStorage.getItem(STORAGE_KEY) || ''; // 可能的提交按钮选择器(按页面实际改动) const SUBMIT_SELECTORS = [ '#submit', // 常见 id 'button[type="submit"]', '.btn-submit', 'input[type="submit"]', 'a.submit' ]; // 创建动态模糊 UI const createUI = () => { const container = document.createElement('div'); container.style.cssText = ` position: fixed; bottom: 20px; right: 20px; width: 320px; padding: 16px; background: rgba(255, 255, 255, 0.65); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.6); border-radius: 16px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); z-index: 999999; font-family: system-ui, -apple-system, sans-serif; transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); `; const title = document.createElement('div'); title.textContent = '🌟 批改网粘贴助手'; title.style.cssText = ` font-weight: 600; margin-bottom: 12px; color: #1d1d1f; font-size: 15px; letter-spacing: 0.5px; `; const textarea = document.createElement('textarea'); textarea.placeholder = '在此输入或粘贴需要自动填充的作文内容...'; textarea.value = myText; textarea.style.cssText = ` width: 100%; height: 140px; padding: 10px; border: 1px solid rgba(0, 0, 0, 0.1); border-radius: 10px; background: rgba(255, 255, 255, 0.85); resize: vertical; box-sizing: border-box; font-size: 13px; line-height: 1.5; margin-bottom: 12px; outline: none; transition: border-color 0.2s, box-shadow 0.2s; color: #333; `; textarea.addEventListener('focus', () => { textarea.style.borderColor = '#007AFF'; textarea.style.boxShadow = '0 0 0 3px rgba(0, 122, 255, 0.2)'; }); textarea.addEventListener('blur', () => { textarea.style.borderColor = 'rgba(0, 0, 0, 0.1)'; textarea.style.boxShadow = 'none'; }); const btnGroup = document.createElement('div'); btnGroup.style.display = 'flex'; btnGroup.style.gap = '10px'; const fillBtn = document.createElement('button'); fillBtn.textContent = '保存并填充'; fillBtn.style.cssText = ` flex: 1; padding: 10px 0; background: #007AFF; color: white; border: none; border-radius: 10px; cursor: pointer; font-weight: 600; font-size: 14px; transition: transform 0.1s, background 0.2s; `; fillBtn.onmouseover = () => fillBtn.style.background = '#0066d6'; fillBtn.onmouseout = () => fillBtn.style.background = '#007AFF'; fillBtn.onmousedown = () => fillBtn.style.transform = 'scale(0.96)'; fillBtn.onmouseup = () => fillBtn.style.transform = 'scale(1)'; const toggleBtn = document.createElement('button'); toggleBtn.textContent = '收起'; toggleBtn.style.cssText = ` padding: 10px 14px; background: rgba(0, 0, 0, 0.04); color: #555; border: 1px solid rgba(0, 0, 0, 0.08); border-radius: 10px; cursor: pointer; font-size: 13px; font-weight: 500; transition: background 0.2s; `; toggleBtn.onmouseover = () => toggleBtn.style.background = 'rgba(0, 0, 0, 0.08)'; toggleBtn.onmouseout = () => toggleBtn.style.background = 'rgba(0, 0, 0, 0.04)'; fillBtn.addEventListener('click', () => { myText = textarea.value; localStorage.setItem(STORAGE_KEY, myText); if(myText.trim()){ run(); } fillBtn.textContent = '已完成 ✨'; fillBtn.style.background = '#34C759'; setTimeout(() => { fillBtn.textContent = '保存并填充'; fillBtn.style.background = '#007AFF'; }, 2000); }); let isMinimized = false; toggleBtn.addEventListener('click', () => { isMinimized = !isMinimized; if (isMinimized) { textarea.style.display = 'none'; fillBtn.style.display = 'none'; title.style.display = 'none'; toggleBtn.textContent = '📝 展开'; toggleBtn.style.background = 'rgba(255, 255, 255, 0.8)'; container.style.padding = '8px 12px'; container.style.width = 'auto'; container.style.borderRadius = '20px'; } else { textarea.style.display = 'block'; fillBtn.style.display = 'block'; title.style.display = 'block'; toggleBtn.textContent = '收起'; toggleBtn.style.background = 'rgba(0, 0, 0, 0.04)'; container.style.padding = '16px'; container.style.width = '320px'; container.style.borderRadius = '16px'; } }); container.appendChild(title); container.appendChild(textarea); btnGroup.appendChild(fillBtn); btnGroup.appendChild(toggleBtn); container.appendChild(btnGroup); document.body.appendChild(container); }; // 解除页面全局复制/粘贴/选择限制(保险) const freeGlobal = () => { const props = ['oncopy', 'onpaste', 'oncut', 'onselectstart', 'oncontextmenu', 'ondragstart']; props.forEach(p => { document[p] = null; document.body && (document.body[p] = null); }); document.body && (document.body.style.userSelect = 'text'); }; // 尝试找到 textarea(考虑 iframe 或动态渲染) const findTextarea = (root = document) => { return root.querySelector('#contents.from_contents, #contents, textarea#from_contents, textarea[name="contents"]'); }; // 解除禁用并填充 const unlockAndFill = (ta, text) => { if (!text) return; // 空内容不填充 // 移除禁用与阻断属性 ['disabled', 'readonly', 'onpaste', 'oncopy', 'oncut', 'onselectstart'].forEach(attr => ta.removeAttribute(attr)); ta.disabled = false; ta.readOnly = false; // 允许选择与输入 ta.style.userSelect = 'text'; ta.style.pointerEvents = 'auto'; // 写入文本 ta.value = text; // 触发事件,让页面识别变更 ta.dispatchEvent(new Event('input', { bubbles: true })); ta.dispatchEvent(new Event('change', { bubbles: true })); // 模拟按键(Enter) const keydownEnter = new KeyboardEvent('keydown', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13, which: 13 }); ta.dispatchEvent(keydownEnter); const keyupEnter = new KeyboardEvent('keyup', { bubbles: true, cancelable: true, key: 'Enter', code: 'Enter', keyCode: 13, which: 13 }); ta.dispatchEvent(keyupEnter); }; // 尝试点击提交按钮 const trySubmit = () => { for (const sel of SUBMIT_SELECTORS) { const btn = document.querySelector(sel); if (btn) { btn.click(); return true; } } return false; }; // 处理可能存在的 iframe const forAllFrames = (fn) => { try { fn(document); const iframes = document.querySelectorAll('iframe'); iframes.forEach(iframe => { try { const doc = iframe.contentDocument || iframe.contentWindow?.document; if (doc) fn(doc); } catch (e) { /* 跨域忽略 */ } }); } catch (e) { /* 忽略 */ } }; // 核心流程:解锁、填充、提交 const run = () => { freeGlobal(); forAllFrames((root) => { let ta = findTextarea(root); if (!ta) return; unlockAndFill(ta, myText); // 若页面监听 form 提交,尝试找到所在表单并提交 const form = ta.closest('form'); if (form) { // 触发 submit 事件 const ok = form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true })); if (ok) { form.submit?.(); } } else { // 尝试点击页面提交按钮 trySubmit(); } }); }; // 页面就绪后执行,多次重试应对异步渲染 const start = () => { if (!myText.trim()) return; // 没内容则不自动运行 let tries = 0; const maxTries = 20; const timer = setInterval(() => { tries++; run(); // 如果找到了并填充,或者达到最大尝试次数就停 const ta = findTextarea(document); if ((ta && ta.value && ta.value.trim().length > 0) || tries >= maxTries) { clearInterval(timer); } }, 500); }; // MutationObserver:如果页面后续替换/重绘 textarea,自动再次填充 const observe = () => { const mo = new MutationObserver(() => { const ta = findTextarea(document); if (ta && (!ta.value || ta.value.trim().length === 0) && myText.trim()) { unlockAndFill(ta, myText); } }); mo.observe(document.documentElement, { childList: true, subtree: true }); }; // 提供一个快捷键:Ctrl+Shift+Enter 手动触发一次(可选) const hotkey = () => { document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.shiftKey && e.key === 'Enter') { e.preventDefault(); run(); } }, true); }; // 初始化 window.addEventListener('load', () => { createUI(); start(); observe(); hotkey(); console.log('Ready: auto-fill engine initialized.'); }); })();