您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
绕过粘贴检测,支持代码题(CodeMirror)和作业题(UEditor)
// ==UserScript== // @name 超星粘贴助手 // @namespace http://tampermonkey.net/ // @version 1.2.1 // @description 绕过粘贴检测,支持代码题(CodeMirror)和作业题(UEditor) // @author muqy1818 // @match *://*.chaoxing.com/* // @match *://*.cx.com/* // @grant none // @license MIT // @run-at document-idle // @homepage https://github.com/muqy1818/ChaoXing_Code // @supportURL https://github.com/muqy1818/ChaoXing_Code/issues // ==/UserScript== (function() { 'use strict'; let pasteHelper = null; let isDragging = false; let dragOffset = { x: 0, y: 0 }; let isInitialized = false; // 初始化状态标记 // 等待页面加载完成,返回是否检测到编辑器 function waitForEditors() { return new Promise((resolve) => { let attempts = 0; const maxAttempts = 20; // 最多等待10秒 const checkForEditors = () => { attempts++; // 减少日志输出频率,避免卡顿 if (attempts % 5 === 0) { console.log(`[粘贴助手] 第${attempts}次检测编辑器...`); } let hasEditor = false; // 检查 CodeMirror 编辑器 if (typeof window.codeEditors !== 'undefined' && window.codeEditors) { const editorKeys = Object.keys(window.codeEditors); if (editorKeys.length > 0) { console.log('[粘贴助手] 检测到CodeMirror编辑器:', editorKeys.length, '个'); hasEditor = true; } } // 检查 UEditor 编辑器 if (typeof window.UE !== 'undefined' && window.UE.instants) { const ueKeys = Object.keys(window.UE.instants); let validCount = 0; ueKeys.forEach(key => { const editor = window.UE.instants[key]; if (editor && editor.ready) { validCount++; } }); if (validCount > 0) { console.log('[粘贴助手] 检测到UEditor编辑器:', validCount, '个'); hasEditor = true; } } // 注意: 不检测textarea,因为超星的答题框都是UEditor接管的 // textarea只是占位元素,会被UEditor初始化为富文本编辑器 if (hasEditor) { resolve(true); return; } if (attempts >= maxAttempts) { console.log('[粘贴助手] 检测超时,未找到编辑器'); resolve(false); return; } setTimeout(checkForEditors, 500); }; // 延迟启动,避免阻塞页面加载 setTimeout(checkForEditors, 1000); }); } // 创建样式 function createStyles() { const style = document.createElement('style'); style.textContent = ` .paste-helper-container { position: fixed; top: 20px; right: 20px; width: 400px; background: #ffffff; border: 2px solid #4CAF50; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); z-index: 10000; font-family: Arial, sans-serif; font-size: 14px; } .paste-helper-header { background: #4CAF50; color: white; padding: 10px 15px; cursor: move; user-select: none; border-radius: 6px 6px 0 0; display: flex; justify-content: space-between; align-items: center; } .paste-helper-title { font-weight: bold; } .paste-helper-minimize { background: none; border: none; color: white; font-size: 18px; cursor: pointer; padding: 0; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; } .paste-helper-minimize:hover { background: rgba(255,255,255,0.2); border-radius: 3px; } .paste-helper-content { padding: 15px; display: block; } .paste-helper-content.collapsed { display: none; } .paste-helper-textarea { width: 100%; height: 150px; padding: 8px; border: 1px solid #ddd; border-radius: 4px; resize: vertical; font-family: 'Consolas', 'Monaco', 'Courier New', monospace; font-size: 12px; box-sizing: border-box; } .paste-helper-controls { margin-top: 10px; display: flex; gap: 10px; align-items: center; } .paste-helper-select { padding: 5px 8px; border: 1px solid #ddd; border-radius: 4px; background: white; } .paste-helper-button { padding: 8px 15px; border: none; border-radius: 4px; cursor: pointer; font-size: 12px; font-weight: bold; } .paste-helper-button.primary { background: #4CAF50; color: white; } .paste-helper-button.secondary { background: #f44336; color: white; } .paste-helper-button:hover { opacity: 0.9; } .paste-helper-status { margin-top: 8px; padding: 5px; font-size: 11px; color: #666; background: #f5f5f5; border-radius: 3px; } .paste-helper-info { margin-bottom: 10px; font-size: 12px; color: #666; } `; document.head.appendChild(style); } // 创建主界面 function createPasteHelper() { const container = document.createElement('div'); container.className = 'paste-helper-container'; // 从localStorage恢复位置 const savedPosition = localStorage.getItem('paste-helper-position'); if (savedPosition) { const pos = JSON.parse(savedPosition); container.style.top = pos.top + 'px'; container.style.right = pos.right + 'px'; } container.innerHTML = ` <div class="paste-helper-header"> <span class="paste-helper-title">超星粘贴助手</span> <button class="paste-helper-minimize" title="最小化">−</button> </div> <div class="paste-helper-content"> <div class="paste-helper-info"> 检测到编辑器: <span id="editor-count">0</span> 个 </div> <textarea class="paste-helper-textarea" placeholder="在此输入要粘贴的内容(代码/作业答案等)..."></textarea> <div class="paste-helper-controls"> <label>选择编辑器:</label> <select class="paste-helper-select"> <option value="">请选择编辑器</option> </select> <button class="paste-helper-button primary">粘贴</button> <button class="paste-helper-button secondary">清空</button> </div> <div class="paste-helper-status">就绪</div> </div> `; document.body.appendChild(container); return container; } // 更新编辑器列表 function updateEditorList() { let allEditors = []; // 检测 CodeMirror 编辑器 if (typeof window.codeEditors !== 'undefined' && window.codeEditors) { const cmKeys = Object.keys(window.codeEditors); cmKeys.forEach(key => { allEditors.push({ type: 'codemirror', id: key, name: `代码编辑器 (${key})` }); }); console.log('[粘贴助手] 检测到CodeMirror编辑器:', cmKeys.length, '个'); } // 检测 UEditor 编辑器 if (typeof window.UE !== 'undefined' && window.UE.instants) { const ueKeys = Object.keys(window.UE.instants); ueKeys.forEach(key => { const editor = window.UE.instants[key]; // 只添加有效的编辑器实例 if (editor && editor.ready) { allEditors.push({ type: 'ueditor', id: key, name: `作业编辑器 (${key})` }); } }); console.log('[粘贴助手] 检测到UEditor编辑器:', ueKeys.length, '个'); } // 注意: 超星的所有答题框都是UEditor,不存在纯textarea // textarea元素只是占位符,会被UEditor接管并隐藏 // 处理编辑器数量变化 if (allEditors.length === 0) { if (pasteHelper) { hideHelper(); } return; } else { if (!pasteHelper) { createHelperIfNeeded(); } else { showHelper(); } } // 更新UI const select = pasteHelper.querySelector('.paste-helper-select'); const countSpan = pasteHelper.querySelector('#editor-count'); if (!select || !countSpan) return; // 清空现有选项 select.innerHTML = '<option value="">请选择编辑器</option>'; // 添加编辑器选项 allEditors.forEach((editor, index) => { const option = document.createElement('option'); option.value = JSON.stringify({ type: editor.type, id: editor.id }); option.textContent = editor.name; select.appendChild(option); }); countSpan.textContent = allEditors.length; // 如果只有一个编辑器,自动选择 if (allEditors.length === 1) { select.value = JSON.stringify({ type: allEditors[0].type, id: allEditors[0].id }); } } // 粘贴内容到编辑器 function pasteCode() { const textarea = pasteHelper.querySelector('.paste-helper-textarea'); const select = pasteHelper.querySelector('.paste-helper-select'); const status = pasteHelper.querySelector('.paste-helper-status'); const content = textarea.value; const selectedEditorStr = select.value; if (!content) { status.textContent = '请输入要粘贴的内容'; status.style.color = '#f44336'; return; } if (!selectedEditorStr) { status.textContent = '请选择目标编辑器'; status.style.color = '#f44336'; return; } try { const editorInfo = JSON.parse(selectedEditorStr); const { type, id } = editorInfo; console.log('[粘贴助手] 开始粘贴到:', type, id); console.log('[粘贴助手] 内容长度:', content.length); let success = false; // 根据编辑器类型选择粘贴方法 if (type === 'codemirror') { // CodeMirror 编辑器 if (typeof window.codeEditors === 'undefined' || !window.codeEditors[id]) { throw new Error('CodeMirror编辑器不存在'); } const editor = window.codeEditors[id]; if (!editor || typeof editor.setValue !== 'function') { throw new Error('编辑器对象无效或缺少setValue方法'); } editor.setValue(content); success = true; } else if (type === 'ueditor') { // UEditor 编辑器 if (typeof window.UE === 'undefined' || !window.UE.instants || !window.UE.instants[id]) { throw new Error('UEditor编辑器不存在'); } const editor = window.UE.instants[id]; if (!editor || typeof editor.setContent !== 'function') { throw new Error('UEditor对象无效或缺少setContent方法'); } // 使用setContent绕过粘贴检测 editor.setContent(content); // 触发内容变化事件 try { if (typeof editor.fireEvent === 'function') { editor.fireEvent('contentChange'); } } catch (e) { console.warn('[粘贴助手] fireEvent失败:', e); } // 调用页面的状态更新函数 try { if (typeof window.answerContentChange === 'function') { window.answerContentChange(); } // 注意: 不调用loadEditorAnswerd,因为它内部会调用UE.getEditor() // 这会导致创建新的编辑器实例! // 用户保存时,页面会自动调用相关函数更新答题状态 } catch (e) { console.warn('[粘贴助手] 状态更新失败(不影响粘贴):', e); } success = true; } if (success) { status.textContent = `内容已成功粘贴到 ${type === 'codemirror' ? '代码编辑器' : type === 'ueditor' ? '作业编辑器' : '答题框'}`; status.style.color = '#4CAF50'; console.log('[粘贴助手] 粘贴成功'); // 保存内容到localStorage localStorage.setItem('paste-helper-last-code', content); } } catch (error) { console.error('[粘贴助手] 粘贴失败:', error); status.textContent = '粘贴失败: ' + error.message; status.style.color = '#f44336'; } } // 清空文本框 function clearCode() { const textarea = pasteHelper.querySelector('.paste-helper-textarea'); const status = pasteHelper.querySelector('.paste-helper-status'); textarea.value = ''; status.textContent = '已清空'; status.style.color = '#666'; } // 设置拖拽功能 function setupDragging() { const header = pasteHelper.querySelector('.paste-helper-header'); header.addEventListener('mousedown', (e) => { if (e.target.classList.contains('paste-helper-minimize')) return; isDragging = true; const rect = pasteHelper.getBoundingClientRect(); dragOffset.x = e.clientX - rect.left; dragOffset.y = e.clientY - rect.top; document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', handleDragEnd); e.preventDefault(); }); } function handleDrag(e) { if (!isDragging) return; const x = e.clientX - dragOffset.x; const y = e.clientY - dragOffset.y; pasteHelper.style.left = Math.max(0, Math.min(window.innerWidth - pasteHelper.offsetWidth, x)) + 'px'; pasteHelper.style.top = Math.max(0, Math.min(window.innerHeight - pasteHelper.offsetHeight, y)) + 'px'; pasteHelper.style.right = 'auto'; } function handleDragEnd() { if (isDragging) { isDragging = false; document.removeEventListener('mousemove', handleDrag); document.removeEventListener('mouseup', handleDragEnd); // 保存位置 const rect = pasteHelper.getBoundingClientRect(); const position = { top: rect.top, right: window.innerWidth - rect.right }; localStorage.setItem('paste-helper-position', JSON.stringify(position)); } } // 设置事件监听器 function setupEventListeners() { // 粘贴按钮 const pasteBtn = pasteHelper.querySelector('.paste-helper-button.primary'); pasteBtn.addEventListener('click', pasteCode); // 清空按钮 const clearBtn = pasteHelper.querySelector('.paste-helper-button.secondary'); clearBtn.addEventListener('click', clearCode); // 最小化按钮 const minimizeBtn = pasteHelper.querySelector('.paste-helper-minimize'); const content = pasteHelper.querySelector('.paste-helper-content'); let isMinimized = false; minimizeBtn.addEventListener('click', () => { isMinimized = !isMinimized; content.classList.toggle('collapsed', isMinimized); minimizeBtn.textContent = isMinimized ? '+' : '−'; minimizeBtn.title = isMinimized ? '展开' : '最小化'; }); // 快捷键支持 document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.key === 'Enter') { const textarea = pasteHelper.querySelector('.paste-helper-textarea'); if (document.activeElement === textarea) { pasteCode(); e.preventDefault(); } } }); // 编辑器选择变化时重置状态 const select = pasteHelper.querySelector('.paste-helper-select'); select.addEventListener('change', () => { const status = pasteHelper.querySelector('.paste-helper-status'); status.textContent = '就绪'; status.style.color = '#666'; }); } // 恢复上次的代码 function restoreLastCode() { const lastCode = localStorage.getItem('paste-helper-last-code'); if (lastCode) { const textarea = pasteHelper.querySelector('.paste-helper-textarea'); textarea.value = lastCode; } } // 窗口管理函数 function showHelper() { if (pasteHelper) { pasteHelper.style.display = 'block'; console.log('[粘贴助手] 显示助手窗口'); } } function hideHelper() { if (pasteHelper) { pasteHelper.style.display = 'none'; console.log('[粘贴助手] 隐藏助手窗口'); } } function removeHelper() { if (pasteHelper) { pasteHelper.remove(); pasteHelper = null; console.log('[粘贴助手] 移除助手窗口'); } } function createHelperIfNeeded() { if (!pasteHelper) { createStyles(); pasteHelper = createPasteHelper(); setupDragging(); setupEventListeners(); restoreLastCode(); console.log('[粘贴助手] 创建助手窗口'); } showHelper(); } // 监听页面变化,更新编辑器列表(防抖处理) function setupMutationObserver() { let updateTimeout; const observer = new MutationObserver(() => { // 防抖处理,避免频繁更新 if (updateTimeout) { clearTimeout(updateTimeout); } updateTimeout = setTimeout(() => { updateEditorList(); }, 1000); // 1秒后更新 }); observer.observe(document.body, { childList: true, subtree: false // 只监听直接子元素变化 }); return observer; } // 初始化 async function init() { try { // 避免重复初始化 if (isInitialized) { console.log('[粘贴助手] 已经初始化过,跳过重复初始化'); return; } console.log('[粘贴助手] 开始初始化...'); // 等待编辑器加载 const hasEditors = await waitForEditors(); if (hasEditors) { // 只在检测到编辑器时才创建界面 createHelperIfNeeded(); updateEditorList(); setupMutationObserver(); console.log('[粘贴助手] 超星粘贴助手已成功加载'); // 定期更新编辑器列表(降低频率) setInterval(() => { updateEditorList(); }, 5000); } else { console.log('[粘贴助手] 当前页面无编辑器,等待后续检测'); // 启动监听器,等待编辑器出现 setupMutationObserver(); } isInitialized = true; } catch (error) { console.error('[粘贴助手] 初始化失败:', error); } } // 启动 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址