JUST Kit

用于江苏科技大学网站的补丁与工具。

当前为 2022-02-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name JUST Kit
  3. // @description Patches & tools for JUST Website.
  4. // @description:zh-CN 用于江苏科技大学网站的补丁与工具。
  5. // @namespace https://greasyfork.org/users/197529
  6. // @version 0.1.29
  7. // @author kkocdko
  8. // @license Unlicense
  9. // @match *://*.just.edu.cn/*
  10. // @match *://*.just.edu.cn:8080/*
  11. // @match *://10.250.255.34/*
  12. // @match *://202.195.195.198/*
  13. // @match *://202.195.206.36:8080/*
  14. // @match *://202.195.206.37:8080/*
  15. // ==/UserScript==
  16. "use strict";
  17.  
  18. const { addFloatButton, waitValue, saveStr } = {
  19. addFloatButton(text, onClick) /* 20200707-1237 */ {
  20. if (!document.addFloatButton) {
  21. const container = document.body
  22. .appendChild(document.createElement("div"))
  23. .attachShadow({ mode: "open" });
  24. container.innerHTML =
  25. "<style>:host{position:fixed;top:3px;left:3px;z-index:2147483647;height:0}#i{display:none}*{float:left;margin:4px;padding:1em;outline:0;border:0;border-radius:5px;background:#1e88e5;box-shadow:0 1px 4px rgba(0,0,0,.1);color:#fff;font-size:14px;line-height:0;transition:.3s}:active{background:#42a5f5;box-shadow:0 2px 5px rgba(0,0,0,.2)}button:active{transition:0s}:checked~button{visibility:hidden;opacity:0;transform:translateY(-3em)}label{border-radius:50%}:checked~label{opacity:.3;transform:translateY(3em)}</style><input id=i type=checkbox><label for=i></label>";
  26. document.addFloatButton = (text, onClick) => {
  27. const button = document.createElement("button");
  28. button.textContent = text;
  29. button.addEventListener("click", onClick);
  30. return container.appendChild(button);
  31. };
  32. }
  33. return document.addFloatButton(text, onClick);
  34. },
  35. waitValue(fn, interval = 200, timeout = 3000) /* 20220104-1405 */ {
  36. return new Promise((resolve, reject) => {
  37. const intervalHandle = setInterval(() => {
  38. try {
  39. const value = fn();
  40. if (!value) return;
  41. clearInterval(intervalHandle);
  42. clearTimeout(timeoutHandle);
  43. resolve(value);
  44. } catch {}
  45. }, interval);
  46. const timeoutHandle = setTimeout(() => {
  47. clearInterval(intervalHandle);
  48. reject("waitValue: timeout");
  49. }, timeout);
  50. });
  51. },
  52. saveStr(name, str) /* 20211203-1130 */ {
  53. const el = document.createElement("a");
  54. el.download = name;
  55. el.href = URL.createObjectURL(new Blob([str]));
  56. el.click();
  57. },
  58. };
  59.  
  60. const urlMatch = /* match url prefix, supports webvpn */ ([s]) =>
  61. location.href.match(/(?<=:..+)\/(?!http|webvpn).+/)[0].startsWith(s);
  62.  
  63. // Styles
  64. document.lastChild.appendChild(document.createElement("style")).textContent = `
  65. body { overflow-x: auto; }
  66. #browserPrompt { display: none; }
  67. input.button { background-color: #07e; }
  68. .checked .iCheck-helper { background: none; border: solid #22645e; border-radius: 50%; opacity: 1; }
  69. `.replace(/;/g, "!important;");
  70.  
  71. // Force page to scroll on x axis
  72. waitValue(() => document.readyState !== "loading").then(() => {
  73. if (top !== self || document.documentElement.offsetWidth >= 1280) return;
  74. addFloatButton("Scroll X Axis", () => {
  75. document.documentElement.style.cssText +=
  76. "min-width: 1280px !important; overflow-x: scroll !important";
  77. });
  78. });
  79.  
  80. // Auto login
  81. if (urlMatch`/cas/login`)
  82. setTimeout(() => document.querySelector(".login_btn").click(), 100);
  83.  
  84. // Fix P.E. page left panel
  85. if (urlMatch`/menu.asp?menu`) {
  86. setTimeout(() => {
  87. for (const el of document.querySelectorAll("[onclick]")) {
  88. const v = el.getAttribute("onclick").replace("href(", "href=(");
  89. el.setAttribute("onclick", v);
  90. }
  91. }, 900);
  92. }
  93.  
  94. // Health clock in
  95. if (urlMatch`/default/work/jkd/jkxxtb/jkxxcj.jsp`) {
  96. addFloatButton("Clock in", () => {
  97. input_tw.value = input_zwtw.value = 36;
  98. post.click();
  99. });
  100. }
  101.  
  102. // Schedule dump
  103. if (urlMatch`/jsxsd/xskb/xskb_list.do`) {
  104. addFloatButton("Dump schedule", () => {
  105. saveStr(
  106. `schedule_${zc.value}_${Date.now().toString(36).slice(0, -2)}.html`,
  107. `<!DOCTYPE html><meta name="viewport" content="width=device-width">` +
  108. kbtable.outerHTML
  109. );
  110. });
  111. }
  112.  
  113. // Teaching Evaluation
  114. if (urlMatch`/jsxsd/xspj/xspj_edit.do`) {
  115. addFloatButton("Fill form", () => {
  116. for (const el of document.querySelectorAll("[type=radio]:first-child"))
  117. el.click();
  118. document.querySelector("[type=radio]:not(:first-child)").click();
  119. });
  120. }
  121.  
  122. // GPA Estimation
  123. // https://github.com/mikai233/fstar-client/blob/e387e2948f158968e01d0497375ef60faccc589e/lib/utils/utils.dart
  124. // if (location.pathname.endsWith("/cjcx_list")) {
  125. // addFloatButton("Estimate GPA", () => {});
  126. // }
  127.  
  128. // Fix `window.showModalDialog`
  129. (this.unsafeWindow || this).showModalDialog = async (url, args, opt = "") => {
  130. // Thanks for github.com/niutech/showModalDialog
  131. const dialog = document.body.appendChild(document.createElement("dialog"));
  132. dialog.style = `padding:0;${opt.replace(/dialog/gi, "")}`;
  133. const iframe = dialog.appendChild(document.createElement("iframe"));
  134. iframe.style = "width:100%;height:100%;border:0";
  135. iframe.src = url;
  136. dialog.showModal();
  137. await new Promise((r) => (iframe.onload = r));
  138. iframe.contentWindow.close = () => dialog.remove();
  139. iframe.contentWindow.dialogArguments = args;
  140. };
  141.  
  142. // Free WLAN?
  143. // (this.unsafeWindow || self).XMLHttpRequest = new Proxy(XMLHttpRequest, {
  144. // construct: (T, args) => {
  145. // const ret = new T(...args);
  146. // let inner = null;
  147. // Object.defineProperty(ret, "onreadystatechange", {
  148. // value(...args) {
  149. // if (ret.readyState == 4 &&ret.responseURL === "http://10.250.255.34/api/v1/login") {}
  150. // if (inner) inner(...args);
  151. // },
  152. // set: (n) => (inner = n),
  153. // });
  154. // return ret;
  155. // },
  156. // });
  157. // if (property == "responseText" && target.responseURL === "http://10.250.255.34/api/v1/login") {
  158. // const json = JSON.parse(target.responseText);
  159. // if (json?.data?.policy?.pagenumb === "mondaypage") {
  160. // json.data.policy.channels.push({ name: "XSWK", id: "1" });
  161. // target.responseText = JSON.stringify(json);
  162. // }
  163. // let b = target.responseText;
  164. // let a = `{"code":200,"message":"ok","data":{"reauth":true,"policy":{"pagenumb":"mondaypage","channels":[{"name":"中国移动","id":"2"},{"name":"中国电信","id":"3"},{"name":"中国联通","id":"4"}]}}}`;
  165. // }
  166.  
  167. /* ===== Notes ===== *
  168.  
  169. 个人主页:my.just.edu.cn
  170. VPN2反代:vpn2.just.edu.cn
  171. 360SO via VPN2:client.v.just.edu.cn/https/webvpnb153e15136e234229309c84507966ea4
  172. 教务系统(自动登录):jwgl.just.edu.cn:8080/sso.jsp
  173. 后勤:hqgy.just.edu.cn/sg/wechat/index.jsp
  174. 查寝分数:hqgy.just.edu.cn/sg/wechat/healthCheck.jsp
  175. 健康打卡:ehall.just.edu.cn/default/work/jkd/jkxxtb/jkxxcj.jsp
  176. 体育:tyxy.just.edu.cn
  177. 网课:teach.just.edu.cn
  178. 实验课成绩:202.195.195.198/sy/
  179. 退出登录:ids2.just.edu.cn/cas/logout
  180. 智慧树:http://portals.zhihuishu.com/just
  181. 超星:http://just.fanya.chaoxing.com
  182. 安全微伴:https://weiban.mycourse.cn/pharos/login/jskjdx/21200002/loginByJskjdx.do
  183.  
  184. 教务系统内网:
  185. http://202.195.206.36:8080/jsxsd
  186. http://202.195.206.37:8080/jsxsd
  187.  
  188. 奇怪的管理界面:
  189. https://client.v.just.edu.cn/enlink/#/client/app
  190.  
  191. VPN2 使用笔记:
  192. 使用 `360SO via VPN2` 搜索要访问的网址,记得加上 `http / https` 前缀。
  193. 搜索结果页出现“找不到该 URL,可以直接访问 `http://x.x`”后点击直接访问链接即可。
  194. 若遇到“无效网关”等奇怪错误,请检查协议前缀是否正确,如 http 可能误写为 https。
  195. 当前(20220110)VPN2 似乎不支持流式传输,因而下载大文件可能出错,记得校验 Hash。
  196.  
  197. /* ================= */