头哥视频自动切换脚本

头哥视频自动播放下一个, 检测到视频暂停自动播放视频

  1. // ==UserScript==
  2. // @name 头哥视频自动切换脚本
  3. // @namespace https://github.com/yghr3a
  4. // @version 0.3.4
  5. // @description 头哥视频自动播放下一个, 检测到视频暂停自动播放视频
  6. // @author yghr3a
  7. // @license MIT
  8. // @match *://www.educoder.net/classrooms/*
  9. // @icon https://th.bing.com/th?id=ODLS.d8b30dba-8ef1-46d4-96a2-e3cce7129fca&w=32&h=32&qlt=90&pcl=fffffa&o=6&pid=1.2
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15. const MaxTryNum = 3;
  16.  
  17. let modal = null;
  18. let titleBar = null;
  19. let messageList = null;
  20.  
  21. function Wait(ms)
  22. {
  23. return new Promise(resolve => setTimeout(resolve, ms));
  24. }
  25.  
  26. function GetTitle()
  27. {
  28. let titleDiv = document.querySelector('div[class="title___bLyk5"]');
  29. return new String(titleDiv.textContent) ;
  30. }
  31.  
  32. async function CatchVideo()
  33. {
  34. let video_container = document.querySelector('div[id="video-container"]');
  35. for(let cnt = 1;video_container == null && cnt <= MaxTryNum; cnt++)
  36. {
  37. video_container = document.querySelector('div[id="video-container"]');
  38. addMessage("尝试获取video_container失败, 重试中!");
  39.  
  40. await Wait(1000);
  41. }
  42.  
  43. let video = video_container.querySelector('video[id="video"]');
  44. for(let cnt = 1;video == null && cnt <= MaxTryNum; cnt++)
  45. {
  46. video = video_container.querySelector('video[id="video"]');
  47. addMessage("尝试获取video失败,重试中!");
  48.  
  49. await Wait(1000);
  50. }
  51.  
  52. addMessage("获取video成功!");
  53.  
  54. return video;
  55. }
  56.  
  57. async function GetVideoList()
  58. {
  59. addMessage("开始获取视频列表!");
  60. let divVideoList = document.querySelectorAll('div[class="brght___uqI6i"]');
  61. for(let cnt = 1;divVideoList == null && cnt <= MaxTryNum; cnt++)
  62. {
  63. divVideoList = document.querySelectorAll('div[class="brght___uqI6i"]');
  64. addMessage("尝试获取class = brght___uqI6i的全部div失败,重试中!");
  65.  
  66. await Wait(1000);
  67. }
  68.  
  69. return divVideoList;
  70.  
  71.  
  72. }
  73.  
  74. async function Next(title)
  75. {
  76. await Wait(3000);
  77.  
  78. let videoList = await GetVideoList();
  79. for(let i = 0; i < videoList.length; i++)
  80. {
  81. let div = videoList[i];
  82. if(videoList[i].title == title)
  83. {
  84. if(i >= videoList.length - 1)
  85. {
  86. addMessage("已经到结尾!");
  87. return;
  88. }
  89. addMessage("切换到下一个视频");
  90. videoList[i + 1].click();
  91. }
  92. }
  93.  
  94. }
  95.  
  96. function GetConfirmButton()
  97. {
  98. let button = document.querySelector('button[class="ant-btn css-lw48js ant-btn-primary"]');
  99. return button;
  100. }
  101.  
  102. function GetPlayButton()
  103. {
  104. let button = document.querySelector('button[id="play"]');
  105. return button;
  106. }
  107.  
  108. function CheckVideoIfPlay(button)
  109. {
  110. let status = button.querySelector('use[href="#play-icon"]');
  111. if(status == null)
  112. {
  113. addMessage("获取按钮状态失败!");
  114. return true;
  115. }
  116.  
  117. if(status.getAttribute('style') == "display: block;")
  118. {
  119. return false;
  120. }
  121. else
  122. {
  123. return true;
  124. }
  125.  
  126. }
  127.  
  128. async function Loading()
  129. {
  130. await Wait(8000);
  131. let title = "hello_world";
  132. // 使用函数来显示悬浮窗
  133. createDraggableModal();
  134. addMessage("加载中!");
  135.  
  136. let ifend = false;
  137.  
  138. while(1)
  139. {
  140. await Wait(1000);
  141.  
  142. // 通过通过实时获取标题来检测视频是否切换!
  143. let newTitle = GetTitle();
  144.  
  145. if(title.trim().toLowerCase() !== newTitle.trim().toLowerCase())
  146. {
  147. addMessage("检测到视频切换!");
  148. title = newTitle;
  149.  
  150. await Wait(2000);
  151. let video = await CatchVideo();
  152.  
  153.  
  154. video.addEventListener('ended', async () => {
  155. addMessage("调用了ended事件, 等待三秒, 准备切换视频!");
  156. ifend = true;
  157. await Next(title);
  158. ifend = false;
  159. });
  160. }
  161.  
  162. // 通过实施检测PlayButton的状态来检测视频是否暂停!
  163. let PlayButton = GetPlayButton();
  164. if(PlayButton != null && CheckVideoIfPlay(PlayButton) == false)
  165. {
  166. if(ifend == false)
  167. {
  168. addMessage("检测到视频暂停!");
  169. PlayButton.click();
  170. }
  171. }
  172.  
  173. // 通过实施尝试捕获确认按钮来检测页面是否存在确认按钮
  174. let ConfirmButton = GetConfirmButton();
  175. if(ConfirmButton != null)
  176. {
  177. addMessage("检测到摄像头确认按钮!");
  178. ConfirmButton.click();
  179. }
  180.  
  181. }
  182. }
  183.  
  184. // 创建一个函数来生成悬浮窗
  185. function createDraggableModal() {
  186. // 模态框容器
  187. modal = document.createElement('div');
  188. modal.id = 'draggableModal';
  189. modal.style.position = 'fixed';
  190. modal.style.top = '50px'; // 初始位置
  191. modal.style.left = '50px';
  192. modal.style.width = '350px';
  193. modal.style.height = '350px';
  194. modal.style.backgroundColor = '#fff';
  195. modal.style.border = '1px solid #ccc';
  196. modal.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.1)';
  197. modal.style.zIndex = '1000';
  198. modal.style.overflow = 'hidden'; // 隐藏溢出内容
  199. modal.style.resize = 'both'; // 允许调整大小(可选,但此处为演示目的)
  200. modal.style.userSelect = 'none'; // 禁止文本选择'
  201. modal.style.resize = 'none';
  202.  
  203. // 消息列表容器
  204. messageList = document.createElement('div');
  205. messageList.style.height = '300px'; // 固定高度
  206. messageList.style.overflowY = 'auto'; // 垂直滚动条
  207. messageList.style.padding = '10px';
  208. messageList.style.borderBottom = '1px solid #ccc'; // 底部边框分隔
  209.  
  210. // 标题栏(用于拖动)
  211. titleBar = document.createElement('div');
  212. titleBar.style.backgroundColor = '#f0f0f0';
  213. titleBar.style.padding = '10px';
  214. titleBar.style.cursor = 'move';
  215. titleBar.textContent = '头哥视频自动切换脚本v0.3.2';
  216.  
  217. // 将元素组合起来
  218. modal.appendChild(titleBar);
  219. modal.appendChild(messageList);
  220.  
  221. // 将模态框添加到body元素的末尾
  222. document.body.appendChild(modal);
  223.  
  224. // 拖动逻辑
  225. var isDragging = false;
  226. var offsetX, offsetY;
  227.  
  228. titleBar.addEventListener('mousedown', function(e) {
  229. isDragging = true;
  230. offsetX = e.clientX - modal.offsetLeft;
  231. offsetY = e.clientY - modal.offsetTop;
  232. document.addEventListener('mousemove', onMouseMove);
  233. document.addEventListener('mouseup', onMouseUp);
  234. });
  235.  
  236. function onMouseMove(e) {
  237. if (isDragging) {
  238. modal.style.left = (e.clientX - offsetX) + 'px';
  239. modal.style.top = (e.clientY - offsetY) + 'px';
  240. }
  241. }
  242.  
  243. function onMouseUp() {
  244. isDragging = false;
  245. document.removeEventListener('mousemove', onMouseMove);
  246. document.removeEventListener('mouseup', onMouseUp);
  247. }
  248. }
  249.  
  250. function addMessage(msg)
  251. {
  252. var message = document.createElement('div');
  253. message.textContent = msg;
  254. message.style.marginBottom = '5px';
  255. messageList.appendChild(message);
  256. }
  257.  
  258.  
  259. window.onload = Loading;
  260.  
  261. })();

QingJ © 2025

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