国家开放大学课程视频后台播放

提升学习效率

  1. // ==UserScript==
  2. // @name 国家开放大学课程视频后台播放
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.4
  5. // @description 提升学习效率
  6. // @author TurbMZ
  7. // @license MIT
  8. // @match https://moodle.syxy.ouchn.cn/mod/*/view.php*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=ouchn.cn
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15. let cache_status = localStorage.getItem('_my_tamermonkey_status_');
  16. let cache_loop_status = localStorage.getItem('_my_tamermonkey_loop_status_');
  17. console.log('后台播放缓存状态',cache_status);
  18. console.log('后台循环缓存状态',cache_loop_status);
  19. if(cache_status === null) {
  20. cache_status= 0;
  21. } else {
  22. cache_status = JSON.parse(cache_status);
  23. }
  24. if(cache_loop_status === null){
  25. cache_loop_status = 0;
  26. } else {
  27. cache_loop_status = JSON.parse(cache_loop_status);
  28. }
  29. let loop_status = cache_loop_status || 0;
  30. let status = cache_status || 0;
  31. localStorage.setItem('_my_tamermonkey_status_', status);
  32. localStorage.setItem('_my_tamermonkey_loop_status_',loop_status);
  33.  
  34. let _my_tamermonkey_speed_ = 1;
  35. const speedMap = [ 1, 1.5, 2, 4 ];
  36. const container = document.getElementById('page-content');
  37. const navDom = document.querySelector('.mobile_course');
  38. const cursess = navDom.querySelectorAll('.activity');
  39. const list = Array.from(cursess).filter(item=>{
  40. return Array.from(item.classList).includes('page') ||
  41. Array.from(item.classList).includes('url');
  42. })
  43. let videoDom = document.getElementsByTagName('VIDEO')[0];
  44. let tryTimes = 0; // 已重试次数
  45. const maxReTryTimes = 10; // 最大重试次数 200ms 重试一次
  46. // 播放下一个视频
  47. const nextPageVideo = function() {
  48. console.log('课程列表',list)
  49. let currentIndex = Array.from(list).findIndex((item,index)=>{
  50. return Array.from(item.classList).includes('current')
  51. });
  52. console.log('播放下一个视频',currentIndex)
  53. if(currentIndex>-1 && currentIndex != list.length-1){ // 有且 当前不是最后一个
  54. const nextLi = list[currentIndex+1]
  55. const alink = nextLi.querySelector('.aalink')
  56. alink&&alink.click()
  57. }
  58. }
  59.  
  60. const init = function() {
  61. console.log("初始化插件功能", status, typeof status);
  62. container.style.position = 'relative';
  63. let btnText = status?'停用后台播放':'启用后台播放';
  64. let controlBox = document.createElement('DIV');
  65. let controlBtn = document.createElement('SPAN');
  66. let speedBtn = document.createElement('SPAN');
  67. let jopeToEndBtn = document.createElement('SPAN');
  68. let loopPlayBtn = document.createElement('SPAN');
  69. // 开关循环播放视频
  70. const loopHandler = function(e){
  71. loop_status = loop_status ? 0 : 1;
  72. localStorage.setItem('_my_tamermonkey_loop_status_',loop_status);
  73. e.target.innerText = loop_status?'关闭循环播放':'开启循环播放';
  74. };
  75. // 控制开关
  76. const controlHandler = function(e) {
  77. status = status ? 0: 1;
  78. localStorage.setItem('_my_tamermonkey_status_',status);
  79. let btnText = status?'停用后台播放':'启用后台播放';
  80. e.target.innerText = btnText;
  81. }
  82. // 调速
  83. const speedHandler = function(e) {
  84. let currentSpeedIndex = speedMap.findIndex(v=>_my_tamermonkey_speed_===v);
  85. if(currentSpeedIndex===speedMap.length-1){
  86. currentSpeedIndex = 0;
  87. }else{
  88. ++currentSpeedIndex;
  89. }
  90. _my_tamermonkey_speed_ = speedMap[currentSpeedIndex];
  91. videoDom.playbackRate = _my_tamermonkey_speed_;
  92. e.target.innerText = `快进>>${_my_tamermonkey_speed_}倍速`;
  93. }
  94. // 快进到最后
  95. const toEndHandler = function(e) {
  96. console.log('快进到最后');
  97. let duration = videoDom.duration;
  98. let toEndTime = Math.floor(duration-1);
  99. videoDom.currentTime = toEndTime;
  100. console.log(videoDom.currentTime);
  101. }
  102. //容器设置样式和id
  103. controlBox.id = 'myTampermonkeyControl';
  104. controlBox.style.cssText = 'position:absolute;right:0px;bottom:0px;display:flex;align-items:center;font-size:12px;';
  105. //控制按钮设置样式和id
  106. controlBtn.id = 'controlBtn';
  107. controlBtn.style.cssText = 'display:inline-block;padding: 4px 10px;border-radius:4px;margin-right:10px;cursor:pointer;background:#999;color:#fff;';
  108. controlBtn.innerText = btnText;
  109. speedBtn.id = 'speedBtn';
  110. speedBtn.style.cssText = 'display:inline-block;padding: 4px 10px;border-radius:4px;cursor:pointer;background:#999;color:#fff;margin-right:10px;';
  111. speedBtn.innerText = `快进>>${_my_tamermonkey_speed_}倍速`;
  112. jopeToEndBtn.style.cssText = 'display:inline-block;padding: 4px 10px;border-radius:4px;cursor:pointer;background:#999;color:#fff;';
  113. jopeToEndBtn.innerText = '跳到最后';
  114. loopPlayBtn.innerText = loop_status?'关闭循环播放':'开启循环播放';
  115. loopPlayBtn.style.cssText = 'display:inline-block;padding: 4px 10px;border-radius:4px;margin-right:10px;cursor:pointer;background:#999;color:#fff;';
  116. // 按钮添加事件
  117. loopPlayBtn.onclick = loopHandler;
  118. controlBtn.onclick= controlHandler;
  119. speedBtn.onclick = speedHandler;
  120. jopeToEndBtn.onclick = toEndHandler;
  121. controlBox.appendChild(loopPlayBtn);
  122. controlBox.appendChild(controlBtn);
  123. controlBox.appendChild(speedBtn);
  124. controlBox.appendChild(jopeToEndBtn);
  125. container.appendChild(controlBox);
  126. videoDom.addEventListener('ended', function () { //结束
  127. console.log("播放结束");
  128. console.log('是否循环播放',loop_status);
  129. if(loop_status) nextPageVideo()
  130. //controlBtn.click()
  131. }, false);
  132. document.addEventListener('visibilitychange', function() {
  133. if(!videoDom){
  134. videoDom = document.getElementsByTagName('VIDEO')[0];
  135. }
  136. var isHidden = document.hidden;
  137. console.log(document.visibilityState,isHidden,status); // window._my_tamermonkey_status_
  138. if (isHidden && status) {
  139. console.log(status);
  140. setTimeout(()=>{
  141. videoDom.play();
  142. },200)
  143. }else if(isHidden){
  144. videoDom.pause();
  145. }
  146. });
  147. // 如开启后台播放,自动静音播放视频
  148. if(status) {
  149. videoDom.muted = 'muted';
  150. setTimeout(()=> {
  151. const playPromise = videoDom.play();
  152. if (playPromise !== undefined) {
  153. playPromise.then(res => {
  154. // Automatic playback started!
  155. // Show playing UI.
  156. }).catch(error => {
  157. // Auto-play was prevented
  158. // Show paused UI.
  159. });
  160. }
  161. },100)
  162. }
  163. }
  164. if(videoDom){ // 有视频
  165. console.log('有视频');
  166. init();
  167. }else{ // 视频未加载,重试
  168. console.log('视频未加载');
  169. let timer = null;
  170. timer = setInterval(()=>{
  171. console.log('轮询');
  172. if(tryTimes >= maxReTryTimes){ // 重试最后都没有找到视频
  173. clearInterval(timer);
  174. timer = null;
  175. if(loop_status){ // 如果是循环播放,则说明是文本课程,直接跳转下一个课程
  176. console.log('文本课程,直接跳转下一个课程')
  177. setTimeout(()=>{
  178. nextPageVideo()
  179. },2000)
  180. }
  181. return;
  182. }
  183. videoDom = document.getElementsByTagName('VIDEO')[0];
  184. if(videoDom){
  185. try{
  186. init();
  187. clearInterval(timer);
  188. timer = null;
  189. return;
  190. }catch(err){
  191. clearInterval(timer);
  192. timer = null;
  193. console.log(err);
  194. }
  195. }
  196. tryTimes++
  197. },200)
  198. }
  199.  
  200. // Your code here...
  201. })();

QingJ © 2025

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