吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 43230|回复: 157
收起左侧

[其他转载] 职教书签:职教云(智慧职教)网课一键刷完,无需油猴,一个浏览器书签搞定(开源纯js

    [复制链接]
dnvc 发表于 2020-6-28 15:08
本帖最后由 dnvc 于 2020-12-23 22:33 编辑

职教云(智慧职教)网站:https://zjy2.icve.com.cn/
职教书签官网(开源):https://zj.miya.ink


此刷课脚本至目前(12月)仍然有效因为职教云未重构课程进度计算的流程);
但是由于刷课人数过多,职教云现在会封禁学习速率过快的账号(从几十分钟到几小时不等),所以使用时常常会遇到:刷了一两个课,突然无法获取令牌的情况。如遇此情况请等待封禁结束,即可继续使用。

此脚本编写于4月份,在6月底公布;由于刷课速度无与伦比,使用至今肯定已被官方发觉,望各位学子耗子尾汁。


一句话简介:

一键刷完职教云(智慧职教)所有课程,随机生成学习时间。
支持所有类型:视频、ppt...等等

支持移动端,手机浏览器也能用
支持浏览器开多个标签同时刷多个课(只要每个页面都运行一遍职教书签即可)

2020年6月30日
更新:可以手动设置跳过已看多少进度的课程了

  • 请手动清除浏览器缓存以更新书签

我需要做什么?

你无需安装任何浏览器插件,你需要做的只是把代码添加到浏览器书签(收藏夹),然后在课程页面单击运行它。


新功能补图(2020年6月30日):

输入跳过指定进度:

new.png

newt.png


1、先上效果图

98.png

99.png

100.png

101.png


2、使用方法

将下面这行代码复制,添加到浏览器书签栏:

javascript:(function(){function getZjsq(){let s=document.createElement("script");s.src="https://zj.miya.ink/zjsq_v3.js";s.onerror=function(){alert("加载失败!请到职教书签官网(https://zj.miya.ink/)获取最新书签!")};document.body.appendChild(s)};getZjsq()}());

添加方法(如chrome):

打开书签管理器,添加新书签。
在这里插入图片描述

粘贴代码,保存。

在这里插入图片描述

添加完毕,之后就按照演示图那样运行即可。


3、原理

逆向分析职教云网页代码,通过运行javascript构造与职教云页面相同的请求,增加课程进度。


4、源代码

以下是职教书签v3的完整源代码,后续请在 https://zj.miya.ink 获取最新代码

使用源代码?

  • 你可以将源代码复制,按F12打开浏览器开发者工具,在控制台中直接粘贴代码并回车。这等同于从浏览器书签运行职教书签。
  • 如果提示无法从官网获取到书签,请像我上面说的这样做,即可继续使用了。
/*

职教书签v3

date: 2020年6月30日
version: 0.2.0
author: Pure-Peace

*/

// vars --------------------------------
const hrefs = []
const arrowDown = 'am-icon-caret-down'
const cl = 'class'
const sp = 'span'
const st = setTimeout
var zjsqInfoDom
var currentLessonIndex = 0
var lessonFailed = 0
var totalStudyTime = 0
var losingStreak = 0
var stopFlag = false
var skipProgress = 0
var totalLessons = 0

// funcs --------------------------------
function main () {
  try {
    const input = prompt('[职教书签v3] 跳过已学进度超过百分之几的课程?\n\n输入百分比,但是不要输入百分号\n如:90\n\n输入100或者更大的数字就不会跳过任何课程:', '90') || '100'
    skipProgress = parseInt(input.replace(/[^0-9]/ig, '')) || 100
    // fetch global datas
    log('开始获取课件数据!')
    globalDataHander()
    // get datas
    st(() => {
      log('正在准备刷取学习进度及时间的必要信息...')
      // started
      directoryDataRequester(0)
    }, 12000)
    return 'started'
  } catch (e) {
    log('主程序异常,可能无法正常工作:' + e)
  };
};

