// ==UserScript==
// @name 🥇(云端热更新版)超星学习通|知到智慧树--网课小助手|AI自动答题|答案校验|AI+题库调用费用1元100+次|飘飘友情提供|自动跳转任务点|自动答题|超高题库覆盖率|逐渐支持更多平台
// @namespace 飘飘
// @version 1.0.0
// @author PIAOPIAO
// @description 轻量级引导脚本,自动从脚本猫平台拉取最新代码执行。支持热更新,无需手动更新脚本。当前版本跟随云端脚本版本号。
// @icon http://pan-yz.chaoxing.com/favicon.ico
// @match *://*.chaoxing.com/*
// @match *://*.xuexitong.com/*
// @match *://*.edu.cn/*
// @match *://*.nbdlib.cn/*
// @match *://*.hnsyu.net/*
// @match *://*.gdhkmooc.com/*
// @match *://onlineexamh5new.zhihuishu.com/*
// @require https://lib.baomitu.com/vue/3.5.0/vue.global.prod.js
// @require https://lib.baomitu.com/vue-demi/0.14.7/index.iife.js
// @require data:application/javascript,window.Vue%3DVue%3B
// @require https://lib.baomitu.com/element-plus/2.7.2/index.full.min.js
// @require https://lib.baomitu.com/pinia/2.3.1/pinia.iife.min.js
// @require https://lib.baomitu.com/rxjs/7.8.2/rxjs.umd.min.js
// @require https://lib.baomitu.com/blueimp-md5/2.19.0/js/md5.min.js
// @resource ElementPlus https://lib.baomitu.com/element-plus/2.7.2/index.css
// @resource ElementPlusStyle https://lib.baomitu.com/element-plus/2.8.2/index.min.css
// @resource ttf https://www.forestpolice.org/ttf/2.0/table.json
// @connect scriptcat.org
// @connect 43.139.12.117
// @grant GM_addStyle
// @grant GM_getResourceText
// @grant GM_getValue
// @grant GM_info
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @run-at document-start
// @antifeature payment 答案需调用AI的API需收费
// ==/UserScript==
(function () {
'use strict';
const CONFIG = {
VERSION_SERVER: {
VERSION_URL: 'http://43.139.12.117:3000/version',
},
SCRIPTCAT: {
SCRIPT_ID: '5597',
SCRIPT_NAME: '超星学习通|知到智慧树--网课小助手',
CODE_URL: 'https://scriptcat.org/scripts/code/5597/%E8%B6%85%E6%98%9F%E5%AD%A6%E4%B9%A0%E9%80%9A%EF%BD%9C%E7%9F%A5%E5%88%B0%E6%99%BA%E6%85%A7%E6%A0%91--%E7%BD%91%E8%AF%BE%E5%B0%8F%E5%8A%A9%E6%89%8B.user.js'
},
CACHE_KEY: 'cloud_script_cache',
VERSION_KEY: 'cloud_script_version',
LAST_CHECK_KEY: 'last_check_time'
};
const log = {
info: (msg, ...args) => console.log(`%c[云端脚本] ${msg}`, 'color: #667eea; font-weight: bold;', ...args),
success: (msg, ...args) => console.log(`%c[云端脚本] ✓ ${msg}`, 'color: #10b981; font-weight: bold;', ...args),
warn: (msg, ...args) => console.warn(`%c[云端脚本] ⚠ ${msg}`, 'color: #f59e0b; font-weight: bold;', ...args),
error: (msg, ...args) => console.error(`%c[云端脚本] ✗ ${msg}`, 'color: #ef4444; font-weight: bold;', ...args)
};
let loadingWindow = null;
function showLoadingWindow() {
if (loadingWindow) return;
const createLoading = () => {
loadingWindow = document.createElement('div');
loadingWindow.id = 'cloud-script-loading-window';
loadingWindow.innerHTML = `
脚本正在加载...
请稍候,正在从云端获取最新代码
`;
loadingWindow.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
display: flex;
align-items: center;
justify-content: center;
z-index: 2147483647;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
`;
const style = document.createElement('style');
style.id = 'cloud-script-loading-styles';
style.textContent = `
#cloud-script-loading-window .loading-content {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 40px 60px;
border-radius: 16px;
text-align: center;
box-shadow: 0 20px 60px rgba(102, 126, 234, 0.4);
animation: loadingPulse 2s ease-in-out infinite;
}
#cloud-script-loading-window .loading-spinner {
width: 50px;
height: 50px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-top-color: white;
border-radius: 50%;
animation: loadingSpin 1s linear infinite;
margin: 0 auto 20px;
}
#cloud-script-loading-window .loading-text {
color: white;
font-size: 18px;
font-weight: 600;
margin-bottom: 8px;
}
#cloud-script-loading-window .loading-subtext {
color: rgba(255, 255, 255, 0.8);
font-size: 13px;
}
@keyframes loadingSpin {
to { transform: rotate(360deg); }
}
@keyframes loadingPulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.02); }
}
`;
document.head.appendChild(style);
document.body.appendChild(loadingWindow);
log.info('加载窗口已显示');
};
if (document.body) {
createLoading();
} else {
document.addEventListener('DOMContentLoaded', createLoading);
}
}
function hideLoadingWindow() {
if (loadingWindow) {
loadingWindow.style.opacity = '0';
loadingWindow.style.transition = 'opacity 0.3s ease';
setTimeout(() => {
if (loadingWindow) {
loadingWindow.remove();
loadingWindow = null;
const style = document.getElementById('cloud-script-loading-styles');
if (style) style.remove();
log.info('加载窗口已关闭');
}
}, 300);
}
}
window.__closeLoadingWindow__ = hideLoadingWindow;
function compareVersion(v1, v2) {
const parts1 = v1.split('.').map(Number);
const parts2 = v2.split('.').map(Number);
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
const p1 = parts1[i] || 0;
const p2 = parts2[i] || 0;
if (p1 > p2) return 1;
if (p1 < p2) return -1;
}
return 0;
}
function httpGet(url, isText = false) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'GET',
url: url,
timeout: 15000,
onload: (response) => {
if (response.status === 200) {
resolve(isText ? response.responseText : response.response);
} else {
reject(new Error(`HTTP ${response.status}`));
}
},
onerror: () => reject(new Error('网络请求失败')),
ontimeout: () => reject(new Error('请求超时'))
});
});
}
function getLocalCache() {
return {
version: GM_getValue(CONFIG.VERSION_KEY, ''),
code: GM_getValue(CONFIG.CACHE_KEY, ''),
lastCheck: GM_getValue(CONFIG.LAST_CHECK_KEY, 0)
};
}
function saveLocalCache(version, code) {
GM_setValue(CONFIG.VERSION_KEY, version);
GM_setValue(CONFIG.CACHE_KEY, code);
GM_setValue(CONFIG.LAST_CHECK_KEY, Date.now());
}
async function fetchLatestVersion() {
try {
log.info('从服务器获取版本信息...');
const response = await httpGet(CONFIG.VERSION_SERVER.VERSION_URL, true);
const data = JSON.parse(response);
if (data.code === 200 && data.data && data.data.latestVersion) {
log.info(`服务器最新版本: ${data.data.latestVersion}`);
return data.data.latestVersion;
} else {
throw new Error('版本信息格式错误');
}
} catch (e) {
log.error('获取版本信息失败:', e.message);
throw e;
}
}
async function downloadScriptCode() {
try {
log.info('从脚本猫下载脚本代码...');
const code = await httpGet(CONFIG.SCRIPTCAT.CODE_URL, true);
const versionMatch = code.match(/@version\s+(\d+\.\d+\.\d+)/);
const version = versionMatch ? versionMatch[1] : 'unknown';
log.success(`下载完成,版本: ${version}`);
return { code, version };
} catch (e) {
log.error('下载脚本失败:', e.message);
throw e;
}
}
function executeCode(code) {
try {
log.info('执行脚本代码...');
window.__CLOUD_SCRIPT_LOADED__ = true;
const codeStart = code.indexOf('// ==/UserScript==');
let executableCode = code;
if (codeStart !== -1) {
executableCode = code.substring(codeStart + '// ==/UserScript=='.length);
}
executableCode = executableCode.trim();
if (typeof Vue === 'undefined') {
throw new Error('Vue 未加载,请检查 @require 配置');
}
log.info('依赖库检查: Vue=' + (typeof Vue !== 'undefined') + ', Pinia=' + (typeof Pinia !== 'undefined') + ', RxJS=' + (typeof rxjs !== 'undefined') + ', MD5=' + (typeof md5 !== 'undefined') + ', ElementPlus=' + (typeof ElementPlus !== 'undefined'));
eval(executableCode);
log.success('脚本执行成功');
setupMainWindowObserver();
} catch (e) {
log.error('脚本执行失败:', e.message);
hideLoadingWindow();
throw e;
}
}
function setupMainWindowObserver() {
const closeAfterInit = () => {
setTimeout(() => {
log.info('脚本初始化完成,关闭加载窗口');
hideLoadingWindow();
}, 500);
};
if (document.readyState === 'complete') {
closeAfterInit();
} else {
window.addEventListener('load', closeAfterInit);
}
}
function showNotification(message, type = 'info') {
const colors = {
info: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
success: 'linear-gradient(135deg, #10b981 0%, #059669 100%)',
error: 'linear-gradient(135deg, #ef4444 0%, #dc2626 100%)'
};
const toast = document.createElement('div');
toast.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 12px 20px;
background: ${colors[type]};
color: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 2147483647;
font-size: 14px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
animation: slideIn 0.3s ease;
`;
toast.textContent = message;
if (!document.getElementById('cloud-script-styles')) {
const style = document.createElement('style');
style.id = 'cloud-script-styles';
style.textContent = `
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
`;
document.head.appendChild(style);
}
document.body.appendChild(toast);
setTimeout(() => {
toast.style.animation = 'slideIn 0.3s ease reverse';
setTimeout(() => toast.remove(), 300);
}, 3000);
}
let cloudVersion = GM_getValue(CONFIG.VERSION_KEY, 'unknown');
window.__CLOUD_SCRIPT_VERSION__ = cloudVersion;
async function main() {
log.info('='.repeat(50));
log.info('云端热更新脚本启动(脚本猫版)');
log.info(`当前云端版本: v${cloudVersion}`);
log.info('='.repeat(50));
if (window.self !== window.top) {
log.info('检测到在 iframe 中运行,跳过');
return;
}
showLoadingWindow();
try {
const localCache = getLocalCache();
let code = localCache.code;
let version = localCache.version;
try {
log.info('检查版本更新...');
const latestVersion = await fetchLatestVersion();
if (!localCache.version || compareVersion(latestVersion, localCache.version) > 0) {
log.info(`发现新版本: ${localCache.version || '无'} → ${latestVersion}`);
const result = await downloadScriptCode();
code = result.code;
version = result.version;
cloudVersion = version;
window.__CLOUD_SCRIPT_VERSION__ = version;
saveLocalCache(version, code);
if (document.body) {
showNotification(`🔄 脚本已更新到 v${version}`, 'success');
}
} else {
log.success(`已是最新版本 v${localCache.version}`);
}
} catch (e) {
log.warn('检查更新失败,使用本地缓存:', e.message);
if (!code) {
throw new Error('网络异常且无本地缓存,无法启动脚本');
}
}
if (code) {
executeCode(code);
} else {
throw new Error('没有可执行的代码');
}
} catch (e) {
log.error('脚本启动失败:', e.message);
hideLoadingWindow();
const showError = () => {
const errorDiv = document.createElement('div');
errorDiv.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 24px 32px;
background: white;
border: 1px solid #fecaca;
border-radius: 12px;
color: #dc2626;
z-index: 999999;
font-size: 14px;
text-align: center;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
`;
errorDiv.innerHTML = `
❌
脚本加载失败
${e.message}
`;
document.body.appendChild(errorDiv);
};
if (document.body) {
showError();
} else {
document.addEventListener('DOMContentLoaded', showError);
}
}
}
main();
})();