您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
一键导出课表/考试安排为ics文件
// ==UserScript== // @name 课表助手 - xtu // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 一键导出课表/考试安排为ics文件 // @author DeltaX // @match http://jwxt.xtu.edu.cn/jsxsd/* // @require https://cdn.bootcdn.net/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js // @grant none // @License MIT // ==/UserScript== (function () { 'use strict'; let SEPARATOR = navigator.appVersion.indexOf('Win') !== -1 ? '\r\n' : '\n'; // 设置上课时间及下课时间 let class_start_summer = [ [], [8, 0], [9, 40], [10, 10], [11, 50], [14, 30], [16, 10], [16, 40], [18, 10], [19, 30], [22, 5] ]; let class_start_winter = [ [], [8, 0], [9, 40], [10, 10], [11, 50], [14, 0], [15, 40], [16, 10], [17, 40], [19, 0], [21, 35] ]; let class_time = 100; // let weekToNum = { "日": 0, "一": 1, "二": 2, "三": 3, "四": 4, "五": 5, "六": 6 } let weekRegexp = /(?:(\d{1,2}-\d{1,2})|(\d{1,2})\(单周\))/g; let nowDate = new Date(); let weekStartQuery = term => new Promise(function (resolve, reject) { let xhr = new XMLHttpRequest(); xhr.open('POST', 'http://jwxt.xtu.edu.cn/jsxsd/jxzl/jxzl_query'); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.withCredentials = true; xhr.onload = function () { if (xhr.status === 200) { resolve( /<tr height='28'><td>1<\/td><td title='(.*?)'>/.exec( this.response )[1] ); } else { reject(this); } }; xhr.send('xnxq01id=' + term); }); let toString = function (date) { return ( date .toISOString() .split(/-|:|[.]/) .slice(0, 4) .join('') + '00Z' ); }; // 生成课表日历文件 function GenerateCourseICS() { // 获取main-->page_iframe-->iframe0 let iframe0 = document.getElementById('Form1'); // 添加按钮"保存ics" let buttonPre = iframe0.querySelector('select#xnxq01id'); buttonPre.outerHTML += ' <input type="button" onclick="saveics()" class="button" name="submit" value="保存ics">'; if (typeof iframe0.saveics === 'function') return; // 添加按钮操作,核心部分 iframe0.saveics = function () { window.console.log('开始生成...'); if ( navigator.userAgent.indexOf('MISE') > -1 && navigator.userAgent.indexOf('MSIE 10') == -1 ) { alert('浏览器不支持哦~😆'); return; } let calendar_start = [ 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:Curriculum-to-iCalendar' ].join(SEPARATOR); let calendar_end = SEPARATOR + 'END:VCALENDAR' + SEPARATOR; let calendarEvents = []; // 获取到课程表 try { let table = document.querySelector('#kbtable').tBodies[0]; let yearTerm = document .querySelector('#xnxq01id') [document.querySelector('#xnxq01id').selectedIndex].innerText.split( '-' ); let year = yearTerm[0] + '-' + yearTerm[1]; let term = yearTerm[2]; // 请求起始周 console.log('查询学期起始日期中,学期: ' + yearTerm.join('-')); weekStartQuery(yearTerm.join('-')).then(weekStart => { let termStartDate = new Date(weekStart.split(/年|月|日/)); // let currentWeek = parseInt((nowDate - startDate) / 1000 * 60 * 60 * 24 * 7); // 逐行添加event至cal console.log('添加课程事件中...'); for (let i = 1; i < table.rows.length - 1; i++) { // 逐课程添加 // let timeAddress = table.rows[i].cells[0].innerText; // let events = timeAddress.split(' ').filter(n => n != " "); for (let j = 1; j < table.rows[i].cells.length; j++) { // 同一时间不同课程 let lessonInfos = table.rows[i].cells[j].innerText.split( '---------------------\n' ); for (let lesInfStr of lessonInfos) { let lessonInfo = lesInfStr.split('\n').filter(n => n !== ''); // console.log(lessonInfo); // 空课程跳过 if (lessonInfo.length < 4) { continue; } let courseName = lessonInfo[0]; let teacherName = lessonInfo[1]; // TODO 多周问题 let weeksStr = lessonInfo[2]; let location = lessonInfo[3]; let description = courseName + ' ' + teacherName + ' '; let weekDay = j; // let interval = parseInt(informations[2]); // TODO 判断夏令时冬令时 let isSummerTime = false; let startTime = []; let endTime = []; if (isSummerTime) { startTime = class_start_summer[2 * i - 1]; endTime = class_start_summer[2 * i]; } else { startTime = class_start_winter[2 * i - 1]; endTime = class_start_winter[2 * i]; } // 按照多周划分后迭代 for ( let weekStrs = weekRegexp.exec(weeksStr); weekStrs !== null; weekStrs = weekRegexp.exec(weeksStr) ) { // 分多周 "2-5,7-9,11-13(周)" 和单周 "13(单周)" let week = []; if (weekStrs[1] !== undefined) { week = weekStrs[1].split('-'); // 多周 } else { week = [weekStrs[2], weekStrs[2]]; // 单周 } let startWeek = parseInt(week[0]); let endWeek = parseInt(week[1]); let startDate = new Date(termStartDate), endDate = new Date(termStartDate), untilDate = new Date(termStartDate); // 课程时间 startDate.setDate( startDate.getDate() + (startWeek - 1) * 7 + weekDay - 1 ); startDate.setHours(startTime[0], startTime[1], 0, 0); endDate.setDate( endDate.getDate() + (startWeek - 1) * 7 + weekDay - 1 ); endDate.setHours(endTime[0], endTime[1]); // 课程截止 untilDate.setDate( untilDate.getDate() + (endWeek - 1) * 7 + weekDay ); untilDate.setHours(endTime[0], endTime[1]); calendarEvents.push( [ 'BEGIN:VEVENT', 'DTSTAMP:' + toString(nowDate), 'UID:' + 'COURSE' + calendarEvents.length + '@' + 'https://1000delta.top', 'SUMMARY:' + courseName, 'DTSTART:' + toString(startDate), 'DTEND:' + toString(endDate), 'RRULE:FREQ=WEEKLY;UNTIL=' + toString(untilDate), 'LOCATION:' + location, 'DESCRIPTION:' + description, 'END:VEVENT' ].join(SEPARATOR) ); } } } } // console.log(calendarEvents); if (calendarEvents.length < 1) { alert('课表里没课哦~😆'); return; } let filename = year + '学年第' + term + '学期课表.ics'; let calendar = calendar_start + SEPARATOR + calendarEvents.join(SEPARATOR) + calendar_end; //保存到文件 let blob; if (navigator.userAgent.indexOf('MSIE 10') === -1) { // chrome or firefox blob = new Blob([calendar]); } else { // ie let bb = new BlobBuilder(); bb.append(calendar); blob = bb.getBlob( 'text/x-vCalendar;charset=' + document.characterSet ); } saveAs(blob, filename); }); } catch (error) { console.log(error); alert('出错啦!/(ㄒoㄒ)/~~'); } }; } const EXAM_ORDER = 0, EXAM_SESSION = 1, EXAM_NAME = 2, EXAM_TYPE = 3, EXAM_MODE = 4, EXAM_TIME = 5, EXAM_LOCATION = 6, EXAM_SEAT = 7, EXAM_ID = 8, EXAM_NOTE = 9; function GenerateExamICS() { window.console.log('考试安排生成准备'); let buttonPre = document.querySelector('input#btn_back'); buttonPre.outerHTML += ' <input type="button" onclick="saveics()" class="button" name="saveics" value="保存ics">'; let term = /学年学期【(.*)】/.exec(buttonPre.parentElement ? buttonPre.parentElement.innerText : ""); window.saveics = function () { // 格式编辑 let calendar_start = [ 'BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:Exam-to-iCalendar' ].join(SEPARATOR); let calendar_end = SEPARATOR + 'END:VCALENDAR' + SEPARATOR; let calendarEvents = []; // 数据获取 let examTitle; let rows = document.querySelector('table#dataList').rows; for (let exam of rows) { if (exam.cells[EXAM_ORDER].innerText === '序号') { examTitle = exam; continue; } let timeTexts = exam.cells[EXAM_TIME].innerText.split(/ |~/); let startDate = new Date(timeTexts[0] + ' ' + timeTexts[1]); let endDate = new Date(timeTexts[0] + ' ' + timeTexts[2]); let description = ` ${examTitle.cells[EXAM_SESSION].innerText}: ${exam.cells[EXAM_SESSION].innerText} ${examTitle.cells[EXAM_NAME].innerText}: ${exam.cells[EXAM_NAME].innerText} ${examTitle.cells[EXAM_TYPE].innerText}: ${exam.cells[EXAM_TYPE].innerText} ${examTitle.cells[EXAM_MODE].innerText}: ${exam.cells[EXAM_MODE].innerText} ${examTitle.cells[EXAM_SEAT].innerText}: ${exam.cells[EXAM_SEAT].innerText} ${examTitle.cells[EXAM_ID].innerText}: ${exam.cells[EXAM_ID].innerText} ${examTitle.cells[EXAM_NOTE].innerText}: ${exam.cells[EXAM_NOTE].innerText} `; calendarEvents.push( [ 'BEGIN:VEVENT', 'DTSTAMP:' + toString(nowDate), 'UID:' + 'EXAM-' + term + calendarEvents.length + '@' + 'https://1000delta.top', 'SUMMARY:' + exam.cells[EXAM_NAME].innerText, 'DTSTART:' + toString(startDate), 'DTEND:' + toString(endDate), 'LOCATION:' + exam.cells[EXAM_LOCATION].innerText, 'DESCRIPTION:' + description, 'END:VEVENT' ].join(SEPARATOR) ); } if (calendarEvents.length < 1) { window.alert('当前没有考试安排哦~'); return; } let filename = term ? term[1] : "" + '考试安排.ics'; let calendar = calendar_start + SEPARATOR + calendarEvents.join(SEPARATOR) + calendar_end; //保存到文件 let blob; if (navigator.userAgent.indexOf('MSIE 10') === -1) { // chrome or firefox blob = new Blob([calendar]); } else { // ie let bb = new BlobBuilder(); bb.append(calendar); blob = bb.getBlob('text/x-vCalendar;charset=' + document.characterSet); } saveAs(blob, filename); } } let queryTable = { 'http://jwxt.xtu.edu.cn/jsxsd/xskb/xskb_list.do': GenerateCourseICS, 'http://jwxt.xtu.edu.cn/jsxsd/xsks/xsksap_list': GenerateExamICS }; // 窗口加载完成调用函数 window.onload = function () { try { queryTable[document.URL](); } catch (error) { if (error.message !== window.error_message) { window.error_message = error.message; console.log(error); } return; } }; // 保证页面刷新后重新执行 // setInterval(onload, 50); })();