function log (text) {
  const info = `[${new Date().format()}] ${text}`
  console.log(info)
  zjsqInfoDom.append(info + '<br>')
  var ele = zjsqInfoDom[0]
  ele.scrollTop = ele.scrollHeight + 999
};

function initial () {
  // 请保持这种格式,否则getText函数无法从注释中正确提取此处的css
  function zjsqCss () {/*
.zjsqInfoBox {
    width: 700px;
    height: 450px;
    background-color:white;
    position:absolute;
    top:50%;
    left:50%;
    transform:translateX(-50%) translateY(-50%);
    -moz-transform:translateX(-50%) translateY(-50%);
    -webkit-transform:translateX(-50%) translateY(-50%);
    -ms-transform:translateX(-50%) translateY(-50%);
    border-radius:5px;
    z-index: 9999;
    box-shadow: 3px 3px 10px rgba(0,0,0,.2);
    padding: 20px;
}

.zjsqTitle {
    font-weight: bold;
    font-size: 16px;
    width: 100%;
    text-align: center;
}

#zjysqInfo {
    border-radius: 4px;
    margin-top: 15px;
    padding: 15px;
    width: 100%;
    height: 370px;
    word-wrap: break-word;
    overflow-y: scroll;
    font-size: 14px;
    color: #FAFAFA;
    background-color: rgba(0,0,0,.8);
} */
  };

    // 请保持这种格式,否则getText函数无法从注释中正确提取此处的html
  function zjsqHtml () {/*
<div id="zjsqInfoBoxId" class="zjsqInfoBox">
    <div class="zjsqTitle">职教书签 v3 Beta2</div>
    <div id="zjysqInfo">
        -time-欢迎使用职教书签~! | 官网:<a  target="_blank">https://zj.miya.ink</a>(开源)<br>
        -time-开始初始化...请勿随意操作页面...<br>
    </div>
</div> */
  };

  function getText (func) {
    var str = func.toString().split('\n')
    str = str.slice(1, str.length - 1).join('\n')
    return str.replace(/-time-/g, `[${new Date().format()}] `)
  };

  function makeDivDraggable (id) {
    var Drag = document.getElementById(id)
    Drag.onmousedown = function (event) {
      var ev = event || window.event
      event.stopPropagation()
      var disX = ev.clientX - Drag.offsetLeft
      var disY = ev.clientY - Drag.offsetTop
      document.onmousemove = function (event) {
        var ev = event || window.event
        Drag.style.left = ev.clientX - disX + 'px'
        Drag.style.top = ev.clientY - disY + 'px'
        Drag.style.cursor = 'move'
      }
    }
    Drag.onmouseup = function () {
      document.onmousemove = null
      this.style.cursor = 'default'
    }
  };

  try {
    console.log('职教书签 v3 beta2 | 官网:https://zj.miya.ink')
    console.log('开始初始化...请勿随意操作页面...')
    Date.prototype.format = function () {
      var format = 'yyyy-MM-dd HH:mm:ss'
      var o = {
        'M+': this.getMonth() + 1, // month
        'd+': this.getDate(), // day
        'H+': this.getHours(), // hour
        'm+': this.getMinutes(), // minute
        's+': this.getSeconds(), // second
        'q+': Math.floor((this.getMonth() + 3) / 3), // quarter
        S: this.getMilliseconds() // millisecond
      }

      if (/(y+)/.test(format)) {
        format = format.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length))
      };

      for (var k in o) {
        if (new RegExp('(' + k + ')').test(format)) {
          format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length))
        };
      };
      return format
    }
    $('<style></style>').text(getText(zjsqCss)).appendTo($('head'))
    $('body').append(getText(zjsqHtml))
    makeDivDraggable('zjsqInfoBoxId')
    zjsqInfoDom = $('#zjysqInfo')
    return true
  } catch (e) {
    log('初始化控制台框架异常:' + e)
    return false
  };
};

