您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
为 USTC 学生定制的各类实用功能:绕过验证码,自动登录(不可用),睿客网性能优化以及更多。
当前为
// ==UserScript== // @name USTC Helper // @name:zh-CN USTC 助手 // @license gpl-3.0 // @namespace http://tampermonkey.net/ // @version 0.8.0 // @description Various useful functions for USTC students: verification code bypass, auto login, rec performance improvement and more. // @description:zh-CN 为 USTC 学生定制的各类实用功能:绕过验证码,自动登录(不可用),睿客网性能优化以及更多。 // @author PRO // @match https://mail.ustc.edu.cn/ // @match https://mail.ustc.edu.cn/coremail/index.jsp* // @match https://passport.ustc.edu.cn/* // @match https://rec.ustc.edu.cn/* // @match https://recapi.ustc.edu.cn/identity/other_login?* // @match https://www.bb.ustc.edu.cn/* // @match https://jw.ustc.edu.cn/login // @match https://young.ustc.edu.cn/login/* // @icon https://passport.ustc.edu.cn/images/favicon.ico // @grant none // ==/UserScript== (function () { 'use strict'; var uhp_config = { passport: { enabled: true, // If false, all features will be disabled for passport.ustc.edu.cn bypass_code: true, // Whether to bypass verification code or not focus: true, // Whether to focus on "Login" button service: true // Hint service domain and its credibility }, mail: { enabled: true, // If false, all features will be disabled for mail.ustc.edu.cn focus: true, // Whether to focus on "Login" button domain: 'mail.ustc.edu.cn' // Automatically switch to given mail domain // Expected values: // 'mail.ustc.edu.cn' // 'ustc.edu.cn' // 'ah.edu.cn' // '' (Do nothing) }, rec: { enabled: true, // If false, all features will be disabled for rec.ustc.edu.cn & recapi.ustc.edu.cn autologin: true, // Whether automatically clicks login (USTC cas login) opencurrent: true // Whether open links in current tab (Significantly improves performance) }, bb: { enabled: true, // If false, all features will be disabled for www.bb.ustc.edu.cn autoauth: true, // Whether automatically authenticate when accessing outside school net autologin: true, // Whether automatically clicks login showhwstatus: true // Whether to display homework status (may consume some traffic) }, jw: { enabled: true, // ... login: 'focus' // What to do to the login button: 'none', 'focus', 'click' }, young: { enabled: true, default_tab: true, // Auto navigate to frequently-used submenu no_datascreen: true // Remove annoying data screen image } }; switch (window.location.host) { case 'mail.ustc.edu.cn': { if (!uhp_config.mail.enabled) { console.info("[USTC Helper] 'mail' feature disabled."); break; } if (uhp_config.mail.domain) { changeDomain(uhp_config.mail.domain); console.info(`[USTC Helper] Domain changed to ${uhp_config.mail.domain}.`); } if (uhp_config.mail.focus) { document.getElementById("login_button").focus(); console.info("[USTC Helper] Login button focused."); } break; } case 'passport.ustc.edu.cn': { if (!uhp_config.passport.enabled) { console.info("[USTC Helper] 'passport' feature disabled."); break; } let form = document.getElementsByClassName('loginForm')[0]; if (!form) { console.log("[USTC Helper] Form not found!"); break; } let options = { childList: true, attributes: false, subtree: true } function bypass() { let showCode = document.getElementsByName('showCode')[0]; showCode.value = ""; let code = document.querySelector('#valiCode'); if (code) { code.remove(); console.info("[USTC Helper] Verification code bypassed."); } else { console.info("[USTC Helper] Verification code not found."); } } function focus() { document.getElementById('login').focus(); console.info("[USTC Helper] Login button focused."); } function hint() { let notice = document.createElement('p'); let params = new URL(window.location.href).searchParams; let service_url = params.get('service'); if (!service_url) return; service_url = decodeURIComponent(service_url); let domain = service_url.split('/')[2]; let color; let status; // Official Student/Staff Third-party let suffix; if (/.+\.ustc\.edu\.cn/.test(domain)) { if (domain == 'home.ustc.edu.cn') { status = "Student"; color = "#d0d01b"; suffix = "@mail.ustc.edu.cn"; } else if (domain == 'staff.ustc.edu.cn') { status = "Staff"; color = "#d0d01b"; suffix = "@ustc.edu.cn"; } else { status = "Official"; color = "green"; } } else { status = "Third-party"; color = "red"; } console.info(`[USTC Helper] ${status} service: ${service_url}`); if (color == "#d0d01b") { let regex = new RegExp(/https?:\/\/(home|staff)\.ustc\.edu\.cn\/~([^\/]+)/i); let match = service_url.match(regex); if (match) { let name = match[2]; let email = name + suffix; console.log("[USTC Helper] Contact email: " + email); notice.innerHTML = `<a style="color: #d0d01b;" title="Contact" href="mailto:${email}">${status}</a> service: <span style="color: grey;" title="${service_url}">${domain}</span>`; } else { console.log("[USTC Helper] Unable to determine contact email!"); notice.innerHTML = `<a style="color: #d0d01b;" title="Unrecognized">${status}</a> service: <span style="color: grey;" title="${service_url}">${domain}</span>`; } } else { notice.innerHTML = `<span style="color: ${color};">${status}</span> service: <span style="color: grey;" title="${service_url}">${domain}</span>`; } let main_card = document.getElementsByClassName('card')[0]; main_card.insertAdjacentElement('afterbegin', notice); } function main() { if (uhp_config.passport.bypass_code) bypass(); if (uhp_config.passport.focus) focus(); if (uhp_config.passport.service) hint(); observer.disconnect(); } let observer = new MutationObserver(main); observer.observe(form, options); break; } case 'rec.ustc.edu.cn': { if (!uhp_config.rec.enabled) { console.info("[USTC Helper] 'rec' feature disabled."); break; } if (uhp_config.rec.opencurrent) { window.webpackJsonp.push_ = window.webpackJsonp.push; window.webpackJsonp.push = (val) => { if (val[0][0] !== "chunk-5ae262a1") return window.webpackJsonp.push_(val); else { // Following script is adapted from https://rec.ustc.edu.cn/js/chunk-5ae262a1.b84e1461.js val[1]["2c03"] = function (t, e, s) { "use strict"; (function (t) { s("55dd"); var r = s("a67e"); e["a"] = { name: "GroupLister", components: { GroupCreate: function () { return Promise.all([s.e("chunk-390136ce"), s.e("chunk-662e27b9")]).then(s.bind(null, "18fa")) }, GroupAdd: function () { return s.e("chunk-5b916374").then(s.bind(null, "c1c7")) }, GroupEdit: function () { return Promise.all([s.e("chunk-390136ce"), s.e("chunk-0daeb591")]).then(s.bind(null, "1fa6")) } }, data: function () { return { status: { GroupCreateStatus: !1, GroupAddStatus: !1, GroupEditStatus: !1 }, loading: !1, nothing: !1, group: {}, sortBy: {}, headers: [{ id: 1, title: "群名称", class: "groupname", sort: "asc", showSort: !0, field: "group_name" }, { id: 2, title: "群号", class: "groupid", sort: "des", showSort: !1, field: "group_number" }, { id: 3, title: "成员", class: "groupuser", sort: "des", showSort: !1, field: "group_memeber_count" }, { id: 5, title: "分享", class: "groupshare", sort: "des", showSort: !1, field: "group_share_file_count" }, { id: 6, title: "操作", class: "groupmenu", sort: "", showSort: !1 }] } }, created: function () { this.sortBy = this.headers[0], this.getGroups() }, computed: { userInfo: function () { return this.$store.state.user.userInfo } }, watch: { $route: function () { this.getGroups() } }, filters: { identityNameFilter: function (t) { var e; switch (t) { case "owner": e = "群主"; break; case "admin": e = "管理员"; break; case "user": e = "成员"; break; default: break } return e } }, methods: { createGroup: function () { t("#newgroup").modal("show") }, addGroup: function () { t("#addgroup").modal("show") }, invite: function (t) { var e = this.$router.resolve({ name: "group", params: { groupNumber: t.group_number } }); this.$confirm({ showYesBtn: !1, showCopyBtn: !0, copyBtnText: "复制文字", title: "邀请入群", type: "confirm", content: "打开链接进入群组主页即可申请加入群组:".concat(t.group_name, ",群组主页链接:").concat(window.location.origin).concat(e.href) }).then((function () { } )).catch((function () { } )) }, goToGroupCloud: function (t, e) { if (["owner", "admin", "user"].indexOf(t.group_member_identity) < 0) return this.$message({ type: "warning", message: "您不是组群成员,无法进入群盘" }), !1; this.$store.commit("setSetting", { from: !0, drive: "groupdisk", tab: e, group: t }), this.$router.push({ name: "groupDisk", params: { groupNumber: t.group_number } }) }, isShowMenu: function (t) { return ["owner", "admin", "user"].indexOf(t.group_member_identity) > -1 }, isEditGroup: function (t) { return ["owner", "admin"].indexOf(t.group_member_identity) > -1 }, goToGroup: function (t) { var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : "group"; if ("wait" === t.group_is_review) return this.$message({ type: "warning", message: "群组待审核,不允许操作!" }), !1; if ("refuse" === t.group_is_review) return this.$message({ type: "warning", message: "群组审核未通过,不允许操作!" }), !1; // Instead of opening in new tab, we prefer to use vue's solution // Modifiy start this.$router.replace({ name: e, params: { groupNumber: t.group_number } }); // Modify end }, goToGroupHome: function (t) { this.$store.commit("SET_GROUP_SHOWDESC", !1), this.$router.push({ name: "group", params: { groupNumber: t } }) }, handleEditGroup: function (e) { var s = this; Object(r["g"])(e.group_number).then((function (t) { s.group = t.entity } )).catch((function (t) { s.$message({ type: "error", message: t }) } )), t("#editgroup").modal("show") }, groupRefresh: function () { this.getGroups() }, sortGroup: function (t) { if (6 === t) return !1; var e = this; this.headers.map((function (s) { return s.id === t ? (s.showSort = !0, s.sort = "des" === s.sort ? "asc" : "des", e.sortBy = s, s) : (s.showSort = !1, s.sort = "des", s) } )), this.sortGroupBy() }, getGroups: function () { var t = this; this.groups = [], this.loading = !0, this.nothing = !1, Object(r["r"])({}).then((function (e) { if (200 === e.status_code) if (t.loading = !1, t.groups = e.entity.datas, e.entity.total > 0) { var s = 0; e.entity.datas.map((function (t) { "user" != t.group_member_identity && t.group_pending_member_count > 0 && (s += t.group_pending_member_count) } )), t.$store.commit("setRequestNums", s), t.sortGroupBy(!0) } else t.nothing = !0; else t.$message({ type: "error", message: e.message }) } )).catch((function (e) { t.$message({ type: "error", message: e }) } )) }, sortGroupBy: function () { var t = this , e = arguments.length > 0 && void 0 !== arguments[0] && arguments[0]; this.groups.sort((function (s, r) { var o; return o = e ? r.group_is_review.localeCompare(s.group_is_review) : "group_name" === t.sortBy.field ? s[t.sortBy.field].localeCompare(r[t.sortBy.field]) : s[t.sortBy.field] - r[t.sortBy.field], o = "asc" === t.sortBy.sort ? o : -o, o } )) }, groupCancel: function (t) { var e = this , s = "adopt" === t.group_is_review ? "解散" : "删除"; this.$confirm({ type: "confirm", content: "".concat(s, "群后,所有关于本群组的信息都将被删除且无法恢复,确定").concat(s, "【").concat(t.group_name, "】吗?"), showCancleBtn: !0, showYesBtn: !0, custom: [] }).then((function () { Object(r["u"])({ groups_list: [t.group_number] }).then((function (t) { 200 === t.status_code ? (e.$message({ type: "success", message: t.message }), e.getGroups()) : e.$message({ type: "error", message: t.message }) } )).catch((function (t) { e.$message({ type: "error", message: t }) } )) } )).catch((function () { } )) }, groupQuit: function (t) { var e = this; this.$confirm({ type: "confirm", content: "确定退出该群组吗?", showCancleBtn: !0, showYesBtn: !0, custom: [] }).then((function () { Object(r["v"])({ group_number: t, action: "quit", members_list: [e.userInfo.user_number] }).then((function (t) { 200 === t.status_code ? (e.$message({ type: "success", message: t.message }), e.getGroups()) : e.$message({ type: "error", message: t.message }) } )).catch((function (t) { e.$message({ type: "error", message: t }) } )) } )).catch((function () { } )) } }, mounted: function () { var t = this; setTimeout((function () { for (var e in t.status) t.status[e] = !0 } ), 500) } } } ).call(this, s("1157")) }; // console.log(val); return window.webpackJsonp.push_(val); } }; } if (uhp_config.rec.autologin && document.location.pathname == '/') { let app = document.getElementById("app"); let options = { childList: true, attributes: false, subtree: true } let observer = new MutationObserver(() => { let btn = document.getElementsByClassName('navbar-login-btn')[0]; if (btn) { btn.click(); observer.disconnect(); } }); observer.observe(app, options); } else if (uhp_config.rec.opencurrent) { let app = document.getElementById("app"); let options = { childList: true, attributes: false, subtree: true } let observer = new MutationObserver(() => { let l = document.getElementsByClassName("app-list").length; if (l) { let links = app.getElementsByTagName("a"); for (let link of links) { if (link.target == '_blank') link.removeAttribute("target"); } } }); observer.observe(app, options); } break; } case 'recapi.ustc.edu.cn': { if (!uhp_config.rec.enabled) { console.info("[USTC Helper] 'rec' feature disabled."); break; } if (uhp_config.rec.autologin) { let btn = document.querySelector("#ltwo > div > button"); if (!btn) { console.error("[USTC Helper] Login button not found!"); } else { btn.click(); } } break; } case 'www.bb.ustc.edu.cn': { if (!uhp_config.bb.enabled) { console.info("[USTC Helper] 'bb' feature disabled."); break; } if (window.location.pathname == '/nginx_auth/' && uhp_config.bb.autoauth) { document.getElementsByTagName('a')[0].click(); } else if ((window.location.pathname == '/' || window.location.pathname == '/webapps/login/') && uhp_config.bb.autologin) { document.querySelector('#login > table > tbody > tr > td:nth-child(2) > span > a').click(); } else if (uhp_config.bb.showhwstatus && window.location.pathname == '/webapps/blackboard/content/listContent.jsp' && document.getElementById('pageTitleText').children[0].textContent == '作业区') { let hw_list = document.getElementById('content_listContainer'); let color_config = ['grey', 'green', 'red', 'yellow']; let hint_text = ['查询中', '已提交', '未提交', '查询错误']; // let hint_text = ['Checking', 'Submitted', 'Not submitted', 'Error']; async function query_status(link) { const r = await fetch(link); if (!r.ok) { console.log(`[USTC Helper] Failed to fetch "${r.url}": ${r.status} ${r.statusText}`); return 3; } else { let html = await r.text(); if (html.match(/<span id="pageTitleText">\n 复查提交历史记录: .+<\/span>/)) return 1; else if (html.match(/<span id="pageTitleText">\n 上载作业:.+<\/span>/)) return 2; else return 3; } } async function process(hw) { let link_ = hw.querySelector("h3 > a"); if (link_) { let status = 0; // 0: Checking 1: Uploaded 2: Not uploaded 3: Error let hint = document.createElement('span'); let ret = ''; hint.style.color = color_config[status]; hint.textContent = `(${hint_text[status]})`; link_.appendChild(hint); let link = link_.href; // https://www.bb.ustc.edu.cn/webapps/assignment/uploadAssignment?content_id=_106763_1&course_id=_12559_1&group_id=&mode=view let params = new URL(link).searchParams; let course_id = params.get("course_id"); let content_id = params.get("content_id"); let uploaded = sessionStorage.getItem(course_id); // Query from cache first if (uploaded) { uploaded = JSON.parse(uploaded); if (uploaded.indexOf(content_id) >= 0) { status = 1; console.log(`[USTC Helper] "${course_id}/${content_id}" present in cache, so this homework is uploaded.`); } } // Not in cache if (!status) { status = await query_status(link); if (status == 1) { ret = content_id; console.log(`[USTC Helper] Online query indicated that "${course_id}/${content_id}" is uploaded.`); } else if (status == 2) { console.log(`[USTC Helper] Online query indicated that "${course_id}/${content_id}" is not uploaded.`); } else { console.warn(`[USTC Helper] Online query "${course_id}/${content_id}" failed!`); } } hint.style.color = color_config[status]; hint.textContent = `(${hint_text[status]})`; return ret; } } let promises = []; for (let hw of hw_list.children) { promises.push(process(hw)); } Promise.all(promises).then( (values) => { let params = new URL(window.location.href).searchParams; let course_id = params.get('course_id'); let uploaded = sessionStorage.getItem(course_id); if (uploaded) { uploaded = JSON.parse(uploaded); } else { uploaded = []; } for (let content_id of values) { if (content_id.length) { uploaded.push(content_id); console.log(`[USTC Helper] Saving "${course_id}/${content_id}" to cache...`); } } sessionStorage.setItem(course_id, JSON.stringify(uploaded)); } ); } break; } case 'jw.ustc.edu.cn': { if (!uhp_config.jw.enabled) { console.info("[USTC Helper] 'jw' feature disabled."); break; } if (uhp_config.jw.login) { let btn = document.getElementById('login-unified-wrapper'); if (uhp_config.jw.login == 'focus') { btn.focus(); } else if (uhp_config.jw.login == 'click') { btn.click(); } else { console.error(`[USTC Helper] Unknown option for jw.login: ${uhp_config.jw.login}`); } } break; } case 'young.ustc.edu.cn': { if (!uhp_config.young.enabled) { console.info("[USTC Helper] 'young' feature disabled."); break; } let app = document.getElementById("app"); let router = app.__vue__.$router; function main() { let menu = app.querySelector(".ant-menu-root"); if (!menu) return; let submenus = menu.querySelectorAll("li.ant-menu-submenu-horizontal:not(.ant-menu-overflowed-submenu) > div"); if (!submenus.length) return; observer.disconnect(); if (uhp_config.young.default_tab) { submenus[0].onclick = (e) => { router.push('/dataAnalysis/studentAnalysis'); e.stopImmediatePropagation(); } submenus[1].onclick = (e) => { router.push('/personalInformation/personalReport'); } submenus[2].onclick = (e) => { router.push('/myproject/SignUp'); } submenus[5].onclick = (e) => { router.push('/isystem/departUserList'); } } if (uhp_config.young.no_datascreen) { app.querySelector("div.header-index-wide > a").remove(); } } let options = { childList: true, attributes: false, subtree: true } let observer = new MutationObserver(main); observer.observe(app, options); break; } default: console.error("[USTC Helper] Unexpected host: " + window.location.host); break; } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址