GGS网校刷课

仅支持广工商网校刷课网站,傻瓜式操作,安装即用

// ==UserScript==
// @name         GGS网校刷课
// @namespace    https://gf.qytechs.cn/users/899412
// @require      https://unpkg.com/[email protected]/dist/jquery.min.js
// @require      https://unpkg.com/[email protected]/dist/cookie.min.js
// @version      2.1.0
// @description  仅支持广工商网校刷课网站,傻瓜式操作,安装即用
// @author       ByoneJie
// @match        *://study.gzgsmooc.org.cn/*
// @icon         https://upyun.byone.top/uploads%2F2022%2F04%2F11%2FquAWKEjl_shcool.gif
// @connect      orc.byone.top
// @connect      127.0.0.1
// @connect      gzad.byone.top
// @grant        unsafeWindow
// @grant        GM_notification
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_listValues
// @grant        GM_deleteValue
// @grant        GM_xmlhttpRequest
// @grant        GM_openInTab
// @license      MIT
// @note        郑重声明:本脚本只做学习交流使用,未经作者允许,禁止转载,不得使用与非法用途,一经发现,追责到底
// ==/UserScript==

(function () {
  'use strict';

// 引入css
var $ = $ || window.$;
$('head').append($(`<link rel="stylesheet" href="https://upyun.byone.top/uploads%2F2022%2F04%2F16%2F37VLSTYK_ggswk_2.0.0.css">`))
$('body').append($(`<script src="https://upyun.byone.top/uploads%2F2022%2F04%2F14%2F18nar1Dg_utils.js"></script>`))
// ggs刷课脚本
const version = '2.1.0'
var timerWhiteList = 0;
var codeStatus = '';

var tools = [
  {
    id: 1,
    name: '解除进度条拖动',
    type: 'checkbox',
    value: false
  },
  {
    id: 2,
    name: '倍数重置',
    type: 'checkbox',
    value: false
  },
  {
    id: 3,
    name: '自动下一集',
    type: 'checkbox',
    value: false
  },
  {
    id: 10,
    name: '重置脚本',
    type: 'button',
    value: 'reset'
  },
  {
    id: 11,
    name: '自动检测更新',
    type: 'checkbox',
    value: true
  },
  {
    id: 12,
    name: '运行日志',
    type: 'checkbox',
    value: false
  }
]

var stuInfo = {};
var userInfo = {};
var token = '';
var logContent =  ``;
var logCount = 0;
var rate = [
  {
    key: 0.5,
    value: '0.5倍'
  },
  {
    key: 1,
    value: '1倍'
  },
  {
    key: 1.25,
    value: '1.25倍'
  },{
    key: 2,
    value: '2倍'
  },{
    key: 4,
    value: '4倍'
  },{
    key: 6,
    value: '6倍(推荐)'
  },{
    key: 10,
    value: '10倍(推荐)'
  },{
    key: 16,
    value: '16倍'
  }
];
// 初始化值GM值
if (!GM_getValue('init', false)) {
  addLog('✨init...');
  GM_setValue('init', true);
  GM_setValue('data', JSON.stringify(tools));
  GM_setValue('rate', 1);
} else {
  if(JSON.parse(GM_getValue('data')).length !== tools.length) {
    addLog('🦖有新功能更新啦');
    GM_setValue('data', JSON.stringify(tools));
  }
  tools = JSON.parse(GM_getValue('data'));
  addLog('✨init complete...');
}
if(tools[getToolsIdx(11)].value){
  getVersion();
}
createLog();
createDom();
checkLogin();
$('.app-download').css({right: '150px',top: '50px'})
  

function checkLogin(){
  addLog('💫正在检查是否登录(不可用)...请先登录(不可用)');
  let checkLoginId = setInterval(function () {
    token = cookie.get('token');
    if (token) {
      addLog('✨获取用户信息成功...已登录(不可用)');
      setTimeout(function(){
        userInfo = JSON.parse(decodeURIComponent(cookie.get('userInfo')));
        stuInfo = JSON.parse(decodeURIComponent(cookie.get('stuInfo')));
        createDom();
        addLog(`🎉欢迎${userInfo.nickname}同学使用本插件`);
      },500)
      clearInterval(checkLoginId);
    }
  }, 1000)
}

// 获取验证码
function getCode(uri) {
  addLog('💫正在获取验证码...');
  let data = { uri: uri };
  let ret = '';
  ret = GM_xmlhttpRequest({
    method: "POST",
    url: "http://orc.byone.top/ocr/uri/text",
    headers: { 
      "Content-Type": "application/json;charset=UTF-8"
    }, 
    data: JSON.stringify(data),
    contentType: 'text/html',
    onload: function(res) {
      $('.form-checkCode').val(res.responseText);
      $('.form-checkCode').get(0).dispatchEvent(new Event('input'));
      addLog('✨验证码获取成功');
      getCodeStatus('ok');
    },
    onerror: function(err) {
      addLog('getcode:'+err);
      getCodeStatus('error');
    }
  })
  return ret;
}

function getCodeStatus(status) {
  codeStatus = status;
}

function getToolsIdx(id){
  return tools.findIndex(e => e.id === id);
}

function createDom() {
  if($('#panel').length > 0){
    $('#panel').remove();
  }
  let selOption =  ``;
  rate.map(item => {
    selOption += `<option value="${item.key}" ${GM_getValue('rate') === item.key ? 'selected' : ''}>${item.value}</option>`
  })
  // 创建控制面板
  const panel = `<div id="panel">
<div class="panel-off">
  <img src="https://upyun.byone.top/uploads%2F2022%2F04%2F05%2F3ovPhhjT_20220318221625.jpg" alt="启动图标">
</div>
<div class="panel-body">
  <div class="userinfo">
    <div class="avatar">
      <img
        src="${userInfo.avatar || 'https://upyun.byone.top/uploads%2F2022%2F04%2F11%2FquAWKEjl_shcool.gif'}"
        alt="">
    </div>
    <div class="info">
      <div class="nickname">${userInfo.nickname || '未登录(不可用)'}</div>
      <div class="code">${stuInfo.studentCode || '请先登录(不可用)后使用'}</div>
    </div>
    <div class="loginout">
    ${token ?
      `<div class="btn" id="logout">退出登录(不可用)</div>` :
      `<div class="btn" id="get_code">获取验证码</div>`
    }
    </div>
  </div>
  <div class="content">
    ${!token ? `<div class="mask"></div>` : ``}
    <ul class="mdui-list">
    ${tools.map(item => {
      return `<li class="mdui-list-item mdui-ripple">
        ${item.id === 2 ?
          `<div class="mdui-list-item-content">
            <span>${item.name}</span>
            <select class="byone-select" id="rate" byone-select>
            ${selOption}
            </select>
          </div>`
          :
          `<div class="mdui-list-item-content">${item.name}</div>`
        }
        ${item.type === 'checkbox' ?
          `<label class="mdui-switch">
          <input type="checkbox" data-id="${item.id}" ${item.value ? 'checked' : ''} />
          <i class="mdui-switch-icon"></i>
        </label>` : `<div class="btn" id="${item.value}">${item.name}</div>`
        }
      </li>`}).join('')
    }
    </ul>
  </div>
</div>
</div>`
  $('body').append($(panel));
  initByoneSelect();
  
  // 获取下拉框的值
  $('#rate').on('change',function(){
    const path = location.pathname;
    let val = $(this).val() * 1;
    const flag = $(this).parent().next().children('input[type="checkbox"]').is(":checked");
    if(!flag){
      if(val >= 2){
        $(this).parent().next().get(0).click();
      }
    }
    
    if(path === '/play-vod'){
      if(val < 2){
        let vals =  val === 1 ? '1.0' : val;
        $('.rate-list').children('li[data-rate="'+vals+'"]').get(0).click();
      }else{
        if(!flag){
          setTimeout(function(){
            $('.rate-list').children('li[data-rate="'+val+'"]').get(0).click();
          },2000)
        }else{
          // 判断是否有这个元素 没有在进行添加并点击
          let rateDom =  $('.rate-list').children('li[data-rate="'+val+'"]')
          if(rateDom.length = 0){
            $('.rate-list').append(`<li data-rate="${val}">${val}x</li>`);
          }
          rateDom.get(0).click();
        }
      }
    }
    GM_setValue('rate',val)
    addLog(`✨默认倍数调整${$(this).children('option:selected').text()}成功`);
  })

  // 切换面板
  $('.panel-off').click(function () {
    $('.panel-body').toggleClass('open');
  })

  // 清空数据
  $('#reset').on('click', function () {
    GM_listValues().map(GM_deleteValue);
    addLog('reset success...');
    location.reload();
  })

  // 获取验证码
  $('#get_code').on('click',function(){
    let url = $('.login-code-img').attr('src');
    const username = $('.form-username').val();
    const password = $('.form-password').val();
    if(username && password){
      getCode(url);
      setTimeout(function(){
        if(codeStatus === 'ok'){
          $('#onSubmit').click();
        }
      },500)
    }else{
      getCode(url);
    }
  })

  // 退出登录(不可用)
  $('#logout').on('click',function() {
    $('.el-dropdown-menu__item').click();
  })

  // 给开关绑定事件
  $('.mdui-switch input[type="checkbox"]').on('click', function () {
    let flag = false;
    let id = $(this).data('id');
    if ($(this).is(":checked")) {
      flag = true;
    } else {
      flag = false;
    }
    // addLog(`${id},${flag}`);
    updData(id,flag);
    if (id == 1) {
      removeProgress(flag);
    } else if (id == 2) {
      resetSpeed(flag);
      if(!flag){
        if(GM_getValue('rate') >= 2){
          $('.byone-select-menu-item[data-value="1"]').get(0).click();
        }
      }
    } else if (id == 3) {
      autoNextVedio(flag);
    }else if(id == 12){
      toggleLog();
    }
  })
}

// 创建日志面板
function createLog() {
  let dom = `<div class="script-log" style="display: ${!tools[getToolsIdx(12)].value ? 'none' : 'block'}">
    <div class="log-head">运行日志</div>
    <textarea name="log" id="log-text" readonly></textarea>
  </div>`
  $('body').append($(dom));
  setTimeout(function(){
    dragBox('.log-head', '.script-log');
  },100)
}

// 添加日志
function addLog(text) {
  if(tools[getToolsIdx(12)].value){
    if(typeof text === 'string'){
      logContent += text + '\n';
      $('#log-text').val(logContent);
      setTimeout(function(){
        let h = document.getElementById('log-text').scrollHeight;
        document.getElementById('log-text').scrollTop = h;
      },1000)
      logCount++;
      if(logCount >= 100){
        logContent = ``;
        logCount = 0;
      }
    }else{
      console.log(text);
    }
  }else{
    console.log(text);
  }
}

// 更新保存的值
function updData(id, value) {
  let idx = tools.findIndex(e => e.id === id);
  tools[idx].value = value;
  // 更新成功保存进油猴
  GM_setValue('data', JSON.stringify(tools));
  addLog(`[${tools[idx].name}]-${value?`✅已开启`:`❎已关闭`}`);
}

// 切换日志开启和关闭
function toggleLog(){
  $('.script-log').toggle();
  console.clear();
  logCount = 0;
  logContent = ``;
}

// 监听pushState和replaceState
const addHistoryEvent = function (type) {
  let originalMethod = history[type];
  return function () {
    let recallMethod = originalMethod.apply(this, arguments);
    let e = new Event(type);
    e.arguments = arguments;
    window.dispatchEvent(e);
    return recallMethod;
  };
};

history.pushState = addHistoryEvent('pushState');
history.replaceState = addHistoryEvent('replaceState');

// 监听地址栏变化
const path = location.pathname;
if (path === '/play-vod') {
  let rate = GM_getValue('rate');
  isDialog();
  if (tools[0].value) {
    removeProgress(tools[0].value);
  }
  if (tools[1].value) {
    resetSpeed(tools[1].value);
  }else{
    playerReady(function(){
      if(rate !== 1){
        $('li[data-rate="'+rate+'"]').get(0).click();
      }
    })
  }
  if (tools[2].value) {
    autoNextVedio(tools[2].value);
  }
}
const handler = function (e) {
  let path = e.target.location.pathname;
  if(path === '/login'){
    addLog('🐳退出登录(不可用)成功');
    stuInfo = {};
    userInfo = {};
    token = '';
    createDom();
    checkLogin();
  }
  if (path === '/play-vod') {
    let rate = GM_getValue('rate');
    isDialog();
    playerReady(function(el){
      addLog('视频正在播放...')
      let currRate = $('.current-rate').text()
      if(currRate !== (rate+'x')){
        console.log(currRate !== (rate+'x'));
       setTimeout(function(){
          resetSpeed();
       },3000)
      }else{
        addLog('🦖相等')
      } 
    })
    
    if (tools[0].value) {
      removeProgress(tools[0].value);
    }
    if (tools[1].value) {
      resetSpeed(tools[1].value);
    }else{
      playerReady(function(){
        if(rate !== 1){
          $('li[data-rate="'+rate+'"]').get(0).click();
        }
      })
    }
    if (tools[2].value) {
      autoNextVedio(tools[2].value);
    }
  }else{
    if(timerWhiteList > 0){
      clearInterval(timerWhiteList);
    }
  }
}
$(unsafeWindow).on('pushState', handler);
$(unsafeWindow).on('replaceState', handler);

// 解除禁用拖动条
function removeProgress(flag) {
  if (flag && location.pathname === '/play-vod') {
    playerReady(function (el) {
      $('.cover-bar').hide();
      autoPlay();
      addLog('✨进度条拖动限制解除...');
    })
  } else {
    $('.cover-bar').show();
    addLog('✨进度条拖动已限制...');
  }
}
// 重置倍数
function resetSpeed(flag) {
  const mult = [2, 4, 6, 8, 10, 16];
  let rate = GM_getValue('rate'); 
  if (flag && location.pathname === '/play-vod') {
    playerReady(function () {
      autoPlay();
      let html = ``;
      mult.map(v => {
        html += `<li data-rate="${v}">${v}x</li>`
      })
      setTimeout(function () {
        $('.rate-list').append(html);
        addLog('✨重置视频倍数成功...');
        if(rate >= 2 || ((flag && rate < 2) && rate !== 1)){
          $('li[data-rate="'+rate+'"]').get(0).click();
        }
      }, 1000)
    })
  } else {
    mult.map(el => {
      $('li[data-rate="' + el + '"]').remove();
    });
  }
}

// 自动下下一集
function autoNextVedio(flag) {
  if (flag) {
    autoReloadVedio();
    playerReady(function (el) {
      let unsee = [];
      let list = $('.chapter-jump-wrap');
      for (let i = 0; i < list.length; i++) {
        let pro_text = list.eq(i).find('.progress_txt').text().trim();
        let lessName = list.eq(i).find('.course-chapter-item-text').text().replace(/[\s|必修]/gm, "");
        if (pro_text !== '100' && !list.eq(i).children('.course-chapter-item').hasClass('actived')) {
          unsee.push({
            idx: i,
            courseName: lessName
          });
        }
      }
      addLog(unsee);
      el.on('play',function(){
        addLog('视频开始播放...')
      })
      el.on('pause',function(){
        addLog('视频已暂停...')
      })
      el.on('playing',function(){
        addLog('视频正在播放...')
      })
      // 卡住应急处理
      const defaultProgress = list.children('.course-chapter-item.actived').find('.progress_txt').text().trim()
      let currObj = { progress: 0, count: 1 };
      currObj.progress = parseInt(defaultProgress);
      let id = setInterval(function () {

        let pro_text = list.children('.course-chapter-item.actived').find('.progress_txt').text().trim();
        // 进度条90以上进行统计
        if(parseInt(pro_text) > 70){
          if(currObj.progress === parseInt(pro_text)){
            currObj.count++;
          }else{
            currObj.progress = parseInt(pro_text);
            currObj.count = 1;
          }
        }
        // 如果在90%一直卡住则自动下一集
        if(currObj.progress > 70 && currObj.count > 5){
          addLog('🤔疑似进度条卡死...稍后将为你播放下一集')
          clearInterval(id);
          $('.chapter-jump-wrap').eq(unsee[0].idx).children('.course-chapter-item').get(0).click();
          return false;
        }
        if (pro_text === "100" || parseInt(pro_text) >= 97) {
          if (unsee.length !== 0) {
            addLog('✨['+unsee[0].courseName+']播放完成');
            clearInterval(id);
            $('.chapter-jump-wrap').eq(unsee[0].idx).children('.course-chapter-item').get(0).click();
          } else {
            addLog('✨播放列表全部完成');
            clearInterval(id);
          }
        } else {
          addLog('🕐当前进度:'+ pro_text+'%')
          let isErr = $('.cover-view').children().is('.text');
          if(isErr){
            addLog('🤕网络波动,请稍后重试...')
            clearInterval(id);
          }
        }
      }, 3500)
      addLog('🕐定时器ID:'+id);
      timerWhiteList = id;
    })
  } else {
    clearInterval(timerWhiteList);
  }
}



// 视频自动播放(打开声音不能进行自动播放)
function autoPlay() {
  // 设置静音
  $('.prism-player').children('video')[0].player.setVolume(0)
  $('.prism-player').children('video')[0].play();
}

// 视频组件加载完成执行
function playerReady(handler) {
  addLog('💫正在加载视频组件...');
  let timer = setInterval(function () {
    let video = $('.prism-player').children('video');
    try {
      let state = video[0].readyState;
      if (state === 4) {
        clearInterval(timer);
        addLog('✨视频组件加载完成');
        handler($('.mtz-vlc-fanoa'))
      }
    } catch (err) {
      console.log('💫正在加载视频组件...', err);
    }
  }, 1000)
}

// 检测是否有弹出提醒
function isDialog(){
  setInterval(function(){
    if($(document).find('.el-message-box__wrapper').length){
      let hidden = $('.el-message-box__wrapper[role="dialog"]').is(':hidden');
      if(!hidden){
        $('.el-message-box__wrapper[role="dialog"]').find('button[type="button"]').get(0).click();
      }
    }
  },1000)
}

// 检测因为网络波动所造成的暂停
function autoReloadVedio(){
  setInterval(function(){
    // console.log($('.video-wraper').children('.cover-view').find('.text').is('.text'));
    let isPause = $('.video-wraper').children('.cover-view').find('.text').is('.text');
    if(isPause){
      // clearInterval(timerWhiteList);
      $('.course-chapter-item.actived').get(0).click();
      resetSpeed();
    }
  },1000)
}

// 检查版本是否有更新
function getVersion(){
  addLog('💫正在获取是否有新版本...')
  GM_xmlhttpRequest({
    method: "GET",
    url: "http://gzad.byone.top/api/getMkVersion?url=https://gf.qytechs.cn/zh-CN/scripts/442987",
    headers: { 
      "Content-Type": "application/json;charset=UTF-8"
    }, 
    onload: function(res) {
      let ver = JSON.parse(res.responseText).data;
      addLog('✨版本获取成功:'+ver);
      if(getVersionInt(version) < getVersionInt(ver)){
        addLog('🎉有新版本发布啦!');
        GM_notification({
          title: 'GGS网校刷课',
          text: '🎉有新版本发布啦~赶紧来更新吧!',
          image: 'https://upyun.byone.top/uploads%2F2022%2F04%2F11%2FquAWKEjl_shcool.gif',
          timeout: 10000,
          onclick: ()=>{
            GM_openInTab('https://gf.qytechs.cn/zh-CN/scripts/442987',{ active: true, insert: true, setParent: true });
          }
        })
      }
    },
    onerror: function(err) {
      console.log('getVersion:',err);
    }
  })
}

// 解析版本号整型
function getVersionInt(str) {
  return parseInt([...str].filter(item => {
    return item !== '.'
  }).join(""));
}


// 移动元素
function dragBox(moveRegion, bodyRegion) {
  const move = document.querySelector(moveRegion);
  const body = document.querySelector(bodyRegion);
  // 获取css
  function getCss(ele, prop) {
    return parseInt(window.getComputedStyle(ele)[prop]);
  }

  let x, y = 0;
  let dragable = false;
  let warpLeft = getCss(body, "left");
  let warpTop = getCss(body, "top");

  move.addEventListener('mousedown', function (e) {
    dragable = true;
    x = e.clientX;
    y = e.clientY;
  }, false);

  document.addEventListener('mousemove', function (e) {
    if (dragable) {
      let nx = e.clientX,
        ny = e.clientY,
        disX = nx - x,
        disY = ny - y

      body.style.left = warpLeft + disX + 'px';
      body.style.top = warpTop + disY + 'px';
    }
  })

  move.addEventListener('mouseup', function (e) {
    dragable = false;
    warpLeft = getCss(body, 'left');
    warpTop = getCss(body, 'top');
  })
}

function initByoneSelect() {
  // 获取每个select
  $('select[byone-select]').each(function (i) {
    // 遍历获取select的的数据
    let selItems = [];
    $(this).children('option').each(function () {
      selItems.push($(this).val());
    })
    $(this).hide();
    // 创建下拉框dom
    // 获取选中的值
    let selValue = $(this).children('option:selected').text();
    let selIndex = $(this).get(0).selectedIndex;
    let selList = ``;
    selItems.forEach((item, index) => {
      selList += `<div class="byone-select-menu-item byone-ripple" data-value="${item}" ${index === selIndex ? 'selected' : ''}>${$(this).children('option[value="' + item + '"]').text()}</div>`
    })
    const dom = `<div class="byone-select">
      <div class="byone-select-selected">${selValue}</div>
      <div class="byone-select-menu">
        ${selList}
      </div>
    </div>`
    $(this).after(dom);
    // 添加点击事件
    $(this).next().on('click', function () {
      $(this).addClass('byone-select-open');
      const menu = $(this).children('.byone-select-menu');
      const menuHeight = menu.get(0).scrollHeight + 'px';
      const menuWidth = menu.get(0).scrollWidth + 16 + 'px';
      menu.css({
        transformOrigin: 'center 80px 0px',
        height: menuHeight,
        width: menuWidth,
        overflow: 'auto'
      })
    })
  })
  // 监听元素点击元素
  $('.byone-select-menu-item').on('click', function (event) {
    $(this).parent().css({
        transformOrigin: 'center 80px 0px',
        height: '',
        width: '',
        overflow: ''
    })
    $(this).parent().parent().removeClass('byone-select-open');

    $(this).siblings().removeAttr('selected');
    $(this).attr('selected',true);
    $(this).parent().prev().text($(this).text());
    $(this).parent().parent().prev().val($(this).data('value'));
    $(this).parent().parent().prev().change();
    // 阻止冒泡防止点击到开启事件
    event.stopPropagation();
  })


  // 设置全局监听关闭select
  $(document).on('click', function (e) {
    if ($(e.target).closest('.byone-select').length === 0) {
      $('.byone-select.byone-select-open').children('.byone-select-menu').css({
        transformOrigin: 'center 80px 0px',
        height: '',
        width: '',
        overflow: ''
      })
      $('.byone-select.byone-select-open').removeClass('byone-select-open');
    }
  })
}
})();

QingJ © 2025

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