function hrefParamsToArray (url) {
  return url
    .substring(url.indexOf('?') + 1)
    .split('&')
    .map((query) => query.split('='))
    .reduce((params, pairs) => (params[pairs[0]] = pairs[1] || '', params), {})
};

function studyProcessRequester (data) {
  function getProcessText () {
    return `[${new Date().format()}] 完成进度:(${totalCount}/${randomRequestTimes}) / 成功数:${successCount} / 失败数:${failedCount}`
  };

  if (stopFlag === true) return 0
  var lessonId = `lesson${currentLessonIndex}`
  var successCount = 0
  var failedCount = 0
  var totalCount = 0
  var randomRequestTimes = Math.floor((Math.random() * 87) + 56)
  const requestData = {
    courseOpenId: data.courseOpenId,
    openClassId: data.openClassId,
    cellId: data.cellId,
    cellLogId: data.cellLogId,
    picNum: Math.round(324 / randomRequestTimes),
    studyNewlyTime: Math.round(14640 / randomRequestTimes),
    studyNewlyPicNum: Math.round(324 / randomRequestTimes),
    token: data.guIdToken
  }
  log(`第(${currentLessonIndex}/${hrefs.length})课,课件:${data.cellName},类型:[${data.categoryName}]`)
  log(`本次随机学习时间:${(randomRequestTimes * 10 / 60).toFixed(2)}分钟 总请求次数:${randomRequestTimes}`)
  log('现在开始上课!')
  zjsqInfoDom.append(`<div id="${lessonId}">${getProcessText()}</div>`)
  var ele = zjsqInfoDom[0]
  ele.scrollTop = ele.scrollHeight + 999
  var lessonProcessDom = $(`#${lessonId}`)
  for (let i = 0; i < randomRequestTimes; i++) {
    var defer = $.Deferred()
    $.ajax({
      async: true,
      timeout: 5000,
      type: 'post',
      url: urls2.Directory_stuProcessCellLog,
      data: requestData,
      dataType: 'json',
      success: function (responseData) {
        successCount += 1
      },
      error: function (response) {
        failedCount += 1
      },
      complete: function (response) {
        totalCount += 1
        lessonProcessDom.text(getProcessText())
        if (totalCount === randomRequestTimes) {
          totalStudyTime += randomRequestTimes * 10
          log(`当前课程(${lessonId}),已完成学习!三秒后开始下一课程...`)
          st(function () {
            return directoryDataRequester(currentLessonIndex)
          }, 4000)
        };
      }
    })
    requestData.picNum += Math.round(300 / randomRequestTimes)
    requestData.studyNewlyTime += Math.round(12640 / randomRequestTimes)
    requestData.studyNewlyPicNum += Math.round(300 / randomRequestTimes)
  };
  return defer
};

function directoryDataRequester (hrefIndex, changeDirectory = false, addData = false) {
  if (stopFlag === true) return 0
  var changedFlag = false
  if (hrefIndex < hrefs.length) {
    currentLessonIndex = hrefIndex + 1
    if (!addData && changeDirectory !== true) log(`正在获取课件(${currentLessonIndex}/${hrefs.length})的请求令牌...`)
    var requestData = hrefParamsToArray(hrefs[hrefIndex])
    if (addData) {
      Object.assign(requestData, addData)
      console.log(requestData)
      delete (requestData.flag)
    };
    var defer = $.Deferred()
    $.ajax({
      async: true,
      timeout: 5000,
      type: 'post',
      url: changeDirectory ? urls2.Directory_changeStuStudyProcessCellData : urls2.Directory_viewDirectory,
      data: requestData,
      dataType: 'json',
      success: function (responseData) {
        if (changeDirectory === true) {
          log('课程切换成功!即将重新请求令牌...')
          changedFlag = false
          return directoryDataRequester(hrefIndex)
        };
        if (responseData.code === 1) {
          log('令牌获取成功!准备就绪...')
          losingStreak = 0
          return studyProcessRequester(responseData)
        } else if (responseData.code === -100) {
          if (changedFlag === true) {
            log('课程切换失败,将跳过此课程...')
            failedHandler(responseData)
          } else {
            log('收到职教云提示切换课程...准备切换...')
            changedFlag = true
            changeDirectory = true
            addData = {
              cellName: responseData.currCellName,
              moduleId: responseData.currModuleId
            }
            return directoryDataRequester(hrefIndex, changeDirectory, addData)
          };
        } else {
          failedHandler(responseData)
        };
      },
      error: function (response) {
        log(`令牌获取失败!跳过此课程,直接开始下一课:(${currentLessonIndex})`)
        console.log(response)
        lessonFailed += 1
        losingStreak += 1
        if (losingStreak > 3) {
          exitHander(-1)
        } else {
          directoryDataRequester(currentLessonIndex)
        };
      }
    })
    return defer
  } else {
    exitHander(1)
  };
};

