🌱【免费版】成学课堂|收费版本使用说明:http://doc.zhanyc.cn/course/cxkt/

当前使用的是免费版本,仅包含视频页面自动换课的功能,如需极速秒过、自动换课、答题、考试等高级功能,可通过描述页安装付费版本,一杯咖啡钱,保你无忧学习,且永久使用|接各类脚本开发工作,微信:zhanyc_cn 备用微信:zhanfengkuo 个人网站:http://doc.zhanyc.cn

  1. // ==UserScript==
  2. // @name 🌱【免费版】成学课堂|收费版本使用说明:http://doc.zhanyc.cn/course/cxkt/
  3. // @namespace http://jb.zhanyc.cn/
  4. // @icon https://js.zhanyc.cn/img/js-logo.svg
  5. // @version 1.1
  6. // @description 当前使用的是免费版本,仅包含视频页面自动换课的功能,如需极速秒过、自动换课、答题、考试等高级功能,可通过描述页安装付费版本,一杯咖啡钱,保你无忧学习,且永久使用|接各类脚本开发工作,微信:zhanyc_cn 备用微信:zhanfengkuo 个人网站:http://doc.zhanyc.cn
  7. // @author zfk
  8. // @include *://*.cx-online.net/*
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @grant GM_addStyle
  12. // @grant GM_deleteValue
  13. // @grant GM_setClipboard
  14. // @grant GM_registerMenuCommand
  15. // @grant GM_getResourceURL
  16. // @grant GM_addValueChangeListener
  17. // @grant GM_removeValueChangeListener
  18. // @grant GM_getResourceText
  19. // @grant window.close
  20. // @run-at document-body
  21. // @require http://libs.baidu.com/jquery/2.0.0/jquery.min.js
  22. // @require https://update.gf.qytechs.cn/scripts/502187/1419386/base_lib.js
  23. // @require https://gf.qytechs.cn/scripts/434540-layerjs-gm-with-css/code/layerjs-gm-with-css.js?version=1065982
  24. // @antifeature
  25. // @license GPL
  26. // ==/UserScript==
  27. (function () {
  28. // @run-at document-start
  29. let $jq = $;
  30. unsafeWindow.$jq = $;
  31. unsafeWindow.layer = layer;
  32. let baseConfig = {}
  33.  
  34. let freeTips = "当前使用的是免费版本,仅包含视频页面自动换课的功能,如需极速秒过、自动换课、答题、考试等高级功能,可点击下方按钮查看付费版本"
  35. let docUrl = "http://doc.zhanyc.cn/pages/cxkt/";
  36. let plugMain = Object.assign(baseConfig, {
  37. config: {
  38. maxComment: 100,
  39. },
  40. pageData: {
  41. nextIndex: -1,// 视频页面标记当前是那个视频
  42. userNameIndex: null,
  43. loadTaskProgress: false, // 答题任务进度是否已经加载完成
  44. mgVideoRun: false,
  45. mgVideoIndex: 0,
  46. videoPageData: null, // 视频页面数据
  47. isRunWork: false,// 是否在跑作业(视频完成了)
  48. confirmRunIndex: null,
  49. videoList: null,//存放课程目录
  50. videoFinishList: null,// 存放课程完成情况
  51. lastMgVideoId: null,// 上一次秒过视频的ID
  52. mgVideoCheckIndex: null,// 上次秒过视频检测的timeoutIndex
  53. waitTime: 0,
  54. lastRunTime: -1,
  55. qaArr: [],
  56. index: {
  57. refreshIndex: null,
  58. list: null,
  59. },
  60. video: {
  61. index: null,
  62. },
  63. },
  64. async init() {
  65. console.log("%c pg init", "background:rgb(0,0,0);color:#fff");
  66. var lockResolver;
  67. if (navigator && navigator.locks && navigator.locks.request) {
  68. const promise = new Promise((res) => {
  69. lockResolver = res;
  70. });
  71.  
  72. navigator.locks.request("unique_lock_name", { mode: "shared" }, () => {
  73. return promise;
  74. });
  75. }
  76. plugMain.addStyle();
  77. unsafeWindow.alert = function (msg) {
  78. layer.alert(msg);
  79. };
  80. let run = true;
  81. if (run) plugMain.firstRun();
  82. },
  83. async runByUrl(url) {
  84. if (url.toLocaleLowerCase().includes("/layout/roomdetail")) {
  85. plugMain.page_video();
  86. } else if (url.includes("/Layout/classStudy") || url.includes('/Layout/home')) {
  87. plugMain.showPaidContent(`免费版本不包含自动换课、换学年功能,如需使用请安装收费版本`);
  88. } else if (url.includes("/Layout/examList")) {
  89. plugMain.showPaidContent(`免费版本不包含考试功能,如需使用请安装收费版本`);
  90. } else if (url.includes("/homeWork?")) {
  91. plugMain.showPaidContent(`免费版本不包含作业答题功能,如需使用请安装收费版本`);
  92. }
  93. },
  94.  
  95. async page_video_work() {
  96. console.log("%c page_video_work", "background:rgb(0,0,0);color:#fff");
  97. plugMain.pageData.lastRunTime = plugMain.now();
  98. let config = plugMain.getConfig();
  99. if (config.czms == "2") return;
  100. await plugMain.gmAuthDownScore("9099284436654264bb5f1ac99baeb3c1");
  101. plugMain.tipsMsg("等待脚本执行")
  102. await plugMain.waitOf(a => plugMain.pageData.loadTaskProgress)
  103. await plugMain.waitTimeout(1000)
  104. let $el = null;
  105. let userData = await plugMain.getUserData()
  106. let courseId = plugMain.parseQueryString().courseId
  107. $(".chapter-item .fa-book").each((i, el) => {
  108. let $parent = $(el).parents(".chapter-item:first")
  109. if ($parent.find(".pass").length == 0) {
  110. let has = userData.skipWordArr.find(a => a.courseId == courseId)
  111. if (has) {
  112. let title = $parent.text().trim()
  113. if (has.skipList.includes(title)) {
  114. plugMain.tipsMsg(`跳过作业:${title}`)
  115. return true
  116. }
  117. }
  118. $el = $(el).parents(".chapter-item:first");
  119. return false;
  120. }
  121. });
  122.  
  123. if ($el == null) {
  124. await plugMain.waitOf(a => plugMain.pageData.mgVideoRun == false, 1000, -1)
  125. isDev && console.log('等待秒过视频完成');
  126. plugMain.confirmRun("当前课程已经完成, 准备返回列表页面").then((a) => {
  127. plugMain.getElByText($(".el-menu-item"), "我的课程").click();
  128. });
  129. return;
  130. }
  131. $el.click();
  132. },
  133. async page_video(callback = false) {
  134. console.log("%c page_video", "background:rgb(0,0,0);color:#fff");
  135. plugMain.pageData.isRunWork = false
  136. plugMain.pageData.lastRunTime = plugMain.now();
  137.  
  138. clearInterval(plugMain.pageData.index.refreshIndex);
  139. // 5分钟没运行则刷新页面
  140. plugMain.pageData.index.refreshIndex = setTimeout(() => {
  141. if (plugMain.now() - plugMain.pageData.lastRunTime > 5 * 60 * 1000)
  142. location.reload();
  143. }, 5 * 60 * 1000);
  144. if (!callback) {
  145. await plugMain.waitOf((a) => $(".fa-volume-up").length > 0);
  146. await plugMain.waitTimeout(2000);
  147. }
  148. await plugMain.waitOf(a => plugMain.pageData.videoList.length != null)
  149.  
  150. let $el = null;
  151. $(".fa-volume-up").each((i, el) => {
  152. if ($(el).parents(".list-item:first").find(".finish").length == 0 && plugMain.pageData.nextIndex < i) {
  153. $el = $(el).parents(".chapter-item:first");
  154. plugMain.pageData.nextIndex = i
  155. return false;
  156. }
  157. });
  158. if ($el == null) {
  159. plugMain.page_video_work();
  160. plugMain.pageData.isRunWork = true
  161. return;
  162. }
  163. $el.click();
  164. let timeout = 2;
  165. plugMain.setGMData("closeLJTS", plugMain.now());
  166. if (plugMain.pageData.video.index != null) {
  167. return;
  168. }
  169.  
  170. if (mg != "1") {
  171. layer.msg(
  172. "脚本支持视频秒过,如需秒过请在右上角油猴脚本的【脚本菜单】中设置秒过后刷新页面生效"
  173. );
  174. } else {
  175. return
  176. }
  177. plugMain.pageData.video.index = setInterval(async () => {
  178. try {
  179. if (plugMain.pageData.waitTime > 0) {
  180. plugMain.pageData.waitTime -= timeout;
  181. return;
  182. }
  183. if (!location.href.toLocaleLowerCase().includes("/layout/roomdetail")) {
  184. return;
  185. }
  186. let title = `进度:${plugMain.getCurTime().toFixed(0)}/${zfk
  187. .getTotalTime()
  188. .toFixed(0)}`;
  189. $("title").text(title);
  190. console.log("%c video run", "background:rgb(255,0,0);color:#fff");
  191. plugMain.pageData.lastRunTime = plugMain.now();
  192. let isFinish = await plugMain.isPlayFinish();
  193.  
  194. if (isFinish) {
  195. layer.msg("视频即将结束,等待下一步操作", { time: 10 * 1000 });
  196. plugMain.pageData.waitTime = plugMain.getTotalTime() - plugMain.getCurTime() + 1;
  197. plugMain.nextVideo();
  198. return;
  199. }
  200. let isPlay = await plugMain.videoIsPlay();
  201. if (!isPlay) {
  202. if (!isFinish) {
  203. plugMain.play();
  204. }
  205. }
  206. } catch (e) {
  207. console.error("视频页面定时器出错", e);
  208. }
  209. }, timeout * 1000);
  210. },
  211. nextVideo() {
  212. plugMain.page_video(true);
  213. },
  214. async page_video_work() {
  215. console.log("%c page_video_work", "background:rgb(0,0,0);color:#fff");
  216. plugMain.showPaidContent(`免费版本不包含答题功能,如需使用请安装收费版本`);
  217. },
  218. checkVideoPlay() {
  219. let lastTime = plugMain.getCurTime();
  220. return new Promise((resolve) => {
  221. setTimeout(() => {
  222. if (plugMain.getTotalTime() > 0 && plugMain.getCurTime() == lastTime) {
  223. plugMain.play();
  224. }
  225. lastTime = plugMain.getCurTime();
  226. resolve();
  227. }, 3000);
  228. });
  229. },
  230. listenerVideo() {
  231. console.log("%c listenerVideo", "background:rgb(255,0,0);color:#fff");
  232. let index = setInterval(() => {
  233. // 重播按钮(视频放完了,但是进度还没完)
  234. if ($(".xgplayer-replay:visible").length > 0) {
  235. document.querySelector("video").play();
  236. return;
  237. }
  238. if ($(".dialog-content") == "学时记录出现异常请检查网络") {
  239. location.reload();
  240. return;
  241. }
  242. }, 5000);
  243. },
  244. async page_viewerforccvideo() {
  245. console.log(
  246. "%c page_viewerforccvideo",
  247. "background:rgb(255,0,0);color:#fff"
  248. );
  249. plugMain.setGMData("closeLJTS", plugMain.now());
  250. plugMain.showPaidContent("当前是免费版本,收费版本可实现全自动看课换课,无人值守,更有5倍记录学时版本等你付费升级")
  251. plugMain.checkVideoPlay().then((a) => {
  252. plugMain.checkVideoPlay();
  253. });
  254.  
  255. plugMain.listenerVideo();
  256. setInterval(() => {
  257. let cIndex = $("li.cvtb-MCK-course-content").index(
  258. $("li.cvtb-MCK-course-content.current")
  259. );
  260. let progress = $("li.cvtb-MCK-course-content.current")
  261. .find(".cvtb-MCK-CsCt-studyProgress")
  262. .text()
  263. .trim();
  264. let key = cIndex + "_" + progress;
  265. if (plugMain.pageData.video.lastKey == key) {
  266. // layer.alert("貌似卡住了,刷新页面");
  267. plugMain.confirmRun("貌似卡住了,5秒后刷新页面").then((a) => {
  268. location.href = location.href;
  269. });
  270. }
  271. plugMain.pageData.video.lastKey = key;
  272. // }, 10 * 1000);
  273. }, 2 * 60 * 1000);
  274.  
  275. plugMain.checkVideoPlay().then((a) => {
  276. plugMain.checkVideoPlay();
  277. });
  278.  
  279. plugMain.listenerVideo();
  280.  
  281. setInterval(() => {
  282. if ($("#rest_tip").length > 0) {
  283. $("#rest_tip").find("button").click();
  284. }
  285. if ($(".xgplayer-volume-large").length > 0) {
  286. $(".xgplayer-volume .xgplayer-icon").click();
  287. }
  288. }, 1000);
  289.  
  290. unsafeWindow.window.on_spark_player_pause = function () {
  291. console.log(">>>ZFK on_spark_player_pause");
  292. // zfk
  293. // clearInterval(r)
  294. };
  295. unsafeWindow.on_spark_player_resume = function () {
  296. console.log(">>>ZFK on_spark_player_resume");
  297. // zfk
  298. // i()
  299. };
  300. },
  301. page_top() {
  302. GM_addValueChangeListener('openLjts', function (name, old_value, new_value, remote) {
  303. plugMain.openLjTips()
  304. })
  305. },
  306. firstRun() {
  307. if (top === window && plugMain.getGMData("showDoc", true)) {
  308. layer.confirm(
  309. freeTips,
  310. { icon: 3, title: "首次使用?", btn: ["查看付费版本", "继续使用免费版本"] },
  311. function (index) {
  312. plugMain.openDoc();
  313. layer.close(index);
  314. plugMain.setGMData("showDoc", false);
  315. plugMain.begin("");
  316. },
  317. function () {
  318. plugMain.setGMData("showDoc", false);
  319. plugMain.begin("");
  320. }
  321. );
  322. } else {
  323. }
  324. plugMain.begin("");
  325. },
  326. async begin(key) {
  327. if (window === top) {
  328. plugMain.registerMenuCommand();
  329. }
  330. let lastUrl = location.href;
  331.  
  332. setInterval(async () => {
  333. if (lastUrl != location.href) {
  334. lastUrl = location.href;
  335. plugMain.runByUrl(location.href);
  336. }
  337. }, 500);
  338. plugMain.runByUrl(location.href);
  339. },
  340.  
  341. setSkip(event, courseId, skip) {
  342. event.stopPropagation()
  343. $(".skipContainer").remove();
  344. var sikpList = plugMain.getGMData("skipList", []);
  345. if (skip) {
  346. sikpList.push(courseId);
  347. plugMain.setGMData("skipList", sikpList);
  348. } else {
  349. plugMain.setGMData(
  350. "skipList",
  351. sikpList.filter((a) => a != courseId)
  352. );
  353. }
  354. layer.msg("操作成功");
  355. plugMain.setSkipBtn();
  356. },
  357. setSkipBtn() {
  358. var sikpList = plugMain.getGMData("skipList", []);
  359. $(".zfk-skipContainer").remove()
  360. $("#currentCourseDiv .course").each((i, el) => {
  361. let courseId = $(el).attr("courseid");
  362. let $btnContainer = $(el)
  363. if (sikpList.includes(courseId)) {
  364. $btnContainer.after(
  365. `<div class="text-center zfk-skipContainer"><button type="button" class="zfk-btn info" onclick="plugMain.setSkip(event,'${courseId}',false)">脚本:取消跳过</button></div>`
  366. );
  367. } else {
  368. $btnContainer.after(
  369. `<div class="text-center zfk-skipContainer"><button type="button" class="zfk-btn danger" onclick="plugMain.setSkip(event,'${courseId}',true)">脚本:跳过课程</button></div>`
  370. );
  371. }
  372. });
  373. },
  374.  
  375. async showPaidContent(msg = "此页面为付费内容,免费脚本不包含", withPostfix = true) {
  376. if (withPostfix) {
  377. msg += "<span style='font-weight:bold;'>*重要:一个学员付费一次,永久使用,永久更新!</span>"
  378. }
  379. if (!plugMain.pageData.paidIndexArr) {
  380. plugMain.pageData.paidIndexArr = []
  381. }
  382. if (plugMain.pageData.paidIndexArr.length > 0) {
  383. for (let i = 0; i < plugMain.pageData.paidIndexArr.length; i++) {
  384. const index = plugMain.pageData.paidIndexArr[i];
  385. layer.close(index)
  386. }
  387. }
  388. let index = layer.open(
  389. {
  390. type: "1",
  391. content: `<div style="padding:14px;">${msg}</div>`,
  392. title: "免费版本提示",
  393. offset: "rb",
  394. area: ["500px"],
  395. btn: ["查看收费版本", "关闭"],
  396. shade: 0,
  397. yes: function (index) { plugMain.openDoc() }
  398. })
  399. plugMain.pageData.paidIndexArr.push(index)
  400. },
  401. localSaveQa(qaArr) {
  402. let list = plugMain.getGMData("qaList", []);
  403. qaArr.forEach((item) => {
  404. let old = list.find((a) => a.key == item.key);
  405. item.value = item.value.replace(/#split#/g, "|");
  406. if (!old) {
  407. list.push(item);
  408. } else {
  409. old.value = item.value;
  410. }
  411. });
  412. plugMain.setGMData("qaList", list);
  413. },
  414. play() {
  415. plugMain.getVideo().volume = 0;
  416. setTimeout(() => {
  417. plugMain.getVideo().play();
  418. }, 200);
  419. // });
  420. },
  421. setVideoVolume() {
  422. try {
  423. if (plugMain.getVideo().volume != 0) {
  424. plugMain.getVideo().volume = 0;
  425. }
  426. } catch (e) {
  427. console.error(e);
  428. }
  429. },
  430. isPlayFinish() {
  431. try {
  432. return (
  433. plugMain.getTotalTime() > 0 && plugMain.getCurTime() + 5 >= plugMain.getTotalTime()
  434. );
  435. } catch (e) {
  436. return false;
  437. }
  438. },
  439. getVideo() {
  440. return $("video")[0];
  441. },
  442. getCurTime() {
  443. let res = 0;
  444. try {
  445. res = $("video")[0].currentTime;
  446. } catch (e) {
  447. console.error(e);
  448. }
  449. return res;
  450. },
  451. getTotalTime() {
  452. let res = 0;
  453. try {
  454. res = $("video")[0].duration;
  455. } catch (e) {
  456. console.error(e);
  457. }
  458. return res;
  459. },
  460. // 题库方法
  461. formatAnswerOption(option) {
  462. // 检查输入是否是单个字母且在 A-Z 范围内
  463. if (/^[a-zA-Z]$/.test(option)) {
  464. option = option.toUpperCase();
  465. return option.charCodeAt(0) - 'A'.charCodeAt(0);
  466. } else {
  467. let arr = [
  468. ["正确", "错误"],
  469. ["对", "错"],
  470. ];
  471. let opt = option.toUpperCase();
  472. let res = -1;
  473. arr.forEach((subArr) => {
  474. if (subArr.includes(opt)) {
  475. res = subArr.indexOf(opt);
  476. return false;
  477. }
  478. });
  479. return res;
  480. }
  481. },
  482.  
  483. // 题库方法
  484. formatAnswerOptionNo(index) {
  485. return ["A", "B", "C", "D", "E", "F", "G", "H"][index]
  486. },
  487. isMatchQAText(txt1, txt2) {
  488. return (
  489. txt1 == txt2 ||
  490. plugMain.simpleHtml(txt1) == plugMain.simpleHtml(txt2) ||
  491. plugMain.simpleText(txt1) == plugMain.simpleText(txt2)
  492. );
  493. },
  494. simpleHtml(html) {
  495. html = html.replace(/&nbsp;|<br\/>|<br>|\n|\r/gi, "");
  496. html = html.trim();
  497. if (!html) return html;
  498. if (html.startsWith("<") && html.endsWith(">")) {
  499. return $(html).text().trim();
  500. }
  501. return html.trim();
  502. },
  503. simpleText(text) {
  504. return text
  505. .replace(/[^\u4e00-\u9fa5a-zA-Z0-9#split#√×]/g, "")
  506. .replace(/[的]/g, "");
  507. },
  508. async videoIsPlay() {
  509. return new Promise((resolve) => {
  510. try {
  511. let curTime = $("video")[0].currentTime;
  512. setTimeout(() => {
  513. let time1 = $("video")[0].currentTime;
  514. let res = time1 > curTime;
  515. if (res) {
  516. setTimeout(() => {
  517. let time2 = $("video")[0].currentTime;
  518. let res2 = time2 > time1;
  519. resolve(res2);
  520. }, 100);
  521. } else {
  522. return resolve(false);
  523. }
  524. }, 100);
  525. } catch (e) {
  526. resolve(false);
  527. }
  528. });
  529. },
  530. beginMan() {
  531. console.log("%c beginMan", "background:rgb(0,0,0);color:#fff");
  532. },
  533. stop() {
  534. location.href = location.href;
  535. },
  536.  
  537. openDoc() {
  538. if (docUrl) {
  539. window.open(docUrl);
  540. } else {
  541. window.open("http://doc.zhanyc.cn/pages/auth/");
  542. }
  543. },
  544. isDZKFMode() {
  545. let res = typeof (loadFun) == 'function' && loadFun.toString().includes('var data = res.response;')
  546. if (!res)
  547. res = typeof isDZKF == "boolean" && !!isDZKF;
  548. return res
  549. },
  550. registerMenuCommand() {
  551. GM_registerMenuCommand("当前是免费版", plugMain.openDoc);
  552. GM_registerMenuCommand("点此安装付费版本", plugMain.openDoc);
  553. GM_registerMenuCommand("联系脚本客服", plugMain.linkAuthor);
  554. },
  555. linkAuthor() {
  556. window.open("http://doc.zhanyc.cn/contact-me/");
  557. },
  558. setClip(txt) {
  559. GM_setClipboard(txt, "text");
  560. layer.msg("复制成功");
  561. },
  562. addStyle() {
  563. GM_addStyle(`
  564. .zfk-btn{background-color:#0fbcf9;color:white;padding:4px 12px;border:none;box-sizing:content-box;font-size:14px;height:20px;border-radius:4px;cursor:pointer;display:inline-block;border:1px solid transparent;white-space:nowrap;user-select:none;text-align:center;vertical-align:middle}.zfk-btn:hover{opacity:.8}.zfk-btn.success{background-color:#38b03f}.zfk-btn.warning{background-color:#f1a325}.zfk-btn.info{background-color:#03b8cf}.zfk-btn.danger{background-color:#ea644a}.zfk-form-tips{font-size:1.2em;color:red}.tips{color:red}.zfk-form textarea,.zfk-form input[type=text],.zfk-form input[type=number],.zfk-form input[type=password]{border:1px solid #888;border-radius:4px;padding:5px;box-sizing:border-box}.zfk-form textarea{width:100%}.zfk-form-item{margin-bottom:10px}.zfk-form-item>label:first-child{width:7em;text-align:right;display:inline-block;padding-right:5px;margin-right:0}.zfk-form-item label{margin-right:4px}.zfk-form-item.block>label:first-child{text-align:left;display:block;width:100%;font-weight:bold}.text-l{text-align:left !important}.text-c{text-align:center !important}.text-r{text-align:right !important}.p-0{padding:0px !important}.p-5{padding:5px !important}.p-10{padding:10px !important}.p-15{padding:15px !important}.p-20{padding:20px !important}.p-t-0{padding-top:0px !important}.p-t-5{padding-top:5px !important}.p-t-10{padding-top:10px !important}.p-t-15{padding-top:15px !important}.p-t-20{padding-top:20px !important}.p-b-0{padding-bottom:0px !important}.p-b-5{padding-bottom:5px !important}.p-b-10{padding-bottom:10px !important}.p-b-15{padding-bottom:15px !important}.p-b-20{padding-bottom:20px !important}.p-l-0{padding-left:0px !important}.p-l-5{padding-left:5px !important}.p-l-10{padding-left:10px !important}.p-l-15{padding-left:15px !important}.p-l-20{padding-left:20px !important}.p-r-0{padding-right:0px !important}.p-r-5{padding-right:5px !important}.p-r-10{padding-right:10px !important}.p-r-15{padding-right:15px !important}.p-r-20{padding-right:20px !important}.p-0{padding:0px !important}.p-5{padding:5px !important}.p-10{padding:10px !important}.p-15{padding:15px !important}.p-20{padding:20px !important}.m-t-0{margin-top:0px !important}.m-t-5{margin-top:5px !important}.m-t-10{margin-top:10px !important}.m-t-15{margin-top:15px !important}.m-t-20{margin-top:20px !important}.m-b-0{margin-bottom:0px !important}.m-b-5{margin-bottom:5px !important}.m-b-10{margin-bottom:10px !important}.m-b-15{margin-bottom:15px !important}.m-b-20{margin-bottom:20px !important}.m-l-0{margin-left:0px !important}.m-l-5{margin-left:5px !important}.m-l-10{margin-left:10px !important}.m-l-15{margin-left:15px !important}.m-l-20{margin-left:20px !important}.m-r-0{margin-right:0px !important}.m-r-5{margin-right:5px !important}.m-r-10{margin-right:10px !important}.m-r-15{margin-right:15px !important}.m-r-20{margin-right:20px !important}.bold{font-weight:bold !important}.tips-box{padding:10px;border:1px solid red;background-color:#fff0f0;color:red}.bold{font-weight:bold}.font-l{font-size:1.2em}.font-xl{font-size:40px}.font-l{font-size:25px}.color-default{color:#ea644a !important}.color-success{color:#38b03f !important}.color-warning{color:#f1a325 !important}.color-danger{color:#ea644a !important}.bg-default{background-color:#ea644a !important}.bg-success{background-color:#38b03f !important}.bg-warning{background-color:#f1a325 !important}.bg-danger{background-color:#ea644a !important}.zfk-table{border-collapse:collapse}.zfk-table thead{background-color:#1abc9c}.zfk-table td,.zfk-table th{text-align:center;padding:6px;border:1px solid #888}.zfk-table tr:nth-child(2n){background-color:#f2f2f2}.zfk-table tr:hover{background-color:#fff799}.zfk-container *{font-size:17px}
  565. `);
  566. }, // plugMain.setGMData("closeLJTS", plugMain.now());
  567. openLjTips(tipsAndClose = true, checkUrlBeforeClose = false) {
  568. let index = layer.open({
  569. type: 1,
  570. title: "请确认",
  571. offset: "100px",
  572. content: `
  573. <div style="padding:10px">
  574. <p>已经为你打开下一门课程,如果没有打开窗口,请检查浏览器地址栏右侧是否有拦截提示,请选择【永久允许】或者在浏览器设置中设置本网站【弹出式窗口和重定向】设置为允许</p>
  575. <p style="color:red;">如下图所示:</p>
  576. <img src="https://js.zhanyc.cn/img/ljts.jpg"/>
  577. </div>
  578. `,
  579. });
  580. if (!plugMain.pageData.ljtsIndexArr) {
  581. plugMain.pageData.ljtsIndexArr = []
  582. }
  583. plugMain.pageData.ljtsIndexArr.push(index)
  584. let url = checkUrlBeforeClose ? location.href : "";
  585. if (plugMain.pageData.closeTipsIndex != null) return;
  586. plugMain.pageData.closeTipsIndex = GM_addValueChangeListener(
  587. "closeLJTS",
  588. function (name, old_value, new_value, remote) {
  589. plugMain.pageData.ljtsIndexArr.forEach(item => {
  590. layer.close(item);
  591. })
  592. plugMain.pageData.ljtsIndexArr = []
  593. tipsAndClose && plugMain.tipsAndClose && plugMain.tipsAndClose(url);
  594. }
  595. );
  596. },
  597. tipsAndClose(checkUrl, timeout = 5000) {
  598. let mark = plugMain.now()
  599. plugMain.pageData.tipsAndCloseMark = mark
  600. plugMain.confirmRun("准备关闭当前页面,如果不想关闭请点击下面【取消执行】按钮", timeout).then((a) => {
  601. if (plugMain.pageData.tipsAndCloseMark != mark) {
  602. isDev && console.log("页面标识变更,取消关闭窗口");
  603. return
  604. }
  605. if (!checkUrl || location.href == checkUrl) window.close();
  606. });
  607. },
  608. closeWaitConfrimWin() {
  609. plugMain.setGMData("closeLJTS", plugMain.now());
  610. },
  611. removeArrEmpty(arr) {
  612. let res = [];
  613. arr.forEach((item) => {
  614. if (!!item && item.trim() != "") {
  615. res.push(item);
  616. }
  617. });
  618. return res;
  619. },
  620. confirmRun(msg = "脚本:3秒后执行下一步操作", time = 3000) {
  621. return new Promise((resolve, reject) => {
  622. let isRun = true;
  623. // clearTimeout(plugMain.pageData.confirmRunIndex);
  624. let confirmRunIndex =
  625. layer.open({
  626. type: '1',
  627. title: '脚本:是否继续执行?',
  628. closeBtn: 0,
  629. zIndex: plugMain.pageData.confirmRunZIndex++,
  630. btn: '取消执行',
  631. offset: "100px",
  632. content: `<div style="padding:20px;">${msg}</div>`,
  633. yes: function (index) {
  634. isRun = false;
  635. reject();
  636. layer.close(confirmRunIndex);
  637. }
  638. });
  639.  
  640. // layer.alert(
  641. // msg,
  642. // { icon: 3, title: "是否继续?", btn: ["取消执行"], offset: "100px" },
  643. // function (index) {
  644. // isRun = false;
  645. // reject();
  646. // layer.close(plugMain.pageData.confirmRunIndex);
  647. // }
  648. // );
  649. setTimeout(() => {
  650. layer.close(confirmRunIndex);
  651. resolve(true);
  652. }, time);
  653. });
  654. },
  655. waitTimeout(timeout) {
  656. return new Promise((resolve, reject) => {
  657. setTimeout(() => {
  658. resolve();
  659. }, timeout);
  660. });
  661. },
  662. waitOf(fun, interval = 1000, timeout = 30) {
  663. console.log("%c waitOf", "background:rgb(0,0,0);color:#fff", fun);
  664. return new Promise((resolve, reject) => {
  665. let _timeOut = timeout * 1000;
  666. try {
  667. if (fun()) {
  668. return resolve();
  669. }
  670. } catch (e) {
  671. console.error(e);
  672. }
  673. let index = setInterval(() => {
  674. try {
  675. if (timeout != -1) {
  676. _timeOut -= interval;
  677. if (_timeOut < 0) {
  678. clearInterval(index);
  679. return reject();
  680. }
  681. }
  682. if (fun()) {
  683. clearInterval(index);
  684. return resolve();
  685. }
  686. } catch (e) {
  687. console.error(e);
  688. }
  689. }, interval);
  690. });
  691. },
  692. getUrlParam(url, name) {
  693. if (arguments.length == 1) {
  694. name = url;
  695. url = window.location;
  696. }
  697. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
  698. var r = url.search.substr(1).match(reg);
  699. if (r != null) return unescape(r[2]);
  700. return "";
  701. },
  702. objectToQueryString(obj) {
  703. var queryParams = [];
  704. for (var key in obj) {
  705. if (obj.hasOwnProperty(key)) {
  706. var value = obj[key];
  707. // 如果值为数组,则将其转换为多个参数
  708. if (Array.isArray(value)) {
  709. for (var i = 0; i < value.length; i++) {
  710. queryParams.push(
  711. encodeURIComponent(key) + "=" + encodeURIComponent(value[i])
  712. );
  713. }
  714. } else {
  715. queryParams.push(
  716. encodeURIComponent(key) + "=" + encodeURIComponent(value)
  717. );
  718. }
  719. }
  720. }
  721. return queryParams.join("&");
  722. },
  723. parseQueryString(url = window.location.href) {
  724. //url参数转对象
  725. url = !url ? window.location.href : url;
  726. if (url.indexOf("?") === -1) {
  727. return {};
  728. }
  729. let search =
  730. url[0] === "?"
  731. ? url.substr(1)
  732. : url.substring(url.lastIndexOf("?") + 1);
  733. if (search === "") {
  734. return {};
  735. }
  736. search = search.split("&");
  737. let query = {};
  738. for (let i = 0; i < search.length; i++) {
  739. let pair = search[i].split("=");
  740. query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
  741. }
  742. return query;
  743. },
  744. getAttrName(el, key) {
  745. if (el.jquery) el = el.get(0);
  746. let propName = Object.keys(el).find((a) => a.startsWith(key));
  747. return propName;
  748. },
  749. getAttrNameList(el, key) {
  750. if (el.jquery) el = el.get(0);
  751. let propName = Object.keys(el).filter((a) => a.startsWith(key));
  752. return propName;
  753. },
  754. alertMsg(msg, timeout = 0) {
  755. layer.open(
  756. {
  757. type: "1",
  758. content: `<div style="padding:14px;">${msg}</div>`,
  759. title: "脚本提示" + (timeout == 0 ? '' : `(${(timeout / 1000).toFixed(2)}秒后自动关闭})`),
  760. offset: "100px",
  761. time: timeout,
  762. btn: "关闭"
  763. })
  764. },
  765. tipsMsg(msg, timeout = 3000) {
  766. layer.msg(msg, { offset: "100px", time: timeout });
  767. },
  768. confirmMsg(msg = "请确认", option = {}) {
  769. let defConfig = {
  770. title: "脚本提示", btn: ["确定", "关闭"],
  771. offset: "100px",
  772. area: ["500px"],
  773. shade: 0.3,
  774. fun1(index) { layer.close(index) },
  775. fun2() { },
  776. fun3() { }
  777. }
  778. Object.assign(defConfig, option)
  779. layer.open(
  780. {
  781. type: "1",
  782. content: `<div style="padding:14px;">${msg}</div>`,
  783. title: option.title,
  784. offset: defConfig.offset,
  785. area: defConfig.area,
  786. btn: defConfig.btn,
  787. shade: defConfig.shade,
  788. yes: defConfig.fun1,
  789. btn2: defConfig.fun2,
  790. btn3: defConfig.fun3
  791. })
  792. },
  793. matchUrl(urlKeyword, mode = "like", url = location.href) {
  794. let res = false;
  795. switch (mode) {
  796. case "eq":
  797. res = urlKeyword == url;
  798. break;
  799. case "like":
  800. res = url.indexOf(urlKeyword) != -1;
  801. break;
  802. case "left":
  803. res = url.startsWith(urlKeyword);
  804. break;
  805. case "right":
  806. res = url.endsWith(urlKeyword);
  807. break;
  808. }
  809. return res;
  810. },
  811. getPromiseWithAbort(p) {
  812. let obj = {};
  813. let p1 = new Promise(function (resolve, reject) {
  814. obj.abort = reject;
  815. });
  816. obj.promise = Promise.race([p, p1]);
  817. return obj;
  818. },
  819. page_yhwelcome() {
  820. console.log("%c page_yhwelcome", "background:rgb(255,0,0);color:#fff");
  821. var token = sessionStorage.getItem("token");
  822. this.setGMData("token", token);
  823. this.setGMData("login", { login: true, time: plugMain.now() });
  824. },
  825. createWorker(f) {
  826. var blob = new Blob(["(" + f + ")()"]);
  827. var url = window.URL.createObjectURL(blob);
  828. var worker = new Worker(url);
  829. return worker;
  830. },
  831. createIntervalWorker(callback, time) {
  832. var pollingWorker = plugMain.createWorker(`async function (e) {
  833. setInterval(async function () {
  834. this.postMessage(null)
  835. }, ${time})
  836. }`);
  837. pollingWorker.onmessage = callback;
  838. return pollingWorker;
  839. },
  840. createTimeoutWorker(callback, time) {
  841. var pollingWorker = plugMain.createWorker(`async function (e) {
  842. setTimeout(async function () {
  843. this.postMessage(null)
  844. }, ${time})
  845. }`);
  846. pollingWorker.onmessage = function () {
  847. callback();
  848. plugMain.stopWorker(pollingWorker);
  849. };
  850. return pollingWorker;
  851. },
  852. stopWorker(vm) {
  853. try {
  854. vm && vm.terminate();
  855. } catch (err) {
  856. console.log(err);
  857. }
  858. },
  859. getGMData(item, def) {
  860. return GM_getValue(item, def);
  861. },
  862. setGMData(item, val) {
  863. return GM_setValue(item, val);
  864. },
  865. delGMData(item, val) {
  866. return GM_deleteValue(item);
  867. },
  868. generateRandomString(length) {
  869. const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  870. let randomString = "";
  871.  
  872. for (let i = 0; i < length; i++) {
  873. const randomIndex = Math.floor(Math.random() * charset.length);
  874. randomString += charset.charAt(randomIndex);
  875. }
  876.  
  877. return randomString;
  878. },
  879. timeSecondsFormat(seconds) {
  880. // 确保秒数为非负整数
  881. seconds = Math.floor(Math.abs(seconds));
  882.  
  883. // 计算小时、分钟和秒
  884. var hours = Math.floor(seconds / 3600);
  885. var minutes = Math.floor((seconds % 3600) / 60);
  886. var secs = seconds % 60;
  887.  
  888. // 如果小时、分钟或秒小于10,则在其前面添加一个0
  889. hours = (hours < 10) ? "0" + hours : hours;
  890. minutes = (minutes < 10) ? "0" + minutes : minutes;
  891. secs = (secs < 10) ? "0" + secs : secs;
  892.  
  893. // 返回格式化的时间字符串
  894. return hours + ":" + minutes + ":" + secs;
  895. },
  896. // 时间转换成秒
  897. timeStringToSeconds(timeString) {
  898. if (!timeString.includes("时")) {
  899. timeString = '0时' + timeString
  900. }
  901. timeString = timeString
  902. .replace("小时", ":")
  903. .replace("时", ":")
  904. .replace("分钟", ":")
  905. .replace("分", ":")
  906. .replace("秒", "");
  907. if (timeString.endsWith(":")) {
  908. timeString = timeString.substring(0, timeString.length - 1);
  909. }
  910. const parts = timeString.split(":");
  911. if (parts.length !== 3) {
  912. if (parts.length == 2) {
  913. parts.push(0);
  914. } else {
  915. throw new Error("Invalid time string format. Expected 'hh:mm:ss'.");
  916. }
  917. }
  918.  
  919. const hours = parseInt(parts[0]);
  920. const minutes = parseInt(parts[1]);
  921. const seconds = parseInt(parts[2]);
  922.  
  923. if (isNaN(hours) || isNaN(minutes) || isNaN(seconds)) {
  924. throw new Error("Invalid time string format. Expected numeric values.");
  925. }
  926.  
  927. return hours * 3600 + minutes * 60 + seconds;
  928. },
  929. getLocalData(item, def) {
  930. var val = localStorage.getItem(item);
  931. if (val == null) return def;
  932.  
  933. return JSON.parse(val).val;
  934. },
  935. setLocalData(item, val) {
  936. return localStorage.setItem(item, JSON.stringify({ val: val }));
  937. },
  938. setFormVal(selector, formVal) {
  939. $.each(formVal, function (key, val) {
  940. let $el = $(selector).find(`[name="${key}"]`);
  941. // console.log($el);
  942. // console.log(key, $el.eq(0).attr("type"));
  943. if ($el.length == 0) return true;
  944. else if ($el.length == 1) {
  945. let type = $el.eq(0).attr("type");
  946. switch (type) {
  947. case "radio":
  948. case "checkbox":
  949. if ($el.val() == val) $el.prop("checked", true);
  950. break;
  951. default:
  952. $el.val(val);
  953. break;
  954. }
  955. } else {
  956. $el.each((i, el) => {
  957. // console.log($(el), $(el).val());
  958. if (val.includes($(el).val())) {
  959. $(el).prop("checked", true);
  960. }
  961. });
  962. }
  963. });
  964. },
  965. getFormVal(selector) {
  966. let formVal = {};
  967. var arr = $(selector).serializeArray();
  968. let tempArr = [];
  969. $.each(arr, function () {
  970. console.log(this);
  971. if (!tempArr.includes(this.name)) {
  972. tempArr.push(this.name);
  973. formVal[this.name] = this.value;
  974. } else {
  975. let oldVal = formVal[this.name];
  976. if (Array.isArray(oldVal)) {
  977. formVal[this.name].push(this.value);
  978. } else {
  979. formVal[this.name] = [formVal[this.name], this.value];
  980. }
  981. }
  982. });
  983. return formVal;
  984. },
  985. now() {
  986. return new Date().getTime();
  987. },
  988. getElByText(query, text, mode = "eq", visible = true) {
  989. let $el = null;
  990. $(query).each((i, el) => {
  991. if (visible && !$(el).is(":visible")) {
  992. return true;
  993. }
  994. if (mode == "eq" && $(el).text().trim() == text) {
  995. $el = $(el);
  996. return false;
  997. } else if (
  998. mode == "startsWith" &&
  999. $(el).text().trim().startsWith(text)
  1000. ) {
  1001. $el = $(el);
  1002. return false;
  1003. } else if (mode == "endsWith" && $(el).text().trim().endsWith(text)) {
  1004. $el = $(el);
  1005. return false;
  1006. }
  1007. });
  1008. return $el;
  1009. },
  1010. getElListByText(query, text, mode = "eq", visible = true) {
  1011. let arr = [];
  1012. $(query).each((i, el) => {
  1013. if (visible && !$(query).is(":visible")) {
  1014. return true;
  1015. }
  1016. if (mode == "eq" && $(el).text().trim() == text) {
  1017. arr.push($(el));
  1018. } else if (
  1019. mode == "startsWith" &&
  1020. $(el).text().trim().startsWith(text)
  1021. ) {
  1022. arr.push($(el));
  1023. } else if (mode == "endsWith" && $(el).text().trim().endsWith(text)) {
  1024. arr.push($(el));
  1025. }
  1026. });
  1027. return arr;
  1028. },
  1029. random(min, max) {
  1030. // 生成随机数范围
  1031. if (arguments.length === 2) {
  1032. return Math.floor(min + Math.random() * (max + 1 - min));
  1033. } else {
  1034. return null;
  1035. }
  1036. },
  1037. downloadTxt(filename, text) {
  1038. var element = document.createElement("a");
  1039. element.setAttribute(
  1040. "href",
  1041. "data:text/plain;charset=utf-8," + encodeURIComponent(text)
  1042. );
  1043. element.setAttribute("download", filename);
  1044.  
  1045. element.style.display = "none";
  1046. document.body.appendChild(element);
  1047.  
  1048. element.click();
  1049.  
  1050. document.body.removeChild(element);
  1051. },
  1052. dateFormat(date = new Date(), fmt = "yyyy-MM-dd HH:mm") {
  1053. let ret;
  1054. if (typeof date === "number") date = new Date(date);
  1055. const opt = {
  1056. "y+": date.getFullYear().toString(), // 年
  1057. "M+": (date.getMonth() + 1).toString(), // 月
  1058. "d+": date.getDate().toString(), // 日
  1059. "H+": date.getHours().toString(), // 时
  1060. "m+": date.getMinutes().toString(), // 分
  1061. "s+": date.getSeconds().toString(), // 秒
  1062. // 有其他格式化字符需求可以继续添加,必须转化成字符串
  1063. };
  1064. for (let k in opt) {
  1065. ret = new RegExp("(" + k + ")").exec(fmt);
  1066. if (ret) {
  1067. fmt = fmt.replace(
  1068. ret[1],
  1069. ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, "0")
  1070. );
  1071. }
  1072. }
  1073. return fmt;
  1074. },
  1075. });
  1076. setTimeout(() => {
  1077. if (!unsafeWindow.zfk) {
  1078. plugMain.init();
  1079. } else {
  1080. console.log('skip init');
  1081. }
  1082. }, 3000);
  1083. if (!unsafeWindow.plugMain) unsafeWindow.plugMain = plugMain;
  1084. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址