Greasy Fork is available in English.

JUST Kit

Patches & tools for JUST Website.

  1. // ==UserScript==
  2. // @name JUST Kit
  3. // @description Patches & tools for JUST Website.
  4. // @description:en Patches & tools for JUST Website.
  5. // @description:zh-CN 用于江苏科技大学网站的补丁与工具。
  6. // @namespace https://greasyfork.org/users/197529
  7. // @version 0.2.3
  8. // @author kkocdko
  9. // @license Unlicense
  10. // @match *://*.just.edu.cn/*
  11. // @match *://*.just.edu.cn:8080/*
  12. // @match *://10.250.255.34/*
  13. // @match *://202.195.195.198/*
  14. // @match *://202.195.206.36:8080/*
  15. // @match *://202.195.206.37:8080/*
  16. // ==/UserScript==
  17. "use strict";
  18.  
  19. const { addFloatButton, saveStr } = {
  20. addFloatButton(text, onclick) /* 20220509-1936 */ {
  21. if (!document.addFloatButton) {
  22. const host = document.body.appendChild(document.createElement("div"));
  23. const root = host.attachShadow({ mode: "open" });
  24. root.innerHTML = `<style>:host{position:fixed;top:4px;left:4px;z-index:2147483647;height:0}#i{display:none}*{float:left;padding:0 1em;margin:4px;font-size:14px;line-height:2em;color:#fff;user-select:none;background:#28e;border:1px solid #fffa;border-radius:8px;transition:.3s}[for]~:active{filter:brightness(1.1);transition:0s}:checked~*{opacity:.3;transform:translateY(-3em)}:checked+*{transform:translateY(3em)}</style><input id=i type=checkbox><label for=i>&zwj;</label>`;
  25. document.addFloatButton = (text, onclick) => {
  26. const el = document.createElement("label");
  27. el.textContent = text;
  28. el.addEventListener("click", onclick);
  29. return root.appendChild(el);
  30. };
  31. }
  32. return document.addFloatButton(text, onclick);
  33. },
  34. saveStr(name, str) /* 20211203-1130 */ {
  35. const el = document.createElement("a");
  36. el.download = name;
  37. el.href = URL.createObjectURL(new Blob([str]));
  38. el.click();
  39. },
  40. };
  41.  
  42. const urlMatch = /* match url prefix, supports webvpn */ ([s]) =>
  43. location.href.match(/(?<=:..+)\/(?!http|webvpn).+/)[0].startsWith(s);
  44.  
  45. // Styles
  46. document.lastChild.appendChild(document.createElement("style")).textContent = `
  47. input.button { background-color: #07e; }
  48. .iradio_square-green.checked { box-shadow: inset 0 0 4px; border-radius: 50%; }
  49. `.replace(/;/g, "!important;");
  50.  
  51. // Force page to scroll on x axis
  52. if (
  53. top === self &&
  54. (urlMatch`/_s2/students_` || urlMatch`/TeachingCenterStudentWeb`)
  55. ) {
  56. document.documentElement.style.cssText +=
  57. ";min-width: 1280px !important; overflow-x: auto !important;";
  58. }
  59.  
  60. // Auto login
  61. if (urlMatch`/cas/login`) {
  62. setInterval(() => {
  63. if (!rememberPassword.checked) return;
  64. const el = document.querySelector(".login_btn");
  65. el.click();
  66. el.click = () => {};
  67. }, 100);
  68. }
  69.  
  70. // Fix P.E. page left panel
  71. if (urlMatch`/menu.asp?menu`) {
  72. setTimeout(() => {
  73. for (const el of document.querySelectorAll("[onclick]")) {
  74. const v = el.getAttribute("onclick").replace("href(", "href=(");
  75. el.setAttribute("onclick", v);
  76. }
  77. }, 900);
  78. }
  79.  
  80. // Health check in
  81. if (urlMatch`/static/?health-check-in`) {
  82. document.head.innerHTML += `<meta name=viewport content="width=device-width"><style>body{margin:0}iframe{border:0;width:100%;height:100%}</style>`;
  83. document.body.innerHTML = `<iframe src=../jkdk.html></iframe>`;
  84. document.title = "just-kit-health-check-in";
  85. const key = document.title + "-location";
  86. addFloatButton("Check in", () => {
  87. const iframe = document.querySelector("iframe").contentWindow.document;
  88. const el = iframe.querySelector("input[placeholder$=定位]");
  89. el.value = localStorage[key];
  90. el._valueTracker.setValue(""); // github.com/facebook/react/issues/11488#issuecomment-347775628
  91. el.dispatchEvent(new Event("input", { bubbles: true }));
  92. setTimeout(() => iframe.querySelector("form+*>*").click());
  93. });
  94. addFloatButton(`Location = ${localStorage[key]}`, function () {
  95. localStorage[key] = prompt(key, localStorage[key]);
  96. this.textContent = `Location = ${localStorage[key]}`;
  97. });
  98. }
  99.  
  100. // Schedule dump
  101. if (urlMatch`/jsxsd/xskb/xskb_list.do`) {
  102. addFloatButton("Dump schedule", () => {
  103. const date = Date.now().toString(36).slice(0, -2);
  104. const name = `schedule_${zc.value || 0}_${date}.html`;
  105. const prefix = `<!DOCTYPE html><meta charset="utf-8"><meta name="viewport" content="width=device-width"><style>body{margin:2px -1px;font-family:sans-serif}table{border:0}</style>`;
  106. const content = prefix + kbtable.outerHTML;
  107. document.documentElement.innerHTML = content;
  108. document.title = name;
  109. saveStr(name, content);
  110. });
  111. }
  112.  
  113. // Schedule dump
  114. if (urlMatch`/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html`) {
  115. addFloatButton("Better schedule", () => {
  116. let v = Math.floor(
  117. (Date.now() - new Date("2023-02-20 00:00:00 +8").getTime()) /
  118. 1000 /
  119. 3600 /
  120. 24 /
  121. 7 +
  122. 1
  123. );
  124. v = +prompt("Week = ", v);
  125.  
  126. if (v !== 0)
  127. document
  128. .querySelectorAll("#kblist_table .glyphicon-calendar")
  129. .forEach((el) => {
  130. let arr = [...el.nextSibling.textContent.matchAll(/\d+-?\d*/g)]
  131. .map((v) => v[0])
  132. .map((t) => (t.includes("-") ? t : t + "-" + t))
  133. .map((v) => v.split("-").map((n) => +n));
  134. for (const [from, to] of arr) {
  135. if (from <= v && v <= to) {
  136. return;
  137. }
  138. }
  139. const cur =el.parentNode.parentNode.parentNode.parentNode;
  140. console.log(cur);
  141. return;
  142. if (cur.parentNode?.nextSibling?.children?.[0]?.rowSpan)
  143. cur.remove();
  144. else cur.parentNode.remove();
  145. });
  146. document
  147. .querySelectorAll(
  148. "#kblist_table>tbody>tr:not(:first-child)>td:first-child"
  149. )
  150. .forEach((el) => {
  151. // el.setAttribute("rowspan", "1");
  152. });
  153. document.querySelectorAll(".timetable .week").forEach((el) => {
  154. el.textContent = el.textContent.slice(2);
  155. });
  156. document.querySelector("#kblist_table .pull-left").nextSibling.remove();
  157. document.querySelector("#kblist_table .pull-left").nextSibling.remove();
  158. document.querySelector('button[href="#table2"]').click();
  159. document
  160. .querySelectorAll(
  161. "#kblist_table .glyphicon-tower, #kblist_table .glyphicon-home"
  162. )
  163. .forEach((el) => {
  164. el.nextSibling.remove();
  165. el.remove();
  166. });
  167. document.querySelectorAll("#kblist_table .glyphicon").forEach((el) => {
  168. el.remove();
  169. });
  170. document.querySelectorAll("#kblist_table td p>font").forEach((el) => {
  171. el.textContent = el.textContent.replace(/^.*?[::]/, " ");
  172. });
  173. document.querySelectorAll(".timetable .week").forEach((el) => {
  174. el.parentNode.width = 24;
  175. });
  176. document.querySelectorAll(".timetable .festival").forEach((el) => {
  177. el.parentNode.width = 34;
  178. });
  179. document.lastChild.appendChild(
  180. document.createElement("style")
  181. ).textContent = `
  182. .timetable .timetable_con { padding: 4px 4px; overflow: hidden;}
  183. .table-bordered,.table>tbody+tbody {border:none;}
  184. .table-bordered>thead>tr>th, .table-bordered>tbody>tr>th, .table-bordered>tfoot>tr>th, .table-bordered>thead>tr>td, .table-bordered>tbody>tr>td, .table-bordered>tfoot>tr>td { border:1px solid #555; border-width: 1px 0 0 0;}
  185. .timetable .week,.timetable .festival{color:#000;}
  186. .timetable .festival{white-space: nowrap;}
  187. .timetable .timetable_con .title { width: 14em; margin-right: 2em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;}
  188. .table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td { padding: 0;}
  189. #table2{ background: #fff; position: fixed; left: 0; top: 0; width: 100vw; overflow: scroll; height: 100vh;}
  190. #table2 font[color="blue"]{color: #000;}*{ font-weight: normal; font-size:16px;font-family: sans-serif;}
  191. .timetable .week{padding:0 4px 0 0;}
  192. `.replace(/;/g, "!important;");
  193. });
  194. }
  195.  
  196. // Teaching evaluation
  197. if (urlMatch`/jsxsd/xspj/xspj_edit.do`) {
  198. addFloatButton("Fill form", () => {
  199. for (const el of document.querySelectorAll("[type=radio]:first-child"))
  200. el.click();
  201. document.querySelector("[type=radio]:not(:first-child)").click();
  202. });
  203. }
  204.  
  205. // Fix `window.showModalDialog`
  206. (this.unsafeWindow || this).showModalDialog = (url) => open(url);
  207.  
  208. // GPA Estimation
  209. // github.com/mikai233/fstar-client/blob/e387e2948f158968e01d0497375ef60faccc589e/lib/utils/utils.dart
  210. // if (location.pathname.endsWith("/cjcx_list")) {
  211. // addFloatButton("Estimate GPA", () => {});
  212. // }
  213.  
  214. // Free WLAN?
  215. // (this.unsafeWindow || self).XMLHttpRequest = new Proxy(XMLHttpRequest, {
  216. // construct: (T, args) => {
  217. // const ret = new T(...args);
  218. // let inner = null;
  219. // Object.defineProperty(ret, "onreadystatechange", {
  220. // value(...args) {
  221. // if (ret.readyState == 4 &&ret.responseURL === "http://10.250.255.34/api/v1/login") {}
  222. // if (inner) inner(...args);
  223. // },
  224. // set: (n) => (inner = n),
  225. // });
  226. // return ret;
  227. // },
  228. // });
  229. // if (property == "responseText" && target.responseURL === "http://10.250.255.34/api/v1/login") {
  230. // const json = JSON.parse(target.responseText);
  231. // if (json?.data?.policy?.pagenumb === "mondaypage") {
  232. // json.data.policy.channels.push({ name: "XSWK", id: "1" });
  233. // target.responseText = JSON.stringify(json);
  234. // }
  235. // let b = target.responseText;
  236. // let a = `{"code":200,"message":"ok","data":{"reauth":true,"policy":{"pagenumb":"mondaypage","channels":[{"name":"中国移动","id":"2"},{"name":"中国电信","id":"3"},{"name":"中国联通","id":"4"}]}}}`;
  237. // }
  238.  
  239. // http://www.gaoxiaokaoshi.com/Study/LibraryStudyList.aspx
  240. // const grid=document.body.appendChild(document.createElement('parallel-grid'))
  241. // grid.style="display:grid;grid:1fr 1fr 1fr 1fr/ 1fr 1fr 1fr;width:100vw;height:100vh"
  242. // showframe=(p_Name, p_Id)=>{grid.appendChild(document.createElement('iframe')).src="../Study/LibraryStudy.aspx?tmp=1&Id=" + p_Id + "&PlanId=" + ddlClass.value}
  243.  
  244. /* ===== Notes ===== *
  245.  
  246. 个人主页: my.just.edu.cn
  247. VPN2反代: vpn2.just.edu.cn
  248. 360SO VPN2: client.v.just.edu.cn/https/webvpnb153e15136e234229309c84507966ea4
  249. 教务: jwgl.just.edu.cn:8080/jsxsd/
  250. 教务(单点登录): jwgl.just.edu.cn:8080/sso.jsp
  251. 教务(内网1): 202.195.206.36:8080/jsxsd
  252. 教务(内网2): 202.195.206.37:8080/jsxsd
  253. 财务: 218.3.134.246/WFManager/login.jsp
  254. 后勤: hqgy.just.edu.cn/sg/wechat/index.jsp
  255. 查寝得分: hqgy.just.edu.cn/sg/wechat/healthCheck.jsp
  256. 健康打卡: dc.just.edu.cn/static/?health-check-in
  257. 健康打卡(RAW): dc.just.edu.cn/jkdk.html
  258. 健康打卡(旧): ehall.just.edu.cn/default/work/jkd/jkxxtb/jkxxcj.jsp
  259. 体育: tyxy.just.edu.cn
  260. 网课: teach.just.edu.cn
  261. 实验课成绩: 202.195.195.198/sy/
  262. 退出登录: ids2.just.edu.cn/cas/logout
  263. 奇怪的管理界面: client.v.just.edu.cn/enlink/#/client/app
  264. 智慧树: portals.zhihuishu.com/just
  265. 超星: just.fanya.chaoxing.com
  266. 安全微伴: weiban.mycourse.cn/pharos/login/jskjdx/21200002/loginByJskjdx.do
  267. 国防教育: www.gaoxiaokaoshi.com
  268.  
  269. 关于 [ VPN2 ] :
  270. 就如 URI 中所写的那样,VPN2 只是一个类似反向代理的玩意。
  271. 由于学校网站配置千奇百怪,有时会遇到只有在校园网中才能访问的情况。这时可以使用 VPN2。
  272. 使用 `360SO via VPN2` 搜索要访问的网址。记得加上 `http / https` 前缀。
  273. 搜索结果页出现“找不到该 URL,可以直接访问 `http://x.x`”后点击直接访问链接即可。
  274. 遇“无效网关”等奇怪错误时,请检查协议前缀是否正确,如 http 可能误写为 https。
  275. 当前(20220110)VPN2 似乎不支持流式传输,因而下载大文件可能出错,记得校验 Hash。
  276.  
  277. 关于 [ 健康打卡 ] :
  278. 新版(20220420)健康打卡报表使用 Hash Router,各跳转关系十分混乱且不稳定。
  279. 为简化实现,当且仅当访问上文指定的地址时才可使用一键打卡功能。
  280. 直接 Post 请求进行打卡的实现在本目录下的 health-check-in.js 中,感兴趣的可以尝试。
  281.  
  282. 如果 [ 教务系统提示 非法访问 ] :
  283. 相信自己,你并没有做错什么。这时候你可以清除 Cookie,SessionStorage 等数据。
  284. 当然 Cookie 会自动过期,所以和跳大神治麻疹一样,随便用点什么“独门秘籍”,过一阵子也就自己好了。
  285.  
  286. 如果 [ 密码错误 ] :
  287. 只需将 [ just123456, 123456, <身份证后六位> ] 排列组合即可。
  288.  
  289. 关于 [ 校园网 ] :
  290.  
  291. /* ================= */