在线云课堂(腾讯、网易、慕课网...)增加多倍速/去除xxx正在播放/自动播放下一条视频

腾讯课堂、慕课网、网易云课堂添加多倍速播放(默认最大 2 倍速,支持到 4 倍速)/自动播放下一个视频(携带上一个视频的倍速);腾讯课堂去除漂浮水印;

  1. // ==UserScript==
  2. // @icon http://9.url.cn/edu/lego_modules/edu-ui/0.0.1/img/nohash/logo_pc_rich.png
  3. // @name 在线云课堂(腾讯、网易、慕课网...)增加多倍速/去除xxx正在播放/自动播放下一条视频
  4. // @namespace http://tampermonkey.net/
  5. // @version 0.5
  6. // @description 腾讯课堂、慕课网、网易云课堂添加多倍速播放(默认最大 2 倍速,支持到 4 倍速)/自动播放下一个视频(携带上一个视频的倍速);腾讯课堂去除漂浮水印;
  7. // @author Bamboo
  8. // @include /^http(s?)://www.imooc.com/(.*)$/
  9. // @include /^http(s?)://ke.qq.com/(.*)$/
  10. // @include /^http(s?)://study.163.com/(.*)$/
  11. // @match *://ke.qq.com/webcourse/*
  12. // @match *://study.163.com/course/*
  13. // @require http://libs.baidu.com/jquery/2.0.0/jquery.min.js
  14. // @run-at document-end
  15. // @license MIT
  16. // ==/UserScript==
  17. var website_url = window.location.href || document.location.href;
  18. var website_host = window.location.host || document.location.host;
  19.  
  20. /**
  21. * 网易云课堂
  22. */
  23. var StudyWy = {
  24. //添加多倍速播放
  25. addWyExtSpeedPlay() {
  26. $('.m-popover-rate').css('display', 'none');
  27. let appendHtml = '<select class="changePlayRateSelect" style="margin-left: 50px">' +
  28. '<option value="0.5">0.5倍速</option>' +
  29. '<option value="0.75">0.75倍速</option>' +
  30. '<option value="1">1倍速</option>' +
  31. '<option value="1.25">1.25倍速</option>' +
  32. '<option value="1.5">1.5倍速</option>' +
  33. '<option value="2">2倍速</option>' +
  34. '<option value="2.5">2.5倍速</option>' +
  35. '<option value="3">3倍速</option>' +
  36. '<option value="3.5">3.5倍速</option>' +
  37. '<option value="4">4倍速</option>' +
  38. '<option value="4.5">4.5倍速</option>' +
  39. '<option value="5">5倍速</option>' +
  40. '<option value="5.5">5.5倍速</option>' +
  41. '<option value="6">6倍速</option>' +
  42. '<option value="6.5">6.5倍速</option>' +
  43. '<option value="7">7倍速</option>' +
  44. '</select>';
  45. $('.j-aotoplaybox').after(appendHtml);
  46. }
  47. }
  48.  
  49. /**
  50. * 腾讯课堂
  51. */
  52. var Bamboo = {
  53. /**
  54. * 根据属性获取标签,列表返回。
  55. * tagName 要获取元素的标签
  56. * attrName 属性名
  57. * attrVal 属性值
  58. **/
  59. getDom(tagName, attrName, attrVal) {
  60. var selectElement = [];
  61. var element = document.getElementsByTagName(tagName);
  62. for (var i = 0; i < element.length; i++) {
  63. var tmpVal = element[i].getAttribute(attrName);
  64. if (attrVal === tmpVal) {
  65. selectElement.push(element[i]);
  66. }
  67. }
  68.  
  69. return selectElement;
  70. },
  71. /**
  72. * 根据父 dom 元素获取子 dom 元素,
  73. * parentDom 要获取的父 dom 元素
  74. * tagName 要获取的子 dom 的标签
  75. * index 要获取子 dom 的索引(第几个元素,默认第 1 个元素-index=0)
  76. **/
  77. getChildDom(parentDom, tagName, index) {
  78. var children = parentDom.getElementsByTagName(tagName);
  79. if (children) {
  80. if (index) {
  81. return children[index]
  82. }
  83. return children[0]
  84. }
  85. return null;
  86. },
  87. removeWatermark() {
  88. var head = document.head
  89. var style = document.createElement("style")
  90. style.type = "text/css"
  91. var css = [
  92. "a[class*='marquee animation'],txpdiv[class*='player-inject'] {",
  93. " display: none!important;",
  94. "}",
  95. "#x-tcp-container > txpdiv {",
  96. " display: none!important;",
  97. "}",
  98. ].join("\n")
  99. var text = document.createTextNode(css)
  100. style.appendChild(text)
  101. head.appendChild(style)
  102. },
  103. liClickEvent() {
  104. var tmpList = document.querySelectorAll("div.loki-playbackrate");
  105. var tmpUlList;
  106. for (var i = 0; i < tmpList.length; i++) {
  107. var tmp = Bamboo.getChildDom(tmpList[i], 'ul');
  108.  
  109. if (tmp) {
  110. tmpUlList = tmp
  111. }
  112. }
  113.  
  114. var childNodes = tmpUlList.childNodes;
  115. for (var j = 0; j < childNodes.length; j++) {
  116. var li = childNodes[j];
  117. var attrVal = li.getAttribute("loki-menu-selected");
  118. var classAttrVal = li.getAttribute("class");
  119. if (classAttrVal && classAttrVal.indexOf('loki-menu-selected') > -1) {
  120. li.setAttribute('class', classAttrVal.substring(0, classAttrVal.indexOf('loki-menu-selected') - 1));
  121. }
  122. }
  123. var rateDiv = document.querySelector("div.loki-playbackrate");
  124. var rateVal = rateDiv.querySelectorAll('button.loki-rate-button')
  125. var classVal = this.getAttribute('class')
  126. classVal = classVal.concat("loki-menu-selected");
  127.  
  128. var selectSpeedText = this.innerText;
  129. var selectSpeed = 1;
  130. rateVal[0].innerText = selectSpeedText;
  131. if (selectSpeedText) {
  132. selectSpeed = selectSpeedText.replace(/x/, '').replace(/倍/, '')
  133. }
  134.  
  135. var video = document.getElementsByTagName("video")[0] || document.getElementById("videoPlayer") || document.querySelector('video');
  136. if (video) {
  137. video.play();
  138. video.playbackRate = selectSpeed;
  139. }
  140. },
  141. initFunc(){
  142. console.log('initFunc ----- bamboo')
  143. var ulList;
  144. //定义播放速度列表
  145. var extSpeedArr = [0.8, 1, 1.25, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7];
  146. var playSpeedList = document.querySelectorAll("div.loki-playbackrate");
  147. var button;
  148. for (var i = 0; i < playSpeedList.length; i++) {
  149. var tmp = Bamboo.getChildDom(playSpeedList[i], 'ul');
  150. var tmp1 = Bamboo.getChildDom(playSpeedList[i], 'button');
  151. if (tmp) {
  152. ulList = tmp
  153. }
  154. if (tmp1) {
  155. button = tmp1;
  156. }
  157. }
  158. if (!ulList || !ulList.innerHTML) {
  159. return
  160. }
  161. ulList.innerHTML = '';
  162.  
  163. for (var j = 0; j < extSpeedArr.length; j++) {
  164. var appendLi = document.createElement('li');
  165. appendLi.setAttribute('class', 'vjs-menu-item')
  166. appendLi.setAttribute('tabindex', '-1')
  167. appendLi.setAttribute('role', 'menuitemcheckbox')
  168. appendLi.setAttribute('aria-live', 'polite')
  169. appendLi.setAttribute('aria-disabled', 'false')
  170. appendLi.setAttribute('aria-checked', 'false')
  171.  
  172. var liSpan1 = document.createElement('span');
  173. liSpan1.setAttribute('class', 'vjs-menu-item-text');
  174. liSpan1.innerText = extSpeedArr[j] + 'x';
  175. appendLi.appendChild(liSpan1);
  176.  
  177. var liSpan2 = document.createElement('span');
  178. liSpan2.setAttribute('class', 'vjs-control-text');
  179. appendLi.appendChild(liSpan1);
  180. appendLi.appendChild(liSpan2);
  181.  
  182. ulList.append(appendLi)
  183.  
  184. if (appendLi.addEventListener) {
  185. appendLi.addEventListener("click", Bamboo.liClickEvent, false);
  186. }
  187. if (appendLi.attachEvent) {
  188. appendLi.attachEvent("onclick", Bamboo.liClickEvent);
  189. }
  190. }
  191. }
  192. };
  193.  
  194. /**
  195. * imooc 网
  196. */
  197. //imooc 添加多倍速播放
  198. let Mooc = {
  199. moocLiClickEvent(obj) {
  200. $(obj).parent().find('li').removeClass('current')
  201. $(obj).addClass('current');
  202.  
  203. var currentSpeedText = $(obj).text();
  204. var currentSpeed = currentSpeedText.replace(/[^0-9]/ig, '');
  205. var cssAttrs = $('.vjs-playback-rate-value').attr('class');
  206. var rateNum = cssAttrs.replace(/[^0-9]/ig, '');
  207.  
  208. $('.vjs-playback-rate-value').removeClass('rate' + rateNum + 'x').addClass('rate' + (currentSpeed * 10 > 100 ? (currentSpeed * 10 / 10) : currentSpeed * 10) + 'x')
  209.  
  210. if (currentSpeed.length == 2) {
  211. currentSpeed = currentSpeed / 10;
  212. } else if (currentSpeed.length == 3) {
  213. currentSpeed = currentSpeed / 100;
  214. }
  215. $('.vjs-playback-rate-value').css('background-image', 'url()');
  216. $('.vjs-playback-rate-value').text(currentSpeed + 'x');
  217.  
  218. var video = document.getElementsByTagName("video")[0] || document.getElementById("videoPlayer") || document.querySelector('video');
  219. if (video) {
  220. video.play();
  221. video.playbackRate = currentSpeed;
  222. }
  223. },
  224. addMoocExtSpeedPlay() {
  225. var extSpeedArr = ['2.5x', '3x', '3.5x', '4x','4.5x','5x','5.5x','6x','6.5x','7x'];
  226. var ulList = $('#vjsMenu').children('ul')
  227. var appendHtml = '<li class="vjs-menu-item" tabindex="-1" role="menuitem" aria-live="polite">?<span class="vjs-control-text"></span><i class="imv2-check"></i></li>';
  228. for (var i = 0; i < extSpeedArr.length; i++) {
  229. var appendLi = appendHtml.replace('?', extSpeedArr[i]);
  230. ulList.prepend(appendLi)
  231. }
  232.  
  233. $('ul.vjs-menu-content').on('click', 'li', function () { //只要改这一行就可以了
  234. Mooc.moocLiClickEvent(this);
  235. });
  236. }
  237. }
  238.  
  239. ; (function () {
  240. 'use strict';
  241. //网易云课堂
  242. if (website_host.indexOf('study.163.com') > -1) {
  243. setTimeout(function () {
  244. try {
  245. StudyWy.addWyExtSpeedPlay();
  246. $(document).ready(function () {
  247. let speedText = $('.j-ratebtn_text').text().replace(/x/, '');
  248. $(".changePlayRateSelect").find("option[value='" + speedText + "']").attr("selected", true);
  249.  
  250. $('.changePlayRateSelect').change(function () {
  251. var val = $(this).children('option:selected').val();//这就是selected的值
  252. $('.j-ratebtn_text').text(val + 'x');
  253. var video = document.getElementsByTagName("video")[0] || document.getElementById("videoPlayer") || document.querySelector('video');
  254. if (video) {
  255. video.play();
  256. video.playbackRate = val;
  257. }
  258. })
  259. });
  260.  
  261. //自动播放下一个视频
  262. var studyLoop = setInterval(function () {
  263. let replayTxt = $('.j-replay').css('display');
  264. if (replayTxt == 'block') {
  265. document.getElementById("j-next").click();
  266.  
  267. setTimeout(() => {
  268. //重置速度与显示,以及隐藏倍速切换
  269. $('.m-popover-rate').css('display', 'none');
  270.  
  271. let speedVal = $('.changePlayRateSelect option:selected').val()
  272. $('.j-ratebtn_text').text(speedVal + 'x');
  273. var video = document.getElementsByTagName("video")[0] || document.getElementById("videoPlayer") || document.querySelector('video');
  274. if (video) {
  275. video.play();
  276. video.playbackRate = speedVal;
  277. }
  278. }, 3000);
  279. }
  280. }, 1000);
  281. } catch (error) {
  282. }
  283. }, 5000);
  284. }
  285.  
  286. //腾讯课堂
  287. if (website_host.indexOf('ke.qq.com') > -1) {
  288. try {
  289. Bamboo.removeWatermark();
  290. setTimeout(Bamboo.initFunc, 5000);
  291.  
  292.  
  293. //自动播放下一个视频
  294. var qqLoop = setInterval(function () {
  295. if ($('.next-btn') != null && $('.next-btn') != undefined && $('.next-btn').length > 0) {
  296. $('.next-btn').click();
  297.  
  298. let speedVal = $('.loki-playbackrate .loki-rate-button').html().replace(/x/, '');
  299. setTimeout(() => {
  300. if (speedVal != undefined && /[0-9]{1}\.{0,1}[0-9]{0,2}/.test(speedVal)) {
  301. var video = document.getElementsByTagName("video")[0] || document.getElementById("videoPlayer") || document.querySelector('video');
  302. if (video) {
  303. console.log('speedVal:' + speedVal)
  304. video.play();
  305. video.playbackRate = speedVal;
  306. Bamboo.initFunc();
  307. }
  308. }
  309. }, 3000);
  310. }
  311. }, 1000);
  312. } catch (error) {
  313. }
  314. }
  315.  
  316. // 慕课网
  317. if (website_host.indexOf('imooc.com') > -1) {
  318. try {
  319. //imooc 自动播放下一条视频 参考372498,不过有的失效的地方我已经改掉
  320. var nextMask = document.querySelector('div.next-box.J_next-box');
  321. var moocLoop = setInterval(function () {
  322. if (!nextMask.classList.contains('hide')) {
  323. //写入 cookie
  324. let speedVal = $('.vjs-playback-rate-value').html().replace(/x/, '');
  325. let cookieVal = document.cookie;
  326. if (cookieVal.indexOf('backPlayRate') > -1) {
  327. let oldSpeedVal = cookieVal.split(";")[0].split("=")[1];
  328. if (speedVal != oldSpeedVal ){
  329. cookieVal = cookieVal.substring(cookieVal.indexOf(';'));
  330. document.cookie = 'backPlayRate=' + speedVal + ';' + cookieVal;
  331. }
  332. } else {
  333. document.cookie = 'backPlayRate=' + speedVal + ';' + cookieVal;
  334. }
  335.  
  336. document.querySelector('span.J-next-btn.next-auto.moco-btn.moco-btn-green').click();
  337. }
  338. }, 1000);
  339. //添加多倍速菜单
  340. setTimeout(function () {
  341. Mooc.addMoocExtSpeedPlay();
  342.  
  343. //读取 cookie 设置播放速度
  344. let cookieVal = document.cookie;
  345. if (cookieVal.indexOf('backPlayRate') > -1) {
  346. let speedVal = cookieVal.split(";")[0].split("=")[1];
  347. if (speedVal != null && speedVal != undefined && /[0-9]{1}\.{0,1}[0-9]{0,2}/.test(speedVal)) {
  348. var cssAttrs = $('.vjs-playback-rate-value').attr('class');
  349. var rateNum = cssAttrs.replace(/[^0-9]/ig, '');
  350.  
  351. $('.vjs-playback-rate-value').removeClass('rate' + rateNum + 'x').addClass('rate' + (speedVal * 10 > 100 ? (speedVal * 10 / 10) : speedVal * 10) + 'x')
  352.  
  353. $('.vjs-playback-rate-value').css('background-image', 'url()');
  354. $('.vjs-playback-rate-value').text(speedVal + 'x');
  355.  
  356. var video = document.getElementsByTagName("video")[0] || document.getElementById("videoPlayer") || document.querySelector('video');
  357. if (video) {
  358. video.play();
  359. video.playbackRate = speedVal;
  360. }
  361. }
  362. }
  363. }, 3000)
  364. } catch (error) {
  365. }
  366. }
  367. })();