超星 - 阅读任务显示已读时间

不要停下来啊!(指阅读)

  1. // ==UserScript==
  2. // @name 超星 - 阅读任务显示已读时间
  3. // @description 不要停下来啊!(指阅读)
  4. // @namespace UnKnown
  5. // @author UnKnown
  6. // @icon https://imgsrc.baidu.com/forum/pic/item/6a63f6246b600c33c3d714d61c4c510fd9f9a106.jpg
  7. // @version 1.1
  8. // @match https://*.chaoxing.com/course/*.html
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @inject-into page
  12. // @run-at document-start
  13. // ==/UserScript==
  14.  
  15. const css = `
  16. #top,
  17. #readTime {
  18. opacity: .9;
  19. transition:
  20. opacity 150ms ease-in-out,
  21. filter 75ms ease-out;
  22. }
  23.  
  24. #top:hover,
  25. #readTime {
  26. opacity: 1;
  27. }
  28.  
  29. #top:active {
  30. filter: brightness(1.5);
  31. }
  32.  
  33. #readTime {
  34. display: flex;
  35. justify-content: center;
  36. align-items: center;
  37. position: fixed;
  38. right: 85px;
  39. bottom: 150px;
  40. width: 0;
  41. overflow: visible;
  42. white-space: nowrap;
  43. }
  44. #readTime > span {
  45. padding: 1ex 1ch;
  46. color: white;
  47. background-color: #212121;
  48. border-radius: 2px;
  49. box-shadow:
  50. 0px 3px 1px -2px rgba(0, 0, 0, 0.2),
  51. 0px 2px 2px 0px rgba(0, 0, 0, 0.14),
  52. 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
  53. }
  54. `.trim();
  55.  
  56. const sendLogs = function (para, url) {
  57. /*
  58. var para = {
  59. courseid : courseid,
  60. chapterid : chapterid,
  61. height : document.getElementById("courseMainBox").clientHeight,
  62. }
  63. if (from != null && from != "") { p._from_ = from; }
  64. if (rtag != null && rtag != "") { p.rtag = rtag; }
  65. var url = "/multimedia/readlog"
  66. */
  67.  
  68. // 多功能随机取整函数
  69. /* 当 extra 存在时,范围为 base ~ base + extra
  70. extra 不存在时,范围为 base ~ base * 2 */
  71. var roll = function (base, extra) {
  72. return Math.round(
  73. base + Math.random() * ( extra || base )
  74. );
  75. };
  76.  
  77. // 发送频率
  78. var interval = 5000;
  79. var intervalInSecond = interval / 1000;
  80.  
  81. // 发送概率
  82. var probability = 0.9;
  83.  
  84. // 页面边距
  85. var pad = roll(200, 66);
  86.  
  87. // 滚动参数,之后由 init 函数设置属性
  88. var scroll = {};
  89.  
  90. var init = function () {
  91. para.h = 0;
  92. // para.height / ( 32 ~ 64 )
  93. scroll.base = para.height / roll(32);
  94. // para.height / ( 16 ~ 32 )
  95. scroll.extra = para.height / roll(16);
  96. };
  97.  
  98. init();
  99.  
  100. // 检测并处理参数对象的 chapterid 属性
  101. var setCourseid = function (paramObj) {
  102. if (
  103. // 传入的参数对象 paramObj 拥有 chapterid 属性
  104. paramObj.chapterid &&
  105. // window.courselist 对象存在,且为数组
  106. window.courselist &&
  107. Array.isArray(window.courselist)
  108. ) {
  109. for( var i = 0; i < window.courselist.length; i++ ) {
  110. var course = window.courselist[i];
  111. var coursenext = window.courselist[i + 1];
  112. if (
  113. // coursenext 不存在,
  114. coursenext == undefined || // (
  115. // 或者 coursenext 存在,但是当前滚动高度 paramObj.h
  116. // 的大小在 course.h 和 coursenext.h 之间
  117. course.h <= paramObj.h &&
  118. paramObj.h < coursenext.h // )
  119. ) {
  120. // 按照 course.knowledgeid 是否存在,设置 chapterid
  121. paramObj.chapterid =
  122. course && course.knowledgeid || 0;
  123. break;
  124. }
  125. }
  126. }; // return paramObj;
  127. };
  128.  
  129. var ajax = function (paramObj, baseUrl) {
  130. setCourseid(paramObj);
  131. var xhr = new XMLHttpRequest();
  132. xhr.open(
  133. "GET",
  134. baseUrl + "?" + new URLSearchParams(paramObj).toString(),
  135. true
  136. );
  137. xhr.send(null);
  138.  
  139. };
  140.  
  141. ajax(para, url);
  142.  
  143. // 在右下角显示浏览器本地记录的本次已读时间
  144. // 后面的 time 和 duration 的单位都是秒
  145. var tick;
  146. var top = document.getElementById("top");
  147.  
  148. if ( top ) {
  149. var toReadableTime = function (time) { // 传入总时长 duration
  150.  
  151. if (time > 0) {
  152. var result = "";
  153.  
  154. if (time >= 3600)
  155. result += Math.floor(time / 3600) + " 小时 ";
  156. if (time >= 60)
  157. result += Math.floor(time / 60 % 60) + " 分钟 ";
  158. // if (time >= 0)
  159. result += Math.floor(time % 60) + " 秒";
  160.  
  161. return result;
  162. } else {
  163. return "0 秒";
  164. }
  165.  
  166. };
  167.  
  168. var div = document.createElement("div");
  169. var span = document.createElement("span");
  170. var style = document.createElement("style");
  171.  
  172. // 总时长
  173. var duration = GM_getValue(para.courseid) || 0;
  174.  
  175. div.id = "readTime";
  176. span.textContent = toReadableTime(duration);
  177. style.textContent = css ||
  178.  
  179. "#readTime { display: flex; justify-content: center; align-items: center;" +
  180. "position: fixed; right: 85px; bottom: 150px; width: 0; overflow: visible;" +
  181. "white-space: nowrap; }" +
  182. "#readTime > span { padding: 1ex 1ch; color: white; background-color: #212121; }";
  183.  
  184. div.appendChild(span);
  185. div.appendChild(style);
  186. document.body.appendChild(div);
  187.  
  188. tick = function (time) { // 传入每次增加的时长 intervalInSecond
  189. duration += time;
  190. span.textContent = toReadableTime(duration);
  191. para.courseid && GM_setValue(para.courseid, duration);
  192. };
  193. } else {
  194. tick = function () {};
  195. }
  196.  
  197. setInterval(
  198. function () {
  199. if ( Math.random() <= probability ) {
  200. para.h += roll( scroll.base, scroll.extra );
  201. if ( para.h > ( para.height + pad ) ) {
  202. init();
  203. }
  204. ajax(para, url);
  205. tick(intervalInSecond);
  206. }
  207. }, interval
  208. );
  209. }
  210.  
  211. Object.defineProperty(
  212. unsafeWindow, "sendLogs", {
  213. configurable: false,
  214. enumerable: true,
  215. writable: false,
  216. value: sendLogs
  217. }
  218. );

QingJ © 2025

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