function exitHander (status) {
  if (status === -1) {
    stopFlag = true
    const text = '由于令牌请求连续失败超过三次,所以书签将停止工作!请等待一段时间后再次使用!'
    log(text)
    alert(text)
  };
  const result = `本次共学习了${currentLessonIndex}个课件,成功数:${hrefs.length - lessonFailed},失败数:${lessonFailed},计算总学习时间约为:${(totalStudyTime / 60).toFixed(2)}分钟!`
  log('**********学习结束!**********')
  log(result)
  if (status !== -1) alert('学习结束!' + result)
  $('#zjsqInfoBoxId').click(function () {
    $('#zjsqInfoBoxId').remove()
  })
  log('感谢您使用职教书签 v3!现在单击本窗口即可关闭。')
};

function globalDataHander () {
  // get modules
  log('正在获取课件模块数据(1/3)...')
  $('.moduleList').each(function () {
    const that = $(this).children('div').get(0)
    if ($($(that).children(sp).get(1)).attr(cl).search(arrowDown) === -1) that.click()
  })
  // get children modules
  st(() => {
    log('正在获取课件详细数据(2/3)...')
    $('tr.openOrCloseTopic').each(function () {
      if ($($(this).find(sp).get(0)).attr(cl).search(arrowDown) === -1) $(this).click()
    })
  }, 3000)
  // get links

  st(() => {
    log('正在获取所有课件链接(3/3)...')
    $('a.isOpenModulePower').each(function () {
      totalLessons += 1
      if (skipProgress >= 100 || (parseInt($(this).prev().attr('title').replace(/[^0-9]/ig, '')) < skipProgress)) {
        hrefs.push($(this).attr('data-href'))
      };
    })
    log('已获取所有课件链接!课件总数:' + totalLessons)
    log('根据您的设置,' + (skipProgress < 100 ? `将跳过学习进度大于${skipProgress}%的课程:跳过了${totalLessons - hrefs.length}课` : '本次将学习所有课程'))
    log(`即将学习的课程数量为:${hrefs.length}`)
  }, 8000)
};

// go
if (initial() === true) {
  main()
} else {
  alert('程序初始化异常,请查看控制台错误信息!')
};

5、更多想说的

可以识别已经看完的课程并跳过,但是由于我想重复刷取学习时间,并没有这么做。
你可以自行修改代码。

2020年6月30日
已更新:可以手动设置跳过已看多少进度的课程了


结束

免费评分

