希赛

希赛页面优化

目前为 2022-10-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name EduCity
  3. // @name:zh-CN 希赛
  4. // @description Optimize the website of educity.cn.
  5. // @description:zh-CN 希赛页面优化
  6. // @namespace https://github.com/HaleShaw
  7. // @version 1.3.2
  8. // @author HaleShaw
  9. // @copyright 2021+, HaleShaw (https://github.com/HaleShaw)
  10. // @license AGPL-3.0-or-later
  11. // @homepage https://github.com/HaleShaw/TM-EduCity
  12. // @supportURL https://github.com/HaleShaw/TM-EduCity/issues
  13. // @contributionURL https://www.jianwudao.com/
  14. // @icon https://www.educity.cn/favicon.ico
  15. // @match https://www.educity.cn/wangxiao2/*
  16. // @match http://www.educity.cn/wangxiao2/*
  17. // @match https://uc.educity.cn/personalCenter/studyCenter.html
  18. // @match https://uc.educity.cn/tiku/testReport.html*
  19. // @match https://uc.educity.cn/tiku/examinationMode.html*
  20. // @match https://uc.educity.cn/tiku/examinationModeCopy.html*
  21. // @match https://wangxiao.xisaiwang.com/wangxiao2/*
  22. // @compatible Chrome
  23. // @grant GM_addStyle
  24. // @grant GM_info
  25. // ==/UserScript==
  26.  
  27. // ==OpenUserJS==
  28. // @author HaleShaw
  29. // @collaborator HaleShaw
  30. // ==/OpenUserJS==
  31.  
  32. (function () {
  33. "use strict";
  34. const zhiBoStyle = `
  35. /* 左上角标题 */
  36. #mainVid > div.vid_head > div.vid_hleft > a:not(:last-child),
  37.  
  38. /* 右上角“返回旧版、视频课程” */
  39. #mainVid > div.vid_head > div.vid_hright > a,
  40.  
  41. /* 离线观看 */
  42. #mainVid > div.vid_mid > div.vid_midL > div.vid_midL_top,
  43.  
  44. /* 右侧笔记、提问 */
  45. #mainVid > div.vid_mid > div.vid_midR > div.vid_midR_tab > div > a:nth-child(2),
  46. #mainVid > div.vid_mid > div.vid_midR > div.vid_midR_tab > div > a:nth-child(3),
  47.  
  48. /* 鼠标混入视频时的浮标按钮“新建笔记” */
  49. .vid_bj_new {
  50. display: none !important;
  51. }
  52.  
  53. .vid_head .vid_hright {
  54. padding-top: 0 !important;
  55. }
  56.  
  57. .vid_head {
  58. height: 25px !important;
  59. }
  60.  
  61. .vid_mid .vid_midL {
  62. padding: 0 !important;
  63. }
  64.  
  65. .vid_midR_tab,
  66. .vid_midR_tab > a,
  67. .vid_midR_tab > a > i,
  68. .vid_midR_tab > .vid_midR_ul,
  69. .vid_midR_tab > .vid_midR_ul > a,
  70. .vid_midR_tab > .vid_midR_ul > a > i,
  71. .tabhide .vid_midR{
  72. width: 28px !important;
  73. }
  74.  
  75. .tabhide .vid_mid {
  76. padding-right: 28px;
  77. }
  78. .vid_mid {
  79. padding-right: 439px;
  80. }
  81.  
  82. .vid_midR {
  83. width: 439px;
  84. }
  85.  
  86. .vid_tab_content {
  87. padding-bottom: 0;
  88. }
  89. `;
  90.  
  91. const testReportStyle = `
  92. .side.rightfixside,
  93. .cbox,
  94. .review,
  95. .doPane.note,
  96. .doPane.question,
  97. .notes,
  98. .advise,
  99. .answerTitle,
  100. .six.clearfix>span,
  101. .pull-right.clearfix,
  102. li.one, li.two, li.four, li.five,
  103. .tsbody,
  104. footer {
  105. display: none !important;
  106. }
  107.  
  108. .wrong,
  109. .wrong + .clearfix.dajx,
  110. .analysisAnswer.none,
  111. li.one.bt{
  112. display: block !important;
  113. }
  114.  
  115. .tsbody {
  116. padding: 5px 0 !important;
  117. }
  118.  
  119. .answerEnd>span {
  120. color: #51cb65;
  121. }
  122.  
  123. .answerEnd>div {
  124. color: #a3a3af;
  125. text-decoration: line-through;
  126. }
  127. `;
  128.  
  129. const examStyle = `
  130. div.col-md-12 > div > div.zt_top_right,
  131. div.doPane.note,
  132. div.doPane.question,
  133. div.shitiDesp.pdt15 > div.jiexinew:nth-child(3),
  134. div.answerTitle,
  135. #ztsetWrap > div.bg-fff.box-shadow,
  136. #scantronWrap > div > div.dtklist > div.cbnWrap > h5,
  137. #scantronWrap > div > div.spanExplain{
  138. display: none !important;
  139. }
  140.  
  141. .right-title {
  142. padding: 0 20px !important;
  143. margin-bottom: 0px !important;
  144. }
  145.  
  146. .zt_top_zong {
  147. height: 65px !important;
  148. background: none !important;
  149. }
  150.  
  151. div.col-md-9 > div.bg-fff.box-shadow.mgt10.subject-content {
  152. background: none !important;
  153. }
  154.  
  155. .bp20 {
  156. padding: 6px !important;
  157. }
  158.  
  159. #ztsetWrap {
  160. margin-top: -96px !important;
  161. }
  162.  
  163. .dtklist>.cbnWrap {
  164. max-height: 837px !important;
  165. padding: 5px 20px 0px 20px !important;
  166. }
  167.  
  168. .col-md-3 {
  169. width: 19% !important;
  170. }
  171.  
  172. .pdb20 {
  173. padding-bottom: 0px !important;
  174. }
  175.  
  176. .subjectBody {
  177. padding-bottom: 0px !important;
  178. }
  179.  
  180. .ISpan {
  181. margin-bottom: 2px !important;
  182. margin-right: 0 !important;
  183. }
  184.  
  185. .pdt15 {
  186. padding-top: 0px !important;
  187. }
  188.  
  189. .answerEnd {
  190. padding: 0 10px !important;
  191. margin-top: 0px !important;
  192. }
  193. .subject-content {
  194. padding: 0px 30px !important;
  195. background: none !important;
  196. }
  197. .answerWrap {
  198. padding: 0px 30px !important;
  199. }
  200.  
  201. .jiexinew {
  202. padding: 5px 30px !important;
  203. }
  204.  
  205. div.analysisAnswer > div.bg-fff.box-shadow.mgt10:nth-child(2) {
  206. padding-bottom: 0 !important;
  207. }
  208.  
  209. .mgb20 {
  210. margin-bottom: 0px !important;
  211. }
  212. .answerList {
  213. padding: 0 15px !important;
  214. }
  215.  
  216. .lh2 {
  217. margin-bottom: 5px !important;
  218. }
  219.  
  220. .countTime {
  221. padding: 0 !important;
  222. }
  223. #ztsetWrap > div.bg-fff.box-shadow {
  224. margin-bottom: 0 !important;
  225. }
  226.  
  227. .mgt10 {
  228. margin-top: 0px !important;
  229. }
  230.  
  231. .swal-footer {
  232. text-align: center !important;
  233. }
  234.  
  235. .lh2 {
  236. font-weight: bolder !important;
  237. color: #337ab7 !important;
  238. font-size: 1.125em !important;
  239. }
  240.  
  241. .lh2 > span {
  242. display: none !important;
  243. }
  244. .shitiText.lh2 {
  245. font-weight: normal !important;
  246. color: #333 !important;
  247. font-size: 14px !important;
  248. }
  249.  
  250. #accountSettingsHeader,
  251. .center.answerCard,
  252. .doPane,
  253. .pull-right > span:not(:first-child),
  254. .answerTitle {
  255. display: none !important;
  256. }
  257.  
  258. #paperTitleWrap {
  259. display: none !important;
  260. }
  261.  
  262. .center {
  263. margin-top: 0px !important;
  264. margin-bottom: 0px !important;
  265. }
  266.  
  267. .modeTitle {
  268. padding-bottom: 0px !important;
  269. }
  270.  
  271. .right-title {
  272. padding: 0 0 !important;
  273. margin-bottom: 0px !important;
  274. }
  275.  
  276. .mgt {
  277. margin-top: 0px !important;
  278. }
  279.  
  280. .subject-content {
  281. background: none !important;
  282. }
  283.  
  284. header {
  285. height: 0px;
  286. }
  287.  
  288. #navigation {
  289. height: 0px !important;
  290. line-height: 2rem !important;
  291. }
  292.  
  293. .spanExplain {
  294. padding: 5px 20px !important;
  295. }
  296.  
  297. .exBtn {
  298. margin-top: 5px !important;
  299. }
  300.  
  301. .answerWrap {
  302. padding: 0px 30px !important;
  303. }
  304.  
  305. .mgb20 {
  306. margin-bottom: 0px !important;
  307. }
  308.  
  309. .singleR {
  310. font-size: 16px;
  311. }
  312. `;
  313.  
  314. setTimeout(() => { main(); }, 1500);
  315.  
  316. function main() {
  317. logInfo(GM_info.script.name, GM_info.script.version);
  318. let url = window.location.href;
  319. // 个人中心添加播放按钮
  320. if ("https://uc.educity.cn/personalCenter/studyCenter.html" == url) {
  321. updatePlayTitle();
  322. } else if (
  323. url.startsWith("https://www.educity.cn/wangxiao2") ||
  324. url.startsWith("http://www.educity.cn/wangxiao2") ||
  325. url.startsWith('https://wangxiao.xisaiwang.com/wangxiao2/')
  326. ) {
  327. // 直播回放调节播放速度
  328. updateSpeed();
  329. } else if (url.startsWith("https://uc.educity.cn/tiku/testReport.html")) {
  330. // 测试报告中,自动填充答案
  331. GM_addStyle(testReportStyle);
  332. autoFillAnswer();
  333. } else if (
  334. url.startsWith("https://uc.educity.cn/tiku/examinationModeCopy.html") ||
  335. url.startsWith("https://uc.educity.cn/tiku/examinationMode.html")
  336. ) {
  337. // 添加键盘监听事件,按键答题
  338. GM_addStyle(examStyle);
  339. addKeyListener();
  340. }
  341. }
  342.  
  343. // 个人中心,学习列表添加播放按钮,修改标题描述
  344. function updatePlayTitle() {
  345. setTimeout(function () {
  346. document.getElementById("loadStuWrap").lastElementChild.click();
  347. setTimeout(function () {
  348. addPlayBotton();
  349. adjustDes();
  350. }, 1000);
  351. }, 1500);
  352. }
  353.  
  354. // 个人中心,学习列表添加播放按钮
  355. function addPlayBotton() {
  356. const urlPrefix = "https://www.educity.cn/courseCenter/zhibo.html?gsver=2&id=";
  357. if (document.getElementsByClassName("enterStudy")) {
  358. let spans = document.getElementsByClassName("enterStudy");
  359. console.log(spans.length);
  360. for (let i = 0; i < spans.length; i++) {
  361. let dataId = spans[i].getAttribute("data-id");
  362. let url = urlPrefix + dataId;
  363. let aEle = document.createElement("a");
  364. aEle.setAttribute("href", url);
  365. aEle.setAttribute("target", "_blank");
  366. aEle.innerHTML = '<i class="icon_index_login_me inline-block icon-st"> </i>';
  367. spans[i].parentElement.append(aEle);
  368. spans[i].style.display = "none";
  369. }
  370. }
  371. }
  372.  
  373. // 将描述移动到标题上
  374. function adjustDes() {
  375. let titleDivs = document.querySelectorAll("div.cMenuTitle.clearfix");
  376. for (let i = 0; i < titleDivs.length; i++) {
  377. let content = "";
  378. let aEle = titleDivs[i].nextElementSibling.querySelector("h4.panel-title>a");
  379. if (aEle) {
  380. content = aEle.innerText;
  381. }
  382. let childEle = document.createElement("div");
  383. childEle.setAttribute("class", "pull-left");
  384. childEle.innerHTML = "<span>" + content + "</span>";
  385. titleDivs[i].append(childEle);
  386. titleDivs[i].nextElementSibling.style.display = "none";
  387. }
  388. }
  389.  
  390. function updateSpeed() {
  391. GM_addStyle(zhiBoStyle);
  392.  
  393. addRemainingTime();
  394. addRateButton();
  395. addRateListener();
  396. updateSideHeight();
  397. }
  398.  
  399.  
  400. /**
  401. * 添加倍速按钮
  402. */
  403. function addRateButton() {
  404. if (!$('.pv-rate-select') || $('.pv-rate-select').length == 0) {
  405. return;
  406. }
  407. $('<div data-rate="4">4x</div><div data-rate="3.5">3.5x</div><div data-rate="3">3x</div><div data-rate="2.5">2.5x</div>').insertBefore($('.pv-rate-select').children().eq(0));
  408. }
  409.  
  410. // 获取当前倍速
  411. function getCurrentRate() {
  412. let rate = 1.0;
  413. let rateEle = document.querySelector('button.pv-rate-btn>span');
  414. if (!rateEle) {
  415. return rate;
  416. }
  417. rate = rateEle.textContent.replace("x", "");
  418.  
  419. return rate;
  420. }
  421.  
  422. /**
  423. * 添加控制播放速度的监听事件,仅用于更新显示当前速度,速度控制通过其他通用三方脚本实现。
  424. */
  425. function addRateListener() {
  426. let rateEle = document.querySelector('button.pv-rate-btn>span');
  427.  
  428. document.onkeyup = function (e) {
  429. var theEvent = e || window.event;
  430. var code = theEvent.keyCode || theEvent.which || theEvent.charCode;
  431. if (code == 88) {
  432. // X,减速
  433. let rate = getCurrentRate();
  434. let newRate = (new Number(rate) - new Number(0.1)).toFixed(1);
  435. rateEle.textContent = newRate + "x";
  436. }
  437. if (code == 67) {
  438. // C,加速
  439. let rate = getCurrentRate();
  440. let newRate = (new Number(rate) + new Number(0.1)).toFixed(1);
  441. rateEle.textContent = newRate + "x";
  442. }
  443. if (code == 90) {
  444. // Z,恢复正常速度
  445. rateEle.textContent = "1x";
  446. }
  447. };
  448. }
  449.  
  450. function updateSideHeight() {
  451. let sideBar = document.querySelector('.vid_midR_tab');
  452. if (!sideBar) {
  453. return;
  454. }
  455. sideBar.style.height = sideBar.parentElement.previousElementSibling.offsetHeight + 'px';
  456. document.querySelector('.vid_midR_wrap').style.height = sideBar.parentElement.previousElementSibling.offsetHeight + 'px';
  457. }
  458.  
  459. // 自动填充答案
  460. function autoFillAnswer() {
  461. setTimeout(function show() {
  462. var aa = document.getElementsByClassName("chak zhank");
  463. var bb = document.getElementsByClassName("ckjx");
  464. const answers = document.getElementsByClassName("answerEnd");
  465. for (let i = 0; i < answers.length; i++) {
  466. var ans = answers[i].children[0].innerText.replace("参考答案:", "").replace(/\s+/g, "");
  467. var your = answers[i].children[1].innerText.replace("你的答案:", "").replace(/\s+/g, "");
  468. if (ans != your) {
  469. aa[i].click();
  470. bb[i].click();
  471. var ansId;
  472. let yourId;
  473. switch (ans) {
  474. case "A":
  475. ansId = 0;
  476. break;
  477. case "B":
  478. ansId = 1;
  479. break;
  480. case "C":
  481. ansId = 2;
  482. break;
  483. case "D":
  484. ansId = 3;
  485. break;
  486. default:
  487. console.warn("error");
  488. break;
  489. }
  490. switch (your) {
  491. case "A":
  492. yourId = 0;
  493. break;
  494. case "B":
  495. yourId = 1;
  496. break;
  497. case "C":
  498. yourId = 2;
  499. break;
  500. case "D":
  501. yourId = 3;
  502. break;
  503. default:
  504. console.warn("Error: There's no your answer.");
  505. break;
  506. }
  507. var ansList =
  508. answers[i].parentElement.previousElementSibling.previousElementSibling.children[0]
  509. .children[1].children;
  510. ansList[ansId].style.fontWeight = "bold";
  511. ansList[ansId].style.color = "#51cb65";
  512. ansList[ansId].children[1].style.fontWeight = "bold";
  513. // ansList[ansId].children[0].children[0].checked = true;
  514. if (yourId != undefined) {
  515. ansList[yourId].style.color = "rgba(128, 128, 145,0.7)";
  516. ansList[yourId].style.textDecoration = "line-through";
  517. }
  518. }
  519. }
  520. }, 6000);
  521. }
  522.  
  523. // 添加键盘监听事件,按键答题
  524. function addKeyListener() {
  525. document.onkeyup = function (e) {
  526. var theEvent = e || window.event;
  527. var code = theEvent.keyCode || theEvent.which || theEvent.charCode;
  528. // Spacebar. 查看答案解析
  529. if (code == 32) {
  530. document.getElementsByClassName("col-md-4 center bottomCenter bp20")[0].click();
  531. }
  532. // Left Arrow.
  533. if (code == 37) {
  534. document.getElementsByClassName("col-md-4 center bp20 bLeftWrap")[0].click();
  535. }
  536. // Right Arrow.
  537. if (code == 39) {
  538. document.getElementsByClassName("col-md-4 center bp20 bRightWrap")[0].click();
  539. }
  540. // A,1.
  541. if (code == 49 || code == 65 || code == 97) {
  542. document.getElementById("slec0A").click();
  543. }
  544. // B,2.
  545. if (code == 50 || code == 66 || code == 98) {
  546. document.getElementById("slec0B").click();
  547. }
  548. // C,3.
  549. if (code == 51 || code == 67 || code == 99) {
  550. document.getElementById("slec0C").click();
  551. }
  552. // D,4.
  553. if (code == 52 || code == 68 || code == 100) {
  554. document.getElementById("slec0D").click();
  555. }
  556. // J. 标记
  557. if (code == 74 && document.getElementsByClassName("bj_icon addBiaoji")[0]) {
  558. document.getElementsByClassName("bj_icon addBiaoji")[0].click();
  559. setTimeout(function () {
  560. if (document.getElementsByClassName("swal-button swal-button--confirm")[0]) {
  561. document.getElementsByClassName("swal-button swal-button--confirm")[0].click();
  562. document.getElementsByClassName("col-md-4 center bp20 bRightWrap")[0].click();
  563. }
  564. }, 300);
  565. }
  566. // P.暂停
  567. if (code == 80 && document.getElementsByClassName("inline-block zanTing")[0]) {
  568. document.getElementsByClassName("inline-block zanTing")[0].click();
  569. }
  570. };
  571. }
  572.  
  573. // ---------------------------------------------------
  574. // 添加剩余时间
  575. function addRemainingTime() {
  576. document.querySelector(".pv-time-current").addEventListener(
  577. "DOMSubtreeModified",
  578. function () {
  579. let remainingTime = getRemainingTime();
  580. let currentEle = document.querySelector('.pv-time-current');
  581. if (currentEle) {
  582. let parent = currentEle.parentElement;
  583. let remainingTimeSpan;
  584. if (document.querySelector('.pv-time-remaining')) {
  585. remainingTimeSpan = document.querySelector('.pv-time-remaining');
  586. } else {
  587. remainingTimeSpan = document.createElement("span");
  588. remainingTimeSpan.setAttribute("class", "pv-time-remaining");
  589. parent.append(remainingTimeSpan);
  590. }
  591. remainingTimeSpan.textContent = remainingTime;
  592. }
  593. },
  594. false
  595. );
  596. }
  597.  
  598. // 获取当前时间
  599. function getNowSeconds() {
  600. let nowSeconds = 0;
  601. let currentEle = document.querySelector('.pv-time-current');
  602. if (!currentEle) {
  603. return nowSeconds;
  604. }
  605.  
  606. let nowTime = currentEle.textContent;
  607. let nowArr = nowTime.split(":");
  608. if (nowArr.length == 2) {
  609. nowSeconds = parseInt(nowArr[0]) * 60 + parseInt(nowArr[1]);
  610. } else if (nowArr.length == 3) {
  611. nowSeconds = parseInt(nowArr[0]) * 60 * 60 + parseInt(nowArr[1]) * 60 + parseInt(nowArr[2]);
  612. }
  613.  
  614. return nowSeconds;
  615. }
  616.  
  617. // 获取总时长
  618. function getAllSeconds() {
  619. let allSeconds = 0;
  620. let durationEle = document.querySelector(".pv-time-duration");
  621. if (!durationEle) {
  622. return allSeconds;
  623. }
  624.  
  625. let allTime = durationEle.textContent;
  626. let allArr = allTime.split(":");
  627. if (allArr.length == 2) {
  628. allSeconds = parseInt(allArr[0]) * 60 + parseInt(allArr[1]);
  629. } else if (allArr.length == 3) {
  630. allSeconds = parseInt(allArr[0] * 60 * 60) + parseInt(allArr[1]) * 60 + parseInt(allArr[2]);
  631. }
  632.  
  633. return allSeconds;
  634. }
  635.  
  636. // 获取剩余时间
  637. function getRemainingTime() {
  638. let allSeconds = getAllSeconds();
  639. let nowSeconds = getNowSeconds();
  640. let seconds = allSeconds - nowSeconds;
  641. let remainingTime = "";
  642. if (seconds >= 0) {
  643. remainingTime = formatSeconds(seconds);
  644. }
  645. return remainingTime;
  646. }
  647.  
  648. // 将秒格式化为时间格式
  649. function formatSeconds(value) {
  650. let result = parseInt(value);
  651. let h =
  652. Math.floor(result / 3600) < 10 ? "0" + Math.floor(result / 3600) : Math.floor(result / 3600);
  653. let m =
  654. Math.floor((result / 60) % 60) < 10
  655. ? "0" + Math.floor((result / 60) % 60)
  656. : Math.floor((result / 60) % 60);
  657. let s = Math.floor(result % 60) < 10 ? "0" + Math.floor(result % 60) : Math.floor(result % 60);
  658.  
  659. let res = "";
  660. if (h !== "00") res += `${h}:`;
  661. if (m !== "00") res += `${m}:`;
  662. res += `${s}`;
  663. return res;
  664. }
  665.  
  666. /**
  667. * Log the title and version at the front of the console.
  668. * @param {String} title title.
  669. * @param {String} version script version.
  670. */
  671. function logInfo(title, version) {
  672. console.clear();
  673. const titleStyle = 'color:white;background-color:#606060';
  674. const versionStyle = 'color:white;background-color:#1475b2';
  675. const logTitle = ' ' + title + ' ';
  676. const logVersion = ' ' + version + ' ';
  677. console.log('%c' + logTitle + '%c' + logVersion, titleStyle, versionStyle);
  678. }
  679. })();