// ==UserScript== // @name 云班课高效助手 // @author bellamy.n.h // @namespace http://tampermonkey.net/ // @version 1.60 // @description 【视频相关功能来啦 😊 新增 “视频连播” 、 “立即看完” 】 添加下载按钮,可批量下载资源,可按资源栏缩小范围进行批量处理资源,高效使用云班课。【***请勿滥用***】【注意:执行完毕后需刷新页面】【自用脚本,根据个人需求开发,只做了chrome适配,其他浏览器可用,但具体操作会有点不同】【如果好用就留着用吧😀,不好用给点建议也好🙇】 // @match https://www.mosoteach.cn/web/index.php* // @include *://www.mosoteach.cn/web/index.php* // @note Version 1.60 新增测试功能,支持 连续播放所有视频、 立即看完当前视频(测试阶段,还请反馈) // @note Version 1.50 加强对输入值约束; 支持多栏处理; chrome浏览器自动打开 设置页面地址更改; 其他Bug修复。 // @note Version 1.40 优化代码; 新增浏览器类型判断,支持chrome浏览器自动打开 设置页面。 // @note Version 1.32 优化操作反馈 (可以重置已选择的资源栏数) // @note Version 1.31 修复可能存在的Bug (页面无法自动关闭) // @grant GM_openInTab // @downloadURL none // ==/UserScript== $(function() { 'use strict'; /** * Determine the browser type */ function browserType() { var userAgent = navigator.userAgent; //get browser userAgent string var isOpera = userAgent.indexOf("Opera") > -1; if (isOpera) { return "Opera" }; //is Opera or not if (userAgent.indexOf("Firefox") > -1) { return "FF"; } //is Firefox or not if (userAgent.indexOf("Chrome") > -1) { return "Chrome"; } if (userAgent.indexOf("Safari") > -1) { return "Safari"; } //is Safari or not if (userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera) { return "IE"; }; //is IE or not } /** * sleep function * @param numberMillis -- 要睡眠的毫秒数 */ function sleep(numberMillis) { var now = new Date(); var exitTime = now.getTime() + numberMillis; while (true) { now = new Date(); if (now.getTime() > exitTime) return; } } /** * Remove duplicate value */ function removeDuplicate(arr) { let x = new Set(arr); return [...x]; } /** * download resources function */ function download(name, href) { var a = document.createElement("a"), //创建a标签 e = document.createEvent("MouseEvents"); //创建鼠标事件对象 e.initEvent("click", false, false); //初始化事件对象 a.href = href; //设置下载地址 a.download = name; //设置下载文件名 a.dispatchEvent(e); //给指定的元素,执行事件click事件 } // Refresh page tips function refreshPage() { alert("操作完成,请小可爱刷新页面查看结果!!!"); } //取消操作 function cancel() { alert("已取消操作!"); } /** * 点击和下载前以弹窗二次确认 * modeName * return boolean **/ function popupComfirm(modeName) { let conf_str = false; conf_str = confirm("小可爱,你即将执行“" + modeName + "”操作!!!" + "\n\n" + "根据选择资源数量的不同,会打开相应数量的页面,如果数量较多,请不要惊慌,因为这些页面会自动关闭的哦!!!" + "\n\n" + "你是否按照上一个提示,进行了相应的操作?" + "\n\n" + "如果是,你是否要开始执行本次操作?"); return conf_str; } /** * 数据清洗 inputString -> idsArr */ function cleanData(inputString) { //去除字符串中的所有空格 inputString.replace(/\s*/g, ""); //去掉首尾的 - 字符 if (inputString.charAt(0) == "-") { if (inputString.charAt(inputString.length - 1) == "-") inputString = inputString.substring(1, inputString.length - 1); else inputString = inputString.substring(1, inputString.length); } else if (inputString.charAt(inputString.length - 1) == "-") { inputString = inputString.substring(0, inputString.length - 1); } //console.log(inputString + "/" + inputString.charAt(0) +"/" + inputString.charAt(inputString.length-1)); //分割出要点击的栏号,存入数组,用于映射出对应的资源栏id let idsArr = inputString.split("-"); //去重并排序 idsArr = removeDuplicate(idsArr).sort(); //去除超出资源栏总数的无效值 let temp = []; for (let i = 0; i < idsArr.length; i++) { // console.log("srcBarSum is" + srcBarSum); if (idsArr[i] <= srcBarSum && idsArr[i] > 0) { temp.push(idsArr[i]); // console.log("temp is" + temp); } } // console.log("idsArr is" + idsArr); return idsArr = temp; } /** * 根据模式名执行对应的批量处理操作 * * 点击确认按钮弹出确认弹窗, * 如果确认执行,则执行点击操作, * 否则执行 取消操作 */ function batchForMoreSrcBars(modeName, ids) { if (ids.length == 0) ids.push(".res-row-box"); let isDownloadMode = modeName == "模拟点击" ? "false" : (modeName == "批量下载" ? "true" : "其他"); if (popupComfirm(modeName)) { try { // console.log(chosenIDs); let startIndex = $("#head").val(); let endIndex = $("#tail").val(); for (let id of ids) { // console.log(thisID); try { batch(isDownloadMode, id, startIndex, endIndex); } catch (e) { console.log(id + "该栏执行异常,跳过执行"); continue; } } } finally { //点击完成,提示刷新页面 setTimeout(refreshPage, 0); //置空栏号输入框 $(".indexNum").val(""); } } else { cancel(); } } /** * Click or download in bulk according to * isDownload : true -> Download Mode ; false -> Click Mode * thisBarID : 此次要执行的资源栏 id * startIndex : 此次资源栏中执行的开始资源编号 * endIndex : 此次资源栏中执行的结束资源编号 * */ function batch(isDownload, thisBarID, startIndex, endIndex) { //let isDownloadMesg = isDownload == "false" ? "模拟点击" : "批量下载"; // 以下五个等价,实现相同功能,但写法是逐步优化 // var list = document.getElementsByClassName("res-row-open-enable"); // var list = $(".res-row-open-enable"); // var list = $(".hide-div").children(); // var list = $(".res-row-box").children(".hide-div").children(); let list = $(thisBarID).children(".hide-div").children(); let succNum = 0; let failNum = 0; let tempUrl; let win; let actualStartIndex = startIndex <= list.length && startIndex > 0 ? startIndex : (startIndex <= 0 ? 1 : list.length); //小于0则为 1 ; 大于 最大值 则为 最大值 let actualEndIndex = endIndex <= list.length && endIndex > 0 ? endIndex : (endIndex <= 0 ? 1 : list.length); //输入值超出资源总数的值,则将输入值置为总数的值 if (actualStartIndex > actualEndIndex) { console.log("here"); alert("小可爱😀,你的起始结束值写反了哟!"); return; } // console.log("actualStartIndex: " + actualStartIndex); // console.log("actualEndIndex: " + actualEndIndex); // list 存在并不为空 if (null == list || list.size() == 0) { console.log(thisBarID + "对应的资源栏为空"); } else { for (let i = actualStartIndex - 1; i < actualEndIndex; i++) { // console.log(i); // console.log(list); // console.log(list[i]); try { tempUrl = list[i].getAttribute("data-href"); if (null == tempUrl || tempUrl == "") { console.log("资源栏:" + thisBarId + "的第 " + (i + 1) + " 条资源未获取到URL"); } else { win = window.open(tempUrl); if (isDownload == 'false') { sleep(100); //睡眠,是为了确保每个资源都被正常获取 win.close(); } succNum++; // console.log(tempUrl); } } catch (e) { console.log(e.name + ": " + e.message); console.log("资源栏:" + thisBarId + "的第 " + (i + 1) + " 条未成功执行 ;URL : " + list[i].getAttribute("data-href")); failNum++; continue; } } } console.log("共检索到 " + list.length + "条; 成功执行 " + succNum + " 次! 失败 " + failNum + " 次! 操作范围:从第 " + actualStartIndex + " 条 至 第 " + actualEndIndex + " 条。"); } /** * click all resources in two ways according to 'isPositive' */ function clickAll(isPositive) { let isPositiveMesg = isPositive == "true" ? "正序点击" : "倒序点击"; let conf_str = false; conf_str = confirm("小可爱,你即将执行“" + isPositiveMesg + "全部资源”操作,如果资源量较大(> 1000),耗时就会较久,打开的页面也会较多哦!不过都会自动关闭的哦!!!" + "\n\n" + "小可爱,资源较多时,还请三思啊!!!" + "\n\n" + "你是否要执行?"); if (conf_str) { let list = document.getElementsByClassName("res-row-open-enable"); let succNum = 0; let failNum = 0; let tempUrl; let win; if (isPositive == "true") { for (let i = 0; i < list.length; i++) { try { tempUrl = list[i].getAttribute("data-href"); win = window.open(tempUrl); sleep(100); //睡眠,是为了确保每个资源都被正常获取 win.close(); succNum++; // console.log(tempUrl); } catch (e) { console.log(e.name + ": " + e.message); console.log("该条未成功执行 ;URL : " + list[i].getAttribute("data-href")); failNum++; continue; } } } else { for (let i = list.length - 1; i >= 0; i--) { try { tempUrl = list[i].getAttribute("data-href"); win = window.open(tempUrl); sleep(100); //睡眠,是为了确保每个资源都被正常获取 win.close(); succNum++; // console.log(tempUrl); } catch (e) { console.log(e.name + ": " + e.message); console.log("该条未成功执行 ;URL : " + list[i].getAttribute("data-href")); failNum++; continue; } } } console.log(isPositiveMesg + ": 共检索到 " + list.length + "条; 成功执行 " + succNum + " 次! 失败 " + failNum + " 次!"); setTimeout(refreshPage, 0); } else { alert("已取消操作!"); } } /** * Play all videos continuously */ function continuousPlay() { isContinuousPaly = true; if( typeof($("#continuousPlay").attr("class")) != "undefined"){ alert("连续播放已开启,无需重复开启"); return; } $('