参与人数 38吾爱币 +34 热心值 +36 收起 理由
j8漫天飞 + 1 + 1 谢谢@Thanks!
三分热度. + 1 谢谢@Thanks!
KAF + 1 + 1 谢谢@Thanks!
vbnewer + 1 + 1 谢谢@Thanks!
清风明月0 + 1 谢谢@Thanks!
菌小酱 + 1 + 1 我很赞同!
晓乐 + 1 我很赞同!
丶熊小憨 + 1 2021-01-16 已经被检测出刷课行为
hjhj525 + 1 + 1 我很赞同!
lingy24 + 1 + 1 一直在请求令牌
晚辈小生 + 2 + 1 2020年12月22日 JS报错 无法正常使用 望修复
吾爱丶感情 + 1 我很赞同!
秋刀不是鱼 + 1 2020-12-20 已经被检测出刷课行为
时光带走了纯真 + 1 + 1 2020-12-20 已经被检测出刷课行为
216794066yhb + 1 + 1 我很赞同!
zedong + 2 + 1 2020-12-11亲测可用!!
2211326847 + 1 + 1 谢谢@Thanks!
大雄的机器猫 + 1 + 1 谢谢@Thanks!
fangsongzi + 1 + 1 谢谢@Thanks!
邪汐 + 1 + 1 谢谢@Thanks!
我来白嫖 + 1 + 1 我很赞同!
油桶 + 1 + 1 2020/11/19 19:51亲测可用,感谢分享。吾爱有你更精彩!
挂机的残梦 + 1 + 1 谢谢@Thanks!
半个勺子 + 1 + 1 谢谢@Thanks!
尘网 + 1 + 1 谢谢@Thanks!
HoDada + 2 + 1 谢谢@Thanks!
进击的三胖次 + 1 + 1 谢谢@Thanks!
popyey + 1 + 1 我很赞同!
ltxhhz + 1 + 1 用心讨论,共获提升!
haimiandashu + 1 + 1 用心讨论,共获提升!
18523237379 + 1 + 1 这种会不会被封号或者处罚呢?
xiao小峰 + 1 + 1 谢谢@Thanks!
yinyu + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
m明明m + 1 + 1 谢谢@Thanks!
坏小子69 + 1 + 1 谢谢 @Thanks!
yxdyxd163 + 1 谢谢@Thanks!
lin文 + 1 我很赞同!
大鸽鸽 + 1 谢谢楼主分享 学习学习

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

李某某i 发表于 2021-11-5 20:08
可以更新一下吗。大佬。刷2节课就被封30分钟。。
 楼主| dnvc 发表于 2020-7-30 03:24
chhzll 发表于 2020-7-28 14:38
这么玩 时间问题 大更新只是时间问题

小问题,一个下午时间写的玩具
学无止境no1 发表于 2020-7-10 10:48
dnvc 发表于 2020-7-8 17:58
有图片不?昨晚十点之后服务应该挂了,现在应该没问题,清理浏览器缓存试试

一直在获取课件的请求令牌,tingyun-rum.js:1 Uncaught TypeError: Cannot read property 'substring' of undefined
    at hrefParamsToArray (<anonymous>:171:6)
    at directoryDataRequester (<anonymous>:245:23)
    at <anonymous>:38:7
    at r (tingyun-rum.js:1)
时光书窝 发表于 2020-6-28 15:19
哇塞,前排支持大佬!
大鸽鸽 发表于 2020-6-28 15:32
这个开源厉害了。 学校学习
lin文 发表于 2020-6-28 15:34
感谢分享,可以同时开两个窗口刷嘛?
星辰公子 发表于 2020-6-28 15:45
楼主这个就很给力了
我替用了又不太擅长表达的
说一声谢谢
yxdyxd163 发表于 2020-6-28 15:48
感谢 分享。 。学习学习。
 楼主| dnvc 发表于 2020-6-28 16:01
lin文 发表于 2020-6-28 15:34
感谢分享,可以同时开两个窗口刷嘛?

可以的,就不知道请求量太大会不会给你冷静一下。。
xxscwsrym 发表于 2020-6-28 16:14
留个脚印
9981难 发表于 2020-6-28 16:37

100CB 大佬可帮做一下其他平台吗?我要帮同事一起学习。随机不定时出现弹窗,要上4个号的我头很大
任逍遥 发表于 2020-6-28 20:43
云端学习(时代光华),这个能快进吗?还有好多节课,一节节刷,要累死人
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 07:12

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表