Skip to content

Commit

Permalink
fix/feat: BIT-Programming-Detect and BIT-乐学-修改侧边栏课程-GUI (#33)
Browse files Browse the repository at this point in the history
BIT-Programming-Detect:
1. 从某字符开始探测,结果仍然从第0个字符开始,已修改;
2. 半秒检查一次测试结果太频繁,容易被封IP,测试发现改成一秒一次即可

BIT-乐学-修改侧边栏课程-GUI:
1. 更换课程列表数据来源,能够在更新课程列表信息时按照课程结束时间倒序展示;
2. 更新课程列表时,能够对比并整合课程列表,将新增的课程插入“隐藏的课程”列表头部并用红色粗体标识;
3. 添加了图标更换的功能,双击弹窗列表中项目的图标并输入新图标名称,可以更改图标;
4. 解决更改课程名称时写入html标签被解析的问题;
5. 解决代码在获取课程名称时前后保留大量空格和换行符的毛病

可参见 https://github.com/CJJ-amateur-programmer/BIT_lexue_sidebar_optimizer

Co-Authored-By: Y.D.X. <[email protected]>
Co-Authored-By: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 10, 2024
1 parent a782a76 commit 0140cec
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 61 deletions.
2 changes: 1 addition & 1 deletion TamperMonkey/BIT-Programming-Detect.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

**注意**

1. 这个程序会频繁向服务器发送固定模式的C语言代码,并通过每秒2次的请求确定是否编译完毕。因此,您不应该频繁或长时间使用此程序,否则可能给服务器造成巨大的压力。
1. 这个程序会频繁向服务器发送固定模式的C语言代码,然后每秒检查一次是否编译完毕。因此,您不应该频繁或长时间使用此程序,否则可能给服务器造成巨大的压力。
2. 这个程序仅在最新版 Microsoft Edge 中采用篡改猴和篡改猴测试版试验过,不保证在 IE、Firefox 等浏览器或其他脚本管理器中正确运行。
3. 请在规定范围内使用程序。任何因使用不当而产生的后果责任自负,本人不承担任何相关责任。
4. 本脚本采用 GPL 3.0 许可。
Expand Down
11 changes: 5 additions & 6 deletions TamperMonkey/BIT-Programming-Detect.user.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// ==UserScript==
// @name BIT-Programming-Detect
// @namespace http://tampermonkey.net/
// @version 0.1.1
// @version 0.1.2
// @description 通过提交C语言程序,逐字符确定测试用例。为符合编程人员的习惯,字符默认从第0个开始。文本框中输入Enter键可以直接开始探测。在结束文本框输入非数字时,会持续探测。探测到所有的测试用例都OF时探测会结束。支持的测试用例字符:ASCII -1, 8-13, 32-126。
// @license GPL-3.0-or-later
// @supportURL https://github.com/YDX-2147483647/BIT-enhanced/issues
Expand Down Expand Up @@ -193,9 +193,8 @@
// ASCII 32-126能够正常显示,统一减去32以显示在耗时的前两位上,对应0-94;
// ASCII 8-13是特殊符号\b\t\n\v\f\r,保险起见也放进来,对应95-100,其中100一般会报“TLE”;如果无时间限制则会显示“1.001”左右的数字,同样可以读取。
// 这样,常用的字符能够全部表示在运行结果页面上,类似于加密。
fm.set('code', '#include<stdio.h>\n#include<time.h>\nvoid delay(int seconds){clock_t start = clock();clock_t lay=(clock_t)seconds*CLOCKS_PER_SEC/1000;while((clock()-start)<lay);}int main(){int x;long long i;for(i=' +
start + ';i<' +
i + ';i++)getchar();x=getchar()-32;if(x==-33)return 1/0;else if(x<-18&&x>-25)x+=119;delay(x*10);return 0;}')
fm.set('code', '#include<stdio.h>\n#include<time.h>\nvoid delay(int seconds){clock_t start = clock();clock_t lay=(clock_t)seconds*CLOCKS_PER_SEC/1000;while((clock()-start)<lay);}int main(){int x;long long i;for(i=0;i<' +
i + ';i++)getchar();x=getchar()-32;if(x==-33)return 1/0;else if(x<-18&&x>-25)x+=119;delay(x*10);return 0;}')
const xhr = new XMLHttpRequest()
xhr.open('POST', 'https://lexue.bit.edu.cn/mod/programming/submit.php', true)
xhr.send(fm)
Expand Down Expand Up @@ -224,8 +223,8 @@
}
x.send()
},
// 500意味着每0.5秒查看一次运行结果页面
500)
// 1000意味着每1秒查看一次运行结果页面
1000)
})
if (!result) { // 出错
const partial_content = document.querySelector('title').innerText + ' 保密测试用例(字符:' + start + '~' + (i - 1) + ')\n探测于' + new Date().toLocaleString() + '\n' + print_arguments(arguments_)// 写入txt的探测内容
Expand Down
12 changes: 9 additions & 3 deletions TamperMonkey/BIT-乐学-修改侧边栏课程-GUI.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@
-**更新课程并修改侧边栏**”将发送网络请求并获取最新的课程情况,列在“显示的课程”一栏;
-**仅修改侧边栏**”则从本地篡改猴储存中获取课程情况。

此外在弹窗中双击格子,还可**编辑课程名称**(粘贴文本时会自动去除换行和格式)。完成后请按<kbd>Enter</kbd>或者单击旁边空白处来退出编辑模式。
此外还可在弹窗界面**编辑课程显示效果**

- **名称**:双击格子,直接修改,或者粘贴文本(会自动去除换行和格式);
- **图标**:双击课程名称前的图标,可直接编辑。这是FontAwesome v4 的图标名称,乐学原本为`graduation-cap`,具体请参考 [Font Awesome Icons](https://fontawesome.com/v4/icons/)[Font Awesome 中文网](https://fontawesome.com.cn/v4/icons)

完成后请按<kbd>Enter</kbd>或者单击旁边空白处来退出编辑模式。

## 兼容性

这段脚本与“[BIT-乐学-修改侧边栏课程](https://greasyfork.org/scripts/470832)”矛盾,同时启用时效果不确定。

- 此脚本的操作方式远比无GUI版直观,直接拖动即可;
- 无GUI版能修改图标,此脚本目前还不能。
- 此脚本的操作方式远比无GUI版直观,直接拖动即可;而且能拉取全部课程列表,方便每学期更新。
- 无GUI版是原初版本,功能已经全面落后,除了代码简洁外基本没有优势。
- 网上新增课程后,目前两脚本设计了不同的默认行为。此脚本会将新课插入“隐藏的课程”列表开头,并用红色粗体标识;无GUI版则不作为,无论网上原本显示与否,都保持原样。

欢迎有志之士前往 [YDX-2147483647/BIT-enhanced](https://github.com/YDX-2147483647/BIT-enhanced) 帮忙合并两段脚本。
79 changes: 30 additions & 49 deletions TamperMonkey/BIT-乐学-修改侧边栏课程-GUI.user.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
// ==UserScript==
// @name BIT-乐学-修改侧边栏课程-GUI
// @namespace http://tampermonkey.net/
// @version 0.1.2
// @version 1.0.0
// @description 修改侧边栏显示的课程
// @license GPL-3.0-or-later
// @supportURL https://github.com/YDX-2147483647/BIT-enhanced/issues
// @author CJJ
// @match *://lexue.bit.edu.cn/*
// @icon https://lexue.bit.edu.cn/theme/image.php/eguru/theme/1724573654/favicon
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// ==/UserScript==

(async function () {
'use strict'
/* global GM_getValue */
/* global GM_setValue */
/* global GM_registerMenuCommand */
// GreasyFork提供:
/* global GM_getValue, GM_setValue, GM_registerMenuCommand */
// 乐学提供:
/* global M */

let dragsrc = null
let shown_courses = await GM_getValue('lexue_shown_courses')
let hidden_courses = await GM_getValue('lexue_hidden_courses')
let shown_courses = await GM_getValue('lexue_shown_courses') || []
let hidden_courses = await GM_getValue('lexue_hidden_courses') || []
const popup_cover = document.createElement('div')
const popup = document.createElement('div')
popup_cover.style = 'width:100%;height:100%;background-color:rgba(0,0,0,0.6);position:fixed;inset:0px;z-index:2000'

function rewrite_sidebar (shown_courses) {
const current_id = (document.querySelector('[data-key="coursehome"].active_tree_node')?.href?.match(/(?<=id=)\w+/) || [])[0]
const current_id = document.querySelector('[data-key="coursehome"].active_tree_node')?.href?.match(/(?<=id=)\w+/)?.join() // 如果找不到返回undefined
const mycourses = document.querySelector('li:has([data-key="mycourses"])')
const sidebar_course_list = mycourses.parentNode

Expand All @@ -43,7 +45,7 @@
<div class="ml-1">
<div class="media">
<span class="media-left">
<i class="icon fa fa-graduation-cap fa-fw " aria-hidden="true"></i>
<i class="icon fa fa-${shown_courses[i][2]} fa-fw " aria-hidden="true"></i>
</span>
<span class="media-body ${classList[1]}">${shown_courses[i][1]}</span>
</div>
Expand All @@ -65,7 +67,6 @@
color:rgb(255,255,255);
font-weight:700;
font-size:20px;
cursor:move;
-webkit-touch-callout:none;
-webkit-user-select:none;
-khtml-user-select:none;
Expand Down Expand Up @@ -108,14 +109,17 @@ ul#shown_courses,ul#hidden_courses{
ul#shown_courses::-webkit-scrollbar,ul#hidden_courses::-webkit-scrollbar{
width: 0px;/* 兼容火狐 */
}
ul#shown_courses>li,ul#hidden_courses>li,div.table-title{
cursor:grab;
ul#shown_courses>li,ul#hidden_courses>li{
cursor: grab;
font-size: 16px;
font-weight: bold;
border: 1px solid #000;
width: 100%;
text-align: center;
}
ul#shown_courses span,ul#hidden_courses span{
min-height:24px;
}
span[contenteditable='true']{
border:thin solid #C0C0C0;
}
Expand All @@ -128,8 +132,8 @@ span[contenteditable='true']{
<div style="width:45%;font-size:16px;">隐藏的课程</div>
</div>
<div style="display:flex;justify-content:center;">
<ul id="shown_courses"></ul>
<ul id="hidden_courses"></ul>
<ul id="shown_courses" ondragover="event.preventDefault();"></ul>
<ul id="hidden_courses" ondragover="event.preventDefault();"></ul>
</div>
<button id="rewrite_sidebar" style="margin:1% 1% 1% 1%;">完成</button></div>`
popup.querySelector('#close_popup').onclick = () => closePopup()
Expand All @@ -140,25 +144,19 @@ span[contenteditable='true']{
const shown_lis = popup.querySelectorAll('#shown_courses>li')
const hidden_lis = popup.querySelectorAll('#hidden_courses>li')
for (let i = 0; i < shown_lis.length; i++) {
shown_courses.push([shown_lis[i].dataset.id, shown_lis[i].innerText])
shown_courses.push([shown_lis[i].dataset.id, shown_lis[i].innerText.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll(' ', '&nbsp;'), shown_lis[i].querySelector('[data-icon]').dataset.icon])
}
for (let j = 0; j < hidden_lis.length; j++) {
hidden_courses.push([hidden_lis[j].dataset.id, hidden_lis[j].innerText])
hidden_courses.push([hidden_lis[j].dataset.id, hidden_lis[j].innerText.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll(' ', '&nbsp;'), hidden_lis[j].querySelector('[data-icon]').dataset.icon])
}
GM_setValue('lexue_shown_courses', shown_courses)
GM_setValue('lexue_hidden_courses', hidden_courses)
rewrite_sidebar(shown_courses)
}
popup.querySelector('#shown_courses').addEventListener('dragover', function (e) {
e.preventDefault()
})
popup.querySelector('#shown_courses').addEventListener('drop', function (e) {
e.preventDefault()
this.append(dragsrc)
})
popup.querySelector('#hidden_courses').addEventListener('dragover', function (e) {
e.preventDefault()
})
popup.querySelector('#hidden_courses').addEventListener('drop', function (e) {
e.preventDefault()
this.append(dragsrc)
Expand All @@ -183,16 +181,7 @@ span[contenteditable='true']{
}
}
})
shown_li.innerHTML =
`<a class="list-group-item list-group-item-action">
<div class="ml-1">
<div class="media">
<span class="media-body" ondblclick="this.setAttribute('contenteditable','true');this.focus()" onblur="this.removeAttribute('contenteditable')" onkeydown="if(event.keyCode===13){this.blur()}" onpaste="event.preventDefault();document.execCommand('insertText',false,event.clipboardData.getData('text/plain').replace(/[\\n|\\r]/gm,''))">
${shown_courses[i][1]}
</span>
</div>
</div>
</a>`
shown_li.innerHTML = `<a class="list-group-item list-group-item-action"><div class="ml-1"><div class="media"><span class="media-left"><i class="icon fa fa-${shown_courses[i][2]} fa-fw" aria-hidden="true" ondblclick="this.style.display='none';this.nextSibling.style.display='block';this.nextSibling.focus();this.parentNode.parentNode.parentNode.parentNode.parentNode.draggable=false"></i><span class="media-body" style="cursor:auto;display:none" contenteditable="true" onfocus="this.innerText=this.dataset.icon" data-icon="${shown_courses[i][2]}" onblur="this.style.display='none';this.previousSibling.style.display='block';this.parentNode.parentNode.parentNode.parentNode.parentNode.draggable=true;this.dataset.icon=this.innerText;this.innerText='';this.previousSibling.className='icon fa fa-'+this.dataset.icon+' fa-fw';" onkeydown="if(event.keyCode===13){this.blur();}" onpaste="event.preventDefault();document.execCommand('insertText',false,event.clipboardData.getData('text/plain').replace(/[\\n|\\r]/gm,''))"></span></span><span class="media-body" ondblclick="this.setAttribute('contenteditable','true');this.focus();this.style.cursor='auto';this.parentNode.parentNode.parentNode.parentNode.draggable=false" onblur="this.removeAttribute('contenteditable');this.style.cursor='grab';this.parentNode.parentNode.parentNode.parentNode.draggable=true" onkeydown="if(event.keyCode===13){this.blur();}" onpaste="event.preventDefault();document.execCommand('insertText',false,event.clipboardData.getData('text/plain').replace(/[\\n|\\r]/gm,'')).replaceAll(' ','&nbsp;')">${shown_courses[i][1]}</span></div></div></a>`
popup.querySelector('#shown_courses').append(shown_li)
}
for (let j = 0; j < hidden_courses.length; j++) {
Expand All @@ -215,16 +204,7 @@ span[contenteditable='true']{
}
}
})
hidden_li.innerHTML =
`<a class="list-group-item list-group-item-action">
<div class="ml-1">
<div class="media">
<span class="media-body" ondblclick="this.setAttribute('contenteditable','true');this.focus()" onblur="this.removeAttribute('contenteditable')" onkeydown="if(event.keyCode===13){this.blur()}" onpaste="event.preventDefault();document.execCommand('insertText',false,event.clipboardData.getData('text/plain').replace(/[\\n|\\r]/gm,''))">
${hidden_courses[j][1]}
</span>
</div>
</div>
</a>`
hidden_li.innerHTML = `<a class="list-group-item list-group-item-action"><div class="ml-1"><div class="media"><span class="media-left"><i class="icon fa fa-${hidden_courses[j][2]} fa-fw" aria-hidden="true" ondblclick="this.style.display='none';this.nextSibling.style.display='block';this.nextSibling.focus();this.parentNode.parentNode.parentNode.parentNode.parentNode.draggable=false"></i><span class="media-body" style="cursor:auto;display:none" contenteditable="true" onfocus="this.innerText=this.dataset.icon" data-icon="${hidden_courses[j][2]}" onblur="this.style.display='none';this.previousSibling.style.display='block';this.parentNode.parentNode.parentNode.parentNode.parentNode.draggable=true;this.dataset.icon=this.innerText;this.innerText='';this.previousSibling.className='icon fa fa-'+this.dataset.icon+' fa-fw'" onkeydown="if(event.keyCode===13){this.blur();}" onpaste="event.preventDefault();document.execCommand('insertText',false,event.clipboardData.getData('text/plain').replace(/[\\n|\\r]/gm,''))"></span></span><span class="media-body" ondblclick="this.setAttribute('contenteditable','true');this.focus();this.style.cursor='auto';this.parentNode.parentNode.parentNode.parentNode.draggable=false" onblur="this.removeAttribute('contenteditable');this.style.cursor='grab';this.parentNode.parentNode.parentNode.parentNode.draggable=true" onkeydown="if(event.keyCode===13){this.blur();}" onpaste="event.preventDefault();document.execCommand('insertText',false,event.clipboardData.getData('text/plain').replace(/[\\n|\\r]/gm,'')).replaceAll(' ','&nbsp;')">${hidden_courses[j][1]}</span></div></div></a>`
popup.querySelector('#hidden_courses').append(hidden_li)
}
document.body.append(popup_cover)
Expand All @@ -240,20 +220,21 @@ span[contenteditable='true']{
const xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
shown_courses = []
hidden_courses = []
const a = new DOMParser().parseFromString(xhr.responseText, 'text/html').querySelectorAll("a[href*='lexue.bit.edu.cn/user/view.php']")
for (let i = 0; i < a.length; i++) {
shown_courses.push([a[i].href.match(/(?<=course=)\w+/)[0], a[i].innerText])
const courses = JSON.parse(xhr.responseText)[0].data.courses
courses.sort((a, b) => a.enddate - b.enddate)
for (let i = 0; i < courses.length; i++) {
if (!hidden_courses.filter(hidden_course => parseInt(hidden_course[0]) === courses[i].id).length && !shown_courses.filter(shown_course => parseInt(shown_course[0]) === courses[i].id).length) {
hidden_courses.unshift([courses[i].id, `<b style="color:red">${courses[i].fullname}</b>`, 'graduation-cap'])
}
}
openPopup()
}
}
xhr.open('GET', document.querySelector("[href*='lexue.bit.edu.cn/user/profile.php?id=']").href + '&showallcourses=1', true)
xhr.send()
xhr.open('POST', `https://lexue.bit.edu.cn/lib/ajax/service.php?sesskey=${M.cfg.sesskey}&info=core_course_get_enrolled_courses_by_timeline_classification`, true)
xhr.send('[{"index":0,"methodname":"core_course_get_enrolled_courses_by_timeline_classification","args":{"offset":0,"limit":0,"classification":"all","sort":"fullname","customfieldname":"","customfieldvalue":""}}]')
}

if (shown_courses || hidden_courses) {
if (shown_courses.length || hidden_courses.length) {
rewrite_sidebar(shown_courses)
} else {
reload_courses()
Expand Down
5 changes: 3 additions & 2 deletions TamperMonkey/BIT-乐学-修改侧边栏课程.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@

这段脚本与“[BIT-乐学-修改侧边栏课程-GUI](https://greasyfork.org/zh-CN/scripts/488788)”矛盾,同时启用时效果不确定。

- 此脚本能修改图标,GUI版目前还不能;
- GUI版的操作方式远比此脚本直观,直接拖动即可;
- GUI版的操作方式远比此脚本直观,直接拖动即可;而且能拉取全部课程列表,方便每学期更新。
- 此脚本是原初版本,功能已经全面落后,除了代码简洁外基本没有优势。
- 网上新增课程后,目前两脚本设计了不同的默认行为。此脚本不作为,无论网上原本显示与否,都保持原样;而GUI版会将新课插入“隐藏的课程”列表开头,并用红色粗体标识;

欢迎有志之士前往 [YDX-2147483647/BIT-enhanced](https://github.com/YDX-2147483647/BIT-enhanced) 帮忙合并两段脚本。

0 comments on commit 0140cec

Please sign in to comment.