希赛

希赛页面优化

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

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