雨课堂部分辅助脚本
前言
由于我的一门水课老师使用了雨课堂的MOOC进行授课,而这部分的成绩最终也按比例算在期末分数中。
于是我和好朋友合作完成,但在互通有无的过程中遇到了一点点小问题,答案交流实在太过繁琐。
这怎能忍!我花了一点时间,完成了下述脚本,以加快知识共享的速度。
介绍
- 雨课堂单元测试导出
- 雨课堂考试结果(试卷)导出
单元测试
/*
*Title: 雨课堂单元测试导出
*Description: F12(/homework)
*Author: Tominysun
*Created: 2023/03/05
*Updated: 2023/03/15
*/
var text = document.querySelector('.text.text-ellipsis').innerText + "\n";
for (var i = 1; i <= parseInt(document.querySelector('.aside-body--progress span').innerText); i++) {
(function(t, data) { // 注意这里是形参
setTimeout(function() {
text += document.querySelector('.subject-item.active').innerText + "."; //题号;
text += document.querySelector('.item-body').innerText + "\n"; //document.querySelector('.problem-body').innerHTML + "\n"; //题干
text += document.querySelector('.problem-remark').innerText + "\n"; //.match(/正确答案:\s*(.*)/)[1] + "\n"; //正确答案
document.querySelector('.text-right button').click(); //下一题
//最后一题,输出txt
if (parseInt(document.querySelector('.subject-item.active').innerText) === parseInt(document.querySelector('.aside-body--progress span').innerText)) {
exportTxt(document.querySelector('.text.text-ellipsis').innerText + ".txt", text);
}
}, 1000 * t);
})();
}
function exportTxt(fileName, data) {
data = data.replace(/\n/g, "\r\n");
if (navigator.userAgent.indexOf("Trident") >= 0) {
try {
// IE 10 或以上
var fileObj = new Blob([data]);
navigator.msSaveBlob(fileObj, fileName);
} catch (ex) {
// IE 9 或以下
var winSave = window.open();
winSave.document.open("text", "utf-8");
winSave.document.write(data);
winSave.document.execCommand("SaveAs", true, fileName);
winSave.close();
}
} else {
// Webkit
var urlObject = window.URL || window.webkitURL || window;
var export_blob = new Blob([data]);
var save_link = document.createElement("a");
save_link.href = urlObject.createObjectURL(export_blob);
save_link.download = fileName;
save_link.click();
}
}
考试结果
/*
*Title: 雨课堂考试结果(试卷)导出
*Description: F12(https://examination.xuetangx.com/result/*)
*Author: Tominysun
*Created: 2023/03/15
*Updated: 2023/03/15
*/
var text = document.querySelector(".header-title").innerText + "\n" + document.querySelector(".exam-main--body").innerText;
function exportTxt(fileName, data) {
data = data.replace(/\n/g, "\r\n");
if (navigator.userAgent.indexOf("Trident") >= 0) {
try {
// IE 10 或以上
var fileObj = new Blob([data]);
navigator.msSaveBlob(fileObj, fileName);
} catch (ex) {
// IE 9 或以下
var winSave = window.open();
winSave.document.open("text", "utf-8");
winSave.document.write(data);
winSave.document.execCommand("SaveAs", true, fileName);
winSave.close();
}
} else {
// Webkit
var urlObject = window.URL || window.webkitURL || window;
var export_blob = new Blob([data]);
var save_link = document.createElement("a");
save_link.href = urlObject.createObjectURL(export_blob);
save_link.download = fileName;
save_link.click();
}
}
exportTxt(document.querySelector(".header-title").innerText + ".txt",text);
修改
以下是我最早的版本:
var text = $('.text.text-ellipsis').innerText + "\n";
document.addEventListener("keydown",keydown);
function keydown(event) {
if (event.keyCode == 83) { //event.ctrlKey && event.altKey &&
for (var i = 1; i <= parseInt($('.aside-body--progress span').innerText); i++) {
(function(t, data) { // 注意这里是形参
setTimeout(function() {
text += $('.subject-item.active').innerText + "."; //题号;
text += $('.item-body').innerText + "\n"; //$('.problem-body').innerHTML + "\n"; //题干
text += $('.problem-remark').innerText + "\n"; //.match(/正确答案:\s*(.*)/)[1] + "\n"; //正确答案
$('.text-right button').click(); //下一题
//if(t = parseInt($('.aside-body--progress span').innerText)){alert(text);}
}, 1000 * t);
})();
}
}
if (event.keyCode == 67) { //event.ctrlKey && event.altKey &&
alert(text);
}
}
alert('用户脚本开始执行!按s键开始,结束后按c键复制。');
为方便执行,压缩后代码如下。
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5 0=$(\'.0.0-e\').2+"\\n";f.g("3",3);4 3(b){6(b.7==h){j(5 i=1;i<=k($(\'.l-8--m o\').2);i++){(4(t,a){p(4(){0+=$(\'.q-9.r\').2+".";0+=$(\'.9-8\').2+"\\n";0+=$(\'.u-v\').2+"\\n";$(\'.0-w x\').y()},z*t)})()}}6(b.7==A){d(0)}}d(\'用户脚本开始执行!按s键开始,结束后按c键复制。\');',37,37,'text||innerText|keydown|function|var|if|keyCode|body|item||||alert|ellipsis|document|addEventListener|83||for|parseInt|aside|progress||span|setTimeout|subject|active|||problem|remark|right|button|click|1000|67'.split('|'),0,{}))
我当时的开发及调试环境是Firefox,但上述脚本迁移到Chrome(Edge)平台后无法运行。
我目前对具体错误原因尚不得而知,但修Bug的思路还是很明确的。将所有使用Jquery的部分全部改为原生JS实现,即可完美修复原有的Bug。
以下是修复后的版本:
var text = document.querySelector('.text.text-ellipsis').innerText + "\n";
document.addEventListener("keydown",keydown);
function keydown(event) {
if (event.keyCode == 83) { //event.ctrlKey && event.altKey &&
for (var i = 1; i <= parseInt(document.querySelector('.aside-body--progress span').innerText); i++) {
(function(t, data) { // 注意这里是形参
setTimeout(function() {
text += document.querySelector('.subject-item.active').innerText + "."; //题号;
text += document.querySelector('.item-body').innerText + "\n"; //document.querySelector('.problem-body').innerHTML + "\n"; //题干
text += document.querySelector('.problem-remark').innerText + "\n"; //.match(/正确答案:\s*(.*)/)[1] + "\n"; //正确答案
document.querySelector('.text-right button').click(); //下一题
//if(t = parseInt(document.querySelector('.aside-body--progress span').innerText)){alert(text);}
}, 1000 * t);
})();
}
}
if (event.keyCode == 67) { //event.ctrlKey && event.altKey &&
//alert(text);
copy();
}
if (event.keyCode == 68) {
exportTxt(document.querySelector('.text.text-ellipsis').innerText + ".txt",text);
}
}
function copy() {
const txt = text;
// 添加一个input元素放置需要的文本内容
const dataContainer = document.createElement('textarea');
dataContainer.value = txt;
document.body.appendChild(dataContainer);
// 选中并复制文本到剪切板
dataContainer.select();
document.execCommand('copy');
// 移除input元素
document.body.removeChild(dataContainer);
alert('复制成功');
}
function exportTxt(fileName, data) {
data = data.replace(/\n/g, "\r\n");
if (navigator.userAgent.indexOf("Trident") >= 0) {
try {
// IE 10 或以上
var fileObj = new Blob([data]);
navigator.msSaveBlob(fileObj, fileName);
} catch (ex) {
// IE 9 或以下
var winSave = window.open();
winSave.document.open("text", "utf-8");
winSave.document.write(data);
winSave.document.execCommand("SaveAs", true, fileName);
winSave.close();
}
} else {
// Webkit
var urlObject = window.URL || window.webkitURL || window;
var export_blob = new Blob([data]);
var save_link = document.createElement("a");
save_link.href = urlObject.createObjectURL(export_blob);
save_link.download = fileName;
save_link.click();
}
}
alert('用户脚本开始执行!按s键开始,结束后按c键复制,按d键下载。');
为方便执行,压缩后代码如下。
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('4 3=2.5(\'.3.3-q\').6+"\\n";2.F("l",l);7 l(b){h(b.m==G){H(4 i=1;i<=I(2.5(\'.J-j--K L\').6);i++){(7(t,a){M(7(){3+=2.5(\'.N-u.O\').6+".";3+=2.5(\'.u-j\').6+"\\n";3+=2.5(\'.P-Q\').6+"\\n";2.5(\'.3-R S\').v()},T*t)})()}}h(b.m==U){o()}h(b.m==V){w(2.5(\'.3.3-q\').6+".p",3)}}7 o(){x p=3;x 9=2.y(\'W\');9.X=p;2.j.Y(9);9.Z();2.z(\'o\');2.j.10(9);A(\'复制成功\')}7 w(a,b){b=b.11(/\\n/g,"\\r\\n");h(B.12.13("14")>=0){15{4 c=C D([b]);B.16(c,a)}17(18){4 d=k.E();d.2.E("3","19-8");d.2.1a(b);d.2.z("1b",1c,a);d.1d()}}1e{4 e=k.1f||k.1g||k;4 f=C D([b]);4 g=2.y("a");g.1h=e.1i(f);g.1j=a;g.v()}}A(\'用户脚本开始执行!按s键开始,结束后按c键复制,按d键下载。\');',62,82,'||document|text|var|querySelector|innerText|function||dataContainer||||||||if||body|window|keydown|keyCode||copy|txt|ellipsis||||item|click|exportTxt|const|createElement|execCommand|alert|navigator|new|Blob|open|addEventListener|83|for|parseInt|aside|progress|span|setTimeout|subject|active|problem|remark|right|button|1000|67|68|textarea|value|appendChild|select|removeChild|replace|userAgent|indexOf|Trident|try|msSaveBlob|catch|ex|utf|write|SaveAs|true|close|else|URL|webkitURL|href|createObjectURL|download'.split('|'),0,{}))
上述代码的实现方式依赖手动操作,最终版本实现完全自动化,取消复制,并且使用txt导出。
学习
在上述编写过程中,绝大部分内容都是互联网随处可找。整体脚本技术含量可以忽略。
但还是学到了一点(或者说发现了原来忽视的东西)。
data = data.replace(/\n/g, "\r\n");
注意到上述这行代码了吗?
最开始的txt导出函数,会导致原来字符串中的换行无法正确显示。
我一开始愣是找不到哪里出了问题。
因为我使用\n
在浏览器环境并没有出现问题,但导出生成txt后就无法正确显示。
原因在于Windows系统环境下,换行符需要使用\r\n
。
因此,生成txt之前,使用正则进行一次批量替换,即可解决。
(上述bug的解决方案是New Bing告诉我的...)
鸣谢
- New Bing