Skip to content

Instantly share code, notes, and snippets.

@erjiaqing
Last active April 2, 2019 07:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erjiaqing/f1049583108196310f9b4dcec58d95f7 to your computer and use it in GitHub Desktop.
Save erjiaqing/f1049583108196310f9b4dcec58d95f7 to your computer and use it in GitHub Desktop.
丢掉乱七八糟的课程表吧!No Time Table,将课表导出为日历文件!(Tampermonkey脚本)
// ==UserScript==
// @name No Time Table
// @namespace http://app.ejq.me/
// @version 0.0.4.1
// @description Export time table as ICS file.
// @author EJQ
// @include http://210.42.121.132/servlet/Svlt_QueryStuLsn*
// @include http://210.42.121.133/servlet/Svlt_QueryStuLsn*
// @include http://210.42.121.134/servlet/Svlt_QueryStuLsn*
// @include http://210.42.121.241/servlet/Svlt_QueryStuLsn*
// @grant none
// @require http://code.jquery.com/jquery-1.12.4.min.js
// @updateURL https://gist.githubusercontent.com/erjiaqing/f1049583108196310f9b4dcec58d95f7/raw/nott.js
// ==/UserScript==
/**
* Copyright (C) 2017 Guo Song (Aka. erjiaqing)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*/
Update log:
0.0.4 -> 0.0.4.1:
[HotFix] 格式修复
0.0.3 -> 0.0.4:
[Fix] 将上课地点存在Location域中
0.0.2 -> 0.0.3:
[Fix] 修复部分已安排时间的课程无法显示的问题
0.0.1 -> 0.0.2:
[Fix] 在没填写教学周的时候拒绝导出,同时导出自带update属性
/*/
function calcClassTime(str)
{
var ret = [];
var weekDay = '日一二三四五六';
var regexp1 = /周(.):(\d+)-(\d+)周,每(\d+)周;\s+(\d+)-(\d+)节(,(\d+)区,([^\s]+)){0,1}/g;
var regexp2 = /周(.):(\d+)-(\d+)周,每(\d+)周;\s+(\d+)-(\d+)节(,(\d+)区,([^\s]+)){0,1}/;
function p(hour, minute)
{
return (hour * 3600 + minute * 60) * 1000;
}
var classStart = [p(8, 0),p(8, 50),p(9, 50),p(10, 40),
p(11, 30),p(14, 5),p(14, 55),p(15, 45),
p(16, 40),p(17, 30),p(18, 30),p(19, 20),p(20, 10)];
var classEnd = [p(8, 45),p(9, 35),p(10, 35),p(11, 25),
p(12, 15),p(14, 50),p(15, 40),p(16, 30),
p(17, 25),p(18, 15),p(19, 15),p(20, 05),p(20, 55)];
var m = str.match(regexp1);
if (m)
m.forEach(function (e){
console.log(e);
var res = e.match(regexp2);
console.log(res);
ret.push({
weekday: weekDay.search(res[1]),
start_week: Number(res[2]),
end_week: Number(res[3]),
interval: Number(res[4]),
class_begin: classStart[Number(res[5]) - 1],
class_end: classEnd[Number(res[6]) - 1],
area: res[8] ? Number(res[8]) : "",
classroom: res[9] ? res[9] : ""
});
});
return ret;
}
function processRow(r)
{
console.log(r);
var ret = calcClassTime(r.children[9].children[0].innerText);
if (ret.length === 0) return undefined;
return {
name: r.children[1].innerText,
id: r.children[0].innerText,
note: r.children[10].innerText + "/" + r.children[5].innerText + "/" + r.children[2].innerText,
time: ret};
}
function processTable()
{
var r = $("tr");
var ret = [];
for (var $i = 1; $i < r.length; $i++)
{
var tmp = processRow(r[$i]);
if (tmp)
ret.push(tmp);
}
return ret;
}
function toTimeStamp(date)
{
return date.toISOString().replace(/[\-:]/g, '').replace(/\.\d{3}/, '');
}
function saveICS(str)
{
function saveAs(blob, filename) {
var type = blob.type;
var force_saveable_type = 'application/octet-stream';
if (type && type != force_saveable_type) { // 强制下载,而非在浏览器中打开
var slice = blob.slice || blob.webkitSlice || blob.mozSlice;
blob = slice.call(blob, 0, blob.size, force_saveable_type);
}
var url = URL.createObjectURL(blob);
var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
save_link.href = url;
save_link.download = filename;
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
save_link.dispatchEvent(event);
URL.revokeObjectURL(url);
}
// console.log(str);
var bb = new Blob([str], {type: "text/plain;charset=utf-8"});
saveAs(bb, 'TimeTable.ics');
}
function processFull(currentWeek)
{
var ret = "";
var header = "BEGIN:VCALENDAR\r\n"+
"VERSION:2.0\r\n"+
"PRODID:-//hacksw/handcal//NONSGML v1.0//EN\r\n";
var uuid_suffix = "whu_noTT@ejq.me";
var res = processTable();
var startWeek = new Date();
//
var thisDay = startWeek.getDay();
if (currentWeek > 0) currentWeek -= 1;
var shift = currentWeek * 7 * 24 * 3600 + thisDay * 24 * 3600 + startWeek.getHours() * 3600 + startWeek.getMinutes() * 60 + startWeek.getSeconds();
shift *= 1000;
startWeek = new Date(startWeek.valueOf() - shift);
res.forEach(function (e) {
e.time.forEach(function (ti) {
for (var $i = ti.start_week - 1; $i < ti.end_week; $i += ti.interval) {
var ts = new Date(startWeek.valueOf() + ($i * 7 * 24 * 3600 + ti.weekday * 24 * 3600) * 1000 + ti.class_begin);
var te = new Date(ts.valueOf() + ti.class_end - ti.class_begin);
// console.log(ts);
// console.log(te);
ret += "BEGIN:VEVENT\r\n" +
"METHOD:UPDATE\r\n"+
"UID:" + e.id + "_wk" + ($i + 1) + "_" + ti.weekday + "_" + ti.class_begin + "_" + ti.class_end + "@nott.ejq.me\r\n" +
"DTSTAMP:" + toTimeStamp(ts) + "\r\n" +
"DTSTART:" + toTimeStamp(ts) + "\r\n" +
"DTEND:" + toTimeStamp(te) + "\r\n" +
"SUMMARY:" + e.name + "\r\n" +
"LOCATION:" + ti.area + "区" + ti.classroom + "\r\n" +
"DESCRIPTION:" + e.note + "\r\n" +
"END:VEVENT\r\n";
}
});
});
saveICS(header + ret + "END:VCALENDAR\r\n");
return header + ret + "END:VCALENDAR\r\n";
}
function finallyProcess()
{
processFull(Number($("#__school_week").val()));
}
function init()
{
$("#search").append('<input type="text" id="__school_week" placeholder="教学周">');
$("#search").append('<input type="button" id="exportICS" class="searchBtb" name="export" value="导出ics">');
$("#exportICS").on("click", finallyProcess);
}
init();
@Bob-cheng
Copy link

function finallyProcess()
{
var tmp = Number($("#__school_week").val());
if(tmp > 0){
processFull(tmp);
}else{
alert("请输入正确的当前的教学周");
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment