// ==UserScript== // @icon http://www.tsinghua.edu.cn/publish/newthu/images/favicon.ico // @name 网络学堂2018助手 // @namespace exhen32@live.com // @version 2019年3月1日02版 // @description 微调排版,提醒更醒目; 支持导出日历,课程一目了然;更多功能开发中! // @require http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js // @require https://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.min.js // @author Exhen // @match http*://learn2018.tsinghua.edu.cn/f/wlxt/index/course/student/ // @grant GM_xmlhttpRequest // @grant GM_setClipboard // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @connect learn2018.tsinghua.edu.cn // @run-at document-idle // @downloadURL none // ==/UserScript== var saveAs = saveAs || (function (view) { "use strict"; // IE <10 is explicitly unsupported if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { return; } var doc = view.document // only get URL when necessary in case Blob.js hasn't overridden it yet , get_URL = function () { return view.URL || view.webkitURL || view; }, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"), can_use_save_link = "download" in save_link, click = function (node) { var event = new MouseEvent("click"); node.dispatchEvent(event); }, is_safari = /constructor/i.test(view.HTMLElement) || view.safari, is_chrome_ios = /CriOS\/[\d]+/.test(navigator.userAgent), throw_outside = function (ex) { (view.setImmediate || view.setTimeout)(function () { throw ex; }, 0); }, force_saveable_type = "application/octet-stream" // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to , arbitrary_revoke_timeout = 1000 * 40 // in ms , revoke = function (file) { var revoker = function () { if (typeof file === "string") { // file is an object URL get_URL().revokeObjectURL(file); } else { // file is a File file.remove(); } }; setTimeout(revoker, arbitrary_revoke_timeout); }, dispatch = function (filesaver, event_types, event) { event_types = [].concat(event_types); var i = event_types.length; while (i--) { var listener = filesaver["on" + event_types[i]]; if (typeof listener === "function") { try { listener.call(filesaver, event || filesaver); } catch (ex) { throw_outside(ex); } } } }, auto_bom = function (blob) { // prepend BOM for UTF-8 XML and text/* types (including HTML) // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type }); } return blob; }, FileSaver = function (blob, name, no_auto_bom) { if (!no_auto_bom) { blob = auto_bom(blob); } // First try a.download, then web filesystem, then object URLs var filesaver = this, type = blob.type, force = type === force_saveable_type, object_url, dispatch_all = function () { dispatch(filesaver, "writestart progress write writeend".split(" ")); } // on any filesys errors revert to saving with object URLs , fs_error = function () { if ((is_chrome_ios || (force && is_safari)) && view.FileReader) { // Safari doesn't allow downloading of blob urls var reader = new FileReader(); reader.onloadend = function () { var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;'); var popup = view.open(url, '_blank'); if (!popup) view.location.href = url; url = undefined; // release reference before dispatching filesaver.readyState = filesaver.DONE; dispatch_all(); }; reader.readAsDataURL(blob); filesaver.readyState = filesaver.INIT; return; } // don't create more object URLs than needed if (!object_url) { object_url = get_URL().createObjectURL(blob); } if (force) { view.location.href = object_url; } else { var opened = view.open(object_url, "_blank"); if (!opened) { // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html view.location.href = object_url; } } filesaver.readyState = filesaver.DONE; dispatch_all(); revoke(object_url); }; filesaver.readyState = filesaver.INIT; if (can_use_save_link) { object_url = get_URL().createObjectURL(blob); setTimeout(function () { save_link.href = object_url; save_link.download = name; click(save_link); dispatch_all(); revoke(object_url); filesaver.readyState = filesaver.DONE; }); return; } fs_error(); }, FS_proto = FileSaver.prototype, saveAs = function (blob, name, no_auto_bom) { return new FileSaver(blob, name || blob.name || "download", no_auto_bom); }; // IE 10+ (native saveAs) if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { return function (blob, name, no_auto_bom) { name = name || blob.name || "download"; if (!no_auto_bom) { blob = auto_bom(blob); } return navigator.msSaveOrOpenBlob(blob, name); }; } FS_proto.abort = function () {}; FS_proto.readyState = FS_proto.INIT = 0; FS_proto.WRITING = 1; FS_proto.DONE = 2; FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null; return saveAs; }( typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content )); // `self` is undefined in Firefox for Android content script context // while `this` is nsIContentFrameMessageManager // with an attribute `content` that corresponds to the window if (typeof module !== "undefined" && module.exports) { module.exports.saveAs = saveAs; } else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) { define("FileSaver.js", function () { return saveAs; }); } var getJSON = function (url, callback) { GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Accept': 'application/json' }, onload: function (response) { if (response.status >= 200 && response.status < 400) { callback(JSON.parse(response.responseText), url); } else { callback(false, url); } } }); }; function waitForKeyElements( selectorTxt, /* Required: The jQuery selector string that specifies the desired element(s). */ actionFunction, /* Required: The code to run when elements are found. It is passed a jNode to the matched element. */ bWaitOnce, /* Optional: If false, will continue to scan for new elements even after the first match is found. */ iframeSelector /* Optional: If set, identifies the iframe to search. */ ) { var targetNodes, btargetsFound; if (typeof iframeSelector == "undefined") targetNodes = jQuery(selectorTxt); else targetNodes = jQuery(iframeSelector).contents() .find(selectorTxt); if (targetNodes && targetNodes.length > 0) { btargetsFound = true; /*--- Found target node(s). Go through each and act if they are new. */ targetNodes.each(function () { var jThis = jQuery(this); var alreadyFound = jThis.data('alreadyFound') || false; if (!alreadyFound) { //--- Call the payload function. var cancelFound = actionFunction(jThis); if (cancelFound) btargetsFound = false; else jThis.data('alreadyFound', true); } }); } else { btargetsFound = false; } //--- Get the timer-control variable for this selector. var controlObj = waitForKeyElements.controlObj || {}; var controlKey = selectorTxt.replace(/[^\w]/g, "_"); var timeControl = controlObj[controlKey]; //--- Now set or clear the timer as appropriate. if (btargetsFound && bWaitOnce && timeControl) { //--- The only condition where we need to clear the timer. clearInterval(timeControl); delete controlObj[controlKey] } else { //--- Set a timer, if needed. if (!timeControl) { timeControl = setInterval(function () { waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector ); }, 300 ); controlObj[controlKey] = timeControl; } } waitForKeyElements.controlObj = controlObj; } function PrefixInteger(num, length) { return (Array(length).join(0) + num).slice(-length); } function init() { if (!document.getElementById("dUietC") && $('ul.stu').length) { var dUietC = document.createElement("a"); dUietC.id = "dUietC"; document.getElementsByTagName("html")[0].appendChild(dUietC); console.log('网络学堂2018助手 is running!') // 新通知数量重新排版 $('.unsee').remove(); $('li.clearfix').each(function () { $(this).css('height', '90px') $(this).css('padding', '8px 8px') if (parseInt($(this).find('span.stud').text()) > 0) { $(this).find('span.stud').css('font-size', '50px'); $(this).find('span.stud').css('display', 'block'); $(this).find('span.stud').css('padding-left', 'none'); $(this).find('span.stud').css('text-align', 'center'); //$(this).find('span.name').text($(this).find('span.liulan').text()); $(this).find('span.liulan').remove(); } else { $(this).find('span.stud').remove(); } }) $('ul.stu').each(function () { $(this).find('li').first().css('padding', '0px'); }) // 图片提醒 $('dd.stu').each(function () { if (parseInt($(this).find('span.green').text()) > 0) { //var wlkcid = $(this).find('.hdtitle a').attr('href').match(/(?<=wlkcid=).*/); var wlkcid = $(this).find('.hdtitle a').attr('href').slice(43); $(this).attr('id', wlkcid) getJSON(`http://learn2018.tsinghua.edu.cn/b/wlxt/kczy/zy/student/index/zyListWj?wlkcid=${wlkcid}&size=99`, function (doc, url) { if (doc) { var ddl = 0; for (var i = 0; i < doc.object.iTotalRecords; i++) { if (ddl <= 0 || ddl > doc.object.aaData[i].jzsj) { ddl = doc.object.aaData[i].jzsj } } console.log(ddl) var now = new Date(); var time = ddl - now.getTime(); console.log(time) var days = Math.ceil(time / 86400000); if (time <= 0) { $(`#${wlkcid}`).find('li.clearfix').first().css('background', 'url(https://raw.githubusercontent.com/Exhen/learn2018helper/master/liangle.jpg)'); $(`#${wlkcid}`).find('li.clearfix').first().append(`已经截至`) } else if (time <= 86400000) { //多于7天 $(`#${wlkcid}`).find('li.clearfix').first().css('background', 'url(https://raw.githubusercontent.com/Exhen/learn2018helper/master/ddl.jpg)'); $(`#${wlkcid}`).find('li.clearfix').first().append(`最后一天`) } else { $(`#${wlkcid}`).find('li.clearfix').first().css('background', 'url(https://raw.githubusercontent.com/Exhen/learn2018helper/master/ddl.jpg)'); $(`#${wlkcid}`).find('li.clearfix').first().append(`还剩${days}`) } $(`#${wlkcid}`).find('p.p_img').remove(); } }) } else { $(this).find('li.clearfix').first().css('background', 'url(https://raw.githubusercontent.com/Exhen/learn2018helper/master/good.jpg)'); $(this).find('li.clearfix').first().append(`没有作业`) $(this).find('p.p_img').remove(); } }) $('head').append('