您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
适用2025国家中小学智慧教育平台寒假研修,可快速通过视频学习。即秒刷!欢迎加入QQ交流群,及时获取最新消息!请勿随意二次发布代码,尊重原创!
当前为
// ==UserScript== // @name 2025国家中小学智慧教育平台寒假研修,可秒刷视频! // @namespace http://tampermonkey.net/zzzzzzys_国家中小学 // @version 1.0.1 // @description 适用2025国家中小学智慧教育平台寒假研修,可快速通过视频学习。即秒刷!欢迎加入QQ交流群,及时获取最新消息!请勿随意二次发布代码,尊重原创! // @author zzzzzzys // @match https://basic.smartedu.cn/teacherTraining/courseDetail?* // @match https://basic.smartedu.cn/* // @icon https://www.google.com/s2/favicons?sz=64&domain=smartedu.cn // @require https://fastly.jsdelivr.net/npm/[email protected]/crypto-js.min.js // @resource https://cdn.staticfile.org/limonte-sweetalert2/11.7.1/sweetalert2.min.css // @require https://fastly.jsdelivr.net/npm/[email protected]/dist/sweetalert2.all.min.js // @connect basic.smartedu.cn // @connect x-study-record-api.ykt.eduyun.cn // @grant unsafeWindow // @grant GM_xmlhttpRequest // @license GPL-3.0-or-later // ==/UserScript== /***************************** * 盗版可耻 * 请尊重原创劳动成果! * 作者:zzzzzzys * https://greasyfork.org/zh-CN/users/1176747-zzzzzzys * 搬运可耻 ****************************/ (function () { 'use strict'; let qqUrl="https://qm.qq.com/q/rDCbvTiV9K" let qqNum="570337037" let biliUrl="https://b23.tv/x5pFcB0" let requestObj = { fullsData: { url: "https://s-file-2.ykt.cbern.com.cn/teach/s_course/v2/activity_sets/3efdb592-138e-4854-8964-5e10f6011f33/fulls.json", method: "GET", }, resourceLearningPositions: { url: "https://x-study-record-api.ykt.eduyun.cn/v1/resource_learning_positions/", method: "PUT" }, } //样式 let style = `.button-3 { position: fixed; appearance: none; background-color: #e52b13; border: 1px solid rgba(27, 31, 35, .15); border-radius: 6px; box-shadow: rgba(27, 31, 35, .1) 0 1px 0; box-sizing: border-box; color: #ffffff; cursor: pointer; display: inline-block; font-family: -apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; font-size: 14px; font-weight: 600; line-height: 20px; padding: 6px 16px; left: 20px; top: 300px; text-align: center; text-decoration: none; user-select: none; -webkit-user-select: none; touch-action: manipulation; vertical-align: middle; white-space: nowrap; } .button-3:focus:not(:focus-visible):not(.focus-visible) { box-shadow: none; outline: none; } .button-3:hover { background-color: #2c974b; } .button-3:focus { box-shadow: rgba(46, 164, 79, .4) 0 0 0 3px; outline: none; } .button-3:disabled { background-color: #94d3a2; border-color: rgba(27, 31, 35, .1); color: rgba(255, 255, 255, .8); cursor: default; } .button-3:active { background-color: #298e46; box-shadow: rgba(20, 70, 32, .2) 0 1px 0 inset; }` const createFloatingButton = () => { // 如果按钮已存在则先移除旧实例 const existingBtn = document.getElementById('zs-helper-btn'); if (existingBtn) existingBtn.remove(); // 直接创建按钮元素(去掉外层div嵌套) const btn = document.createElement('div'); btn.id = 'zs-helper-btn'; // 确保唯一ID直接设置在元素上 btn.style.cssText = ` position: fixed; left: 0px; top: 50%; transform: translateY(-50%); background: #FF4DAF; color: white; padding: 12px 24px; border-radius: 30px; cursor: pointer; box-shadow: 0 4px 12px rgba(255,77,175,0.3); z-index: 2147483647; /* 使用最大z-index值 */ transition: 0.3s; font-family: 'Microsoft Yahei', sans-serif; white-space: nowrap; display: flex; align-items: center; gap: 8px; `; // 添加内部HTML内容 btn.innerHTML = ` <svg style="width:18px;height:18px;fill:white;" viewBox="0 0 24 24"> <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/> </svg> <span>使用指南</span> `; // 使用更可靠的事件监听方式 const handleHover = () => { btn.style.transform = 'translateY(-50%) scale(1.05)'; btn.style.boxShadow = '0 6px 16px rgba(255,77,175,0.4)'; }; const handleLeave = () => { btn.style.transform = 'translateY(-50%) scale(1)'; btn.style.boxShadow = '0 4px 12px rgba(255,77,175,0.3)'; }; btn.addEventListener('mouseenter', handleHover); btn.addEventListener('mouseleave', handleLeave); btn.addEventListener('click', showGuideDialog); document.body.appendChild(btn); return btn; }; // 显示操作指南弹窗 const showGuideDialog = () => { if (Swal) { Swal.fire({ title: '<span style="color: #FF4DAF; font-size:26px; display: flex; align-items: center; gap:8px;">📚 智能刷课指南 <div style="font-size:12px; color:#95a5a6; margin-left:auto;">v1.0.0</div></span>', html: ` <div style="text-align: left; max-width: 720px; line-height: 1.8;"> <!-- 操作步骤 --> <div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 20px;"> <div style="color: red; font-weight:500; margin-bottom:10px;"> 播放页面未正常生效请刷新页面! </div> <div style="color: #2c3e50; font-weight:500; margin-bottom:10px;"> 🚀 极速操作流程<br> </div> <div style="display: grid; grid-template-columns: 32px 1fr; gap: 10px; align-items: center;"> <div style="background: #FF4DAF; color: white; width:24px; height:24px; border-radius:50%; text-align:center; line-height:24px;">1</div> <div>进入2025研修课程播放页面</div> <div style="background: #FF4DAF; color: white; width:24px; height:24px; border-radius:50%; text-align:center; line-height:24px;">2</div> <div>等待视频加载完成(<span style="color:#e74c3c">未自动播放时</span>)</div> <div style="background: #FF4DAF; color: white; width:24px; height:24px; border-radius:50%; text-align:center; line-height:24px;">3</div> <div>点击左侧<span style="color:#FF4DAF; font-weight:bold">「即刻开刷」</span>按钮</div> </div> </div> <!-- 注意事项 --> <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-bottom:20px;"> <div style="border-left: 3px solid #FF4DAF; padding-left:12px;"> <div style="color: #e74c3c; font-weight:500; margin-bottom:8px;">⚠️ 重要提醒</div> <ul style="margin:0; padding-left:18px; color:#7f8c8d; font-size:14px;"> <li>视频最后剩下5秒需要看完</li> <li>请勿主动点击播放</li> <li>建议刷完全部视频再刷新,观看最后的几秒</li> </ul> </div> <div style="border-left: 3px solid #27ae60; padding-left:12px;"> <div style="color: #27ae60; font-weight:500; margin-bottom:8px;">💡 高效技巧</div> <ul style="margin:0; padding-left:18px; color:#7f8c8d; font-size:14px;"> <li>先刷一个视频</li> <li>点击另外一个视频</li> <li>再点击回刚刷的视频,播放完最后5s</li> </ul> </div> </div> <!-- 社群入口 --> <div style="background: linear-gradient(135deg, #FF4DAF 0%, #FF6B6B 100%); padding:15px; border-radius:8px; color:white;"> <div style="display: flex; align-items: center; gap:15px;"> <img src="https://qzonestyle.gtimg.cn/qzone/qzact/act/external/tiqq/logo.png" style="height:36px; border-radius:6px;"> <div> <div style="font-size:16px; font-weight:bold; margin-bottom:4px;">教师交流群</div> <div style="font-size:12px; opacity:0.9;">获取实时支持 | 最新功能优先体验</div> </div> </div> <a href="${qqUrl}" target="_blank" style="display: block; margin-top:12px; padding:10px; background: rgba(255,255,255,0.2); border-radius:6px; text-align:center; text-decoration:none; color:white !important; transition:0.3s; font-weight:500;"> 🎯 点击加入QQ群:${qqNum} </a> <a href="${biliUrl}" target="_blank" style="display: block; margin-top:12px; padding:10px; background: rgba(255,255,255,0.2); border-radius:6px; text-align:center; text-decoration:none; color:white !important; transition:0.3s; font-weight:500;"> 📽️ 点击观看使用教程,哔哩哔哩:${biliUrl} </a> </div> </div> `, confirmButtonText: "已了解,开始减负之旅 →", confirmButtonColor: "#FF4DAF", showCancelButton: true, cancelButtonText: "不在显示此窗口", cancelButtonColor: "#95a5a6", width: 760, customClass: { popup: 'animated pulse', title: 'swal-title-custom' }, footer: '<div style="color:#bdc3c7; font-size:12px;">请合理使用本工具</div>' }).then((result) => { // console.log(result); // console.log(Swal.DismissReason.cancel); if (result.dismiss === Swal.DismissReason.cancel) { // 跳转到课程列表页或其他操作 localStorage.setItem('noMoreDialog',"ture") } }); } } // 初始化逻辑 // 初始化逻辑优化 const init = () => { // 创建悬浮按钮 const floatBtn = createFloatingButton(); // 添加防DOM清理监听(优化版) const observer = new MutationObserver(mutations => { if (!document.body.contains(floatBtn)) { createFloatingButton(); } }); observer.observe(document.body, { childList: true }); // 添加CSS保护 const style = document.createElement('style'); style.textContent = ` #zs-helper-btn { pointer-events: auto !important; opacity: 1 !important; visibility: visible !important; } #zs-helper-btn:hover { transform: translateY(-50%) scale(1.05) !important; } `; document.head.appendChild(style); }; window.onload = function () { init() if (!location.href.includes("courseDetail") && !localStorage.getItem("noMoreDialog")) { showGuideDialog() return } if(!location.href.includes("courseDetail") && !location.href.includes('courseIndex') ) { return; } let myStyle = document.createElement('style') myStyle.innerHTML = style; document.head.appendChild(myStyle); /*let intercept=GM_GetValue*/ let div = document.createElement('div'); div.innerHTML = `<div style="left: 0;top: 300px;" id="my1" class="button-3" >即刻开刷</div> <div style="left: 0;top: 340px;" id="my2" class="button-3" >2222</div>` document.body.appendChild(div); document.getElementById('my1').addEventListener("click", async () => { try { await setProgress(requestObj.resourceLearningPositions.url + getResourceId() + '/' + getDynamicToken().token["user_id"], getVideoTime()) if (Swal) { Swal.fire({ title: "刷课成功!", html: ` <div style="text-align: left;"> <p>此视频只剩下最后5s,请刷新后再观看!建议先刷完目录下视频再刷新!</p> <hr style="margin: 10px 0;"> <p>💬 <strong>教师交流QQ群</strong></p> <p>欢迎加入交流群获取更多支持:<br> <a href="${qqUrl}" target="_blank" style="color: #FF4DAFFF; text-decoration: underline;"> 点击加入QQ群:${qqNum} </a> </p> </div> `, icon: 'success', confirmButtonColor: "#FF4DAFFF", // cancelButtonText: "取消,等会刷新", // 作者:zzzzzzys // https://greasyfork.org/zh-CN/users/1176747-zzzzzzys // 搬运可耻 confirmButtonText: "确定", }).then((result) => { if (result.isConfirmed) { } }); } } catch (e) { console.error(e) if (Swal) { Swal.fire({ title: "失败!", text: e, icon: 'error', // showCancelButton: true, confirmButtonColor: "#FF4DAFFF", // cancelButtonText: "取消,等会刷新", confirmButtonText: "点击去反馈", }).then((result) => { if (result.isConfirmed) { window.open("https://greasyfork.org/zh-CN/scripts/525037/feedback") } }); } } }) document.getElementById('my2').addEventListener('click', function() { Swal.fire({ title: '<span style="font-size:24px; color: #FF4DAF;">欢迎加入交流群</span>', html: ` <div style="text-align: left; max-width: 580px; line-height: 1.7; font-size: 14px;"> <!-- 社群入口 --> <div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 20px;"> <h3 style="margin:0 0 12px 0; color: #2c3e50;"> <img src="https://qzonestyle.gtimg.cn/qzone/qzact/act/external/tiqq/logo.png" style="height:20px; vertical-align:middle;"> QQ群 </h3> <div style="color: #e74c3c; font-weight:500;"> 群号:<span style="font-family: monospace;">${qqNum}</span> </div> <a href="${qqUrl}" target="_blank" style="display: inline-block; margin-top:10px; padding:8px 20px; background: #FF4DAF; color: white !important; border-radius:20px; text-decoration: none; transition:0.3s;"> 🚀 一键加入群聊 </a> </div> <!-- 核心价值 --> <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px;"> <!-- 左列 --> <div style="padding-right:15px; border-right:1px dashed #eee;"> <div style="color: #27ae60; margin-bottom:15px;"> <h4 style="margin:0 0 8px 0; font-size:15px;">📚 减负工具</h4> <!-- <ul style="margin:0; padding-left:18px;">--> <!-- <li>自动化备课工具套件</li>--> <!-- <li>智能学情分析报告</li>--> <!-- <li>教学资源智能检索</li>--> <!-- </ul>--> </div> <div style="color: #2980b9; margin-top:15px;"> <h4 style="margin:0 0 8px 0; font-size:15px;">🛡️ 使用规范</h4> <ul style="margin:0; padding-left:18px;"> <li>仅限中小学课程使用</li> <li>禁止商业倒卖行为</li> <li>请勿批量自动化操作大量刷课</li> </ul> </div> </div> <!-- 右列 --> <div style="padding-left:15px;"> <div style="color: #e67e22;"> <h4 style="margin:0 0 8px 0; font-size:15px;">⚖️ 版权声明</h4> <ul style="margin:0; padding-left:18px;"> <li>本工具完全免费</li> <li>源码禁止二次传播</li> <!-- <li>保留原创法律权利</li>--> </ul> </div> <div style="color: #9b59b6; margin-top:15px;"> <h4 style="margin:0 0 8px 0; font-size:15px;">💌 联系我们</h4> <ul style="margin:0; padding-left:18px;"> <!-- <li>反馈建议:[email protected]</li>--> <li>紧急问题:请私聊群管理员</li> </ul> </div> </div> </div> </div> `, icon: 'info', confirmButtonColor: "#FF4DAF", confirmButtonText: "2222", showCloseButton: true, width: 680, showDenyButton: true, denyButtonText: '<img src="https://img.icons8.com/fluency/24/star--v1.png" style="height:18px; vertical-align:middle;"> 前往好评', // 带图标的按钮 denyButtonColor: '#FFC107', focusDeny: false, showCancelButton: false, // 新增按钮回调 preDeny: () => { window.open("https://greasyfork.org/zh-CN/scripts/525037/feedback", "_blank"); return false; // 阻止弹窗关闭 }, customClass: { denyButton: 'swal-custom-deny', popup: 'swal-custom-popup', title: 'swal-custom-title' }, footer: '<div style="color:#95a5a6; font-size:12px;">请合理使用。</div>' }); }); } function getVideoTime() { return Math.round(document.querySelector('video').duration) } function getResourceId() { // 获取目标元素 const divElement = document.querySelector('div.vjs-poster'); if (divElement) { const bgImage = divElement.style.backgroundImage; const uuidPattern = /assets\/([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/; const match = bgImage.match(uuidPattern); if (match) { const resId = match[1]; console.log(resId); return resId } } throw Error("can not get ResourceId!") } function getDynamicToken() { try { const pattern = /^ND_UC_AUTH-([0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12})&ncet-xedu&token$/; for (let key of Object.keys(localStorage)) { if (pattern.test(key)) { return { key: key, appId: key.match(pattern)[1], token: JSON.parse(JSON.parse(localStorage.getItem(key)).value) }; } } throw Error("Invalid token! can not get loginInfo!"); } catch (err) { throw Error("At:getDynamicToken>>" + err); } } // const tokenData = getDynamicToken(); // if (tokenData) { // console.log("完整键名:", tokenData.key); // console.log("用户UUID:", tokenData.uuid); // console.log("Token值:", tokenData.token); // } // 作者:zzzzzzys // https://greasyfork.org/zh-CN/users/1176747-zzzzzzys // 搬运可耻 const getMACAuthorizationHeaders = function (url, method) { let n = getDynamicToken().token return He(url, method, { accessToken: n.access_token, macKey: n.mac_key, diff: n.diff }); } function Ze(e) { for (var t = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""), n = "", r = 0; r < e; r++) n += t[Math.ceil(35 * Math.random())]; return n } function Fe(e) { return (new Date).getTime() + parseInt(e, 10) + ":" + Ze(8) } function ze(e, t, n, r) { let o = { relative: new URL(e).pathname, authority: new URL(e).hostname } let i = t + "\n" + n.toUpperCase() + "\n" + o.relative + "\n" + o.authority + "\n"; return CryptoJS.HmacSHA256(i, r).toString(CryptoJS.enc.Base64) } function He(e) { // 作者:zzzzzzys // https://greasyfork.org/zh-CN/users/1176747-zzzzzzys // 搬运可耻 let t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "GET" , n = arguments.length > 2 ? arguments[2] : void 0 , r = n.accessToken , o = n.macKey , i = n.diff , s = Fe(i) , a = ze(e, s, t, o); return 'MAC id="'.concat(r, '",nonce="').concat(s, '",mac="').concat(a, '"') } const setProgress = function (url, duration) { const info = getDynamicToken() return new Promise((resolve, reject) => { GM_xmlhttpRequest({ 'url': url, method: 'PUT', "headers": { "accept": "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", "authorization": getMACAuthorizationHeaders(url, 'PUT'), "cache-control": "no-cache", "pragma": "no-cache", "content-type": "application/json", "sdp-app-id": info.appId, "sec-ch-ua": "\"Not A(Brand\";v=\"8\", \"Chromium\";v=\"132\", \"Microsoft Edge\";v=\"132\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"Windows\"", "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "cross-site", "host": "x-study-record-api.ykt.eduyun.cn", "origin": "https://basic.smartedu.cn", "referer": "https://basic.smartedu.cn/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0" }, data: JSON.stringify({position: duration - 3}), // fetch:true, onload: function (res) { console.log('请求成功') console.log(res) if (res.status === 200) { console.log("刷课成功!") resolve(res) } }, onerror: function (err) { reject('请求错误!' + err.toString()) } }) }) } })()