未验证 提交 006f5020 编写于 作者: F freedownzhou 提交者: GitHub

Merge pull request #3 from CodFrm/master

merge codfrm
---
name: 错误反馈
about: 反馈错误给我们
name: BUG反馈
about: 将你所遇到的BUG反馈给我们
---
**错误描述**
你所遇到的错误是怎么样的?最好提供错误截图
**错误提示**
有没有错误的提示,没有不填写(在浏览器中f12打开开发者工具,console的错误提示)
**错误提示和日志内容**
有没有错误的提示,和日志的内容(在浏览器中f12打开开发者工具,console的错误提示,日志内容在Filter中填入cxmooc,然后全部复制上来)
**出现时间**
你是怎么操作出现的这个错误?
你是怎么操作出现的这个错误?能不能复现呢?(再次出现)
**错误版本**
你的浏览器版本和扩展的版本
你的浏览器版本和扩展的版本,油猴,Chrome,还是火狐?
node_modules
build/cxmooc-tools/src/*.*
build/tampermonkey.js
build/*.js
docs/.vuepress/dist/
.vscode/
coverage
typings
typings.json
......
......@@ -10,28 +10,57 @@ dist: xenial
node_js: stable
cache:
# yarn: true
directories:
- node_modules
- npm
before_install:
- export TZ='Asia/Shanghai'
- openssl aes-256-cbc -K $encrypted_b7d8153e3775_key -iv $encrypted_b7d8153e3775_iv -in ./build/cxmooc-tools.pem.enc -out ./build/cxmooc-tools.pem -d
- npm install
- export TZ='Asia/Shanghai'
- openssl aes-256-cbc -K $encrypted_b7d8153e3775_key -iv $encrypted_b7d8153e3775_iv -in ./build/cxmooc-tools.pem.enc -out ./build/cxmooc-tools.pem -d
- npm install
script:
- npm run pack
- cd build/cxmooc-tools && zip ../cxmooc-tools.zip -r ./
- npm run docs:build
- npm run build
- npm run tampermonkey
- npm run pack
- cd build/cxmooc-tools && zip ../cxmooc-tools.zip -r ./ && cd ../../
deploy:
provider: releases
api_key: $GITHUB_TOKEN
file_glob: true
file:
- build/tampermonkey.js
- build/*.crx
- build/*.zip
skip_cleanup: true
# draft: true
on:
tags: true
\ No newline at end of file
- provider: releases
api_key: $GITHUB_TOKEN
file_glob: true
file:
- build/tampermonkey.js
- build/*.crx
- build/*.zip
skip_cleanup: true
on:
tags: true
- provider: pages
skip_cleanup: true
committer-from-gh: true
github_token: $GITHUB_TOKEN
local_dir: docs/.vuepress/dist
keep-history: true
target-branch: gh-pages
on:
branch: master
- provider: script
script: node src/tg-bot.js
skip_cleanup: true
on:
all_branches: true
condition: $TRAVIS_BRANCH =~ ^hotfix|develop$
- provider: script
script: node src/tg-bot.js
skip_cleanup: true
on:
tags: true
- provider: npm
email: $NPM_EMAIL
api_key: $NPM_KEY
on:
tags: true
......@@ -3,21 +3,39 @@
![GitHub All Releases](https://img.shields.io/github/downloads/codfrm/cxmooc-tools/total.svg)
![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/codfrm/cxmooc-tools.svg?label=version)
## 超星慕课小工具
> 一个快速学习超星慕课的chrome扩展工具(੧ᐛ੭挂科模式,启动)
>
> 已经发布了一个属于油猴的脚本[油猴安装](#油猴安装),火狐浏览器也可以支持了!
>
> 初次开发chrome扩展,有兴趣的朋友可以一起来哦,欢迎PR!
## 关于超星慕课小工具
> **[使用文档](https://cx-doc.xloli.top/)**
## 准备工作
> 如果你想参与开发,请阅读下面内容,如果只是使用本插件,请直接跳转到[安装](#安装)
一个超星(学习通)和智慧树(知到)刷课工具,火狐,谷歌,油猴支持.全自动任务,视频倍速秒过,作业考试题库,验证码自动打码(੧ᐛ੭挂科模式,启动)
### Build
环境:
### 浏览器适配列表
* [x] Chrome for PC
* [x] Firefox for PC
* [x] Firefox for Mobile
* [x] QQ 浏览器 for PC
* [x] Tampermonkey
### 功能支持列表
> 详情请看使用文档
* [x] 视频挂机
* [x] 视频秒过
* [x] 视频倍速
* [x] 静音播放
* [x] 任务答题
* [x] 自动阅读
* [x] 自动填写验证码
* [x] 考试答题
* [x] 作业答题
## 参与开发
> 如果你想参与开发,请阅读下面内容,如果只是使用本插件,请移步 **[使用文档](https://cx-doc.xloli.top/)**
### 环境:
* Node.js
* webpack
### Build
```bash
git clone https://github.com/CodFrm/cxmooc-tools.git
cd cxmooc-tools
......@@ -25,112 +43,53 @@ npm install
npm run build
# 开发模式请使用
npm run dev
# 打包生成crx和油猴
# 打包生成crx和油猴脚本
npm run pack
```
### Server
> 搭建了一个服务器程序,这个服务器用于完善题库。由于接口没有任何权限,所以只会记录你的正确答题答案,并不会记录你的其他个人信息。以上过程全由插件自动提交,还请大家不要故意上传错误的答案哦 (๑• . •๑)
>
> 因为超星慕课全站启用了https,所以服务器配置需要https。
环境:
* Node.js
* Mongodb
> 搭建了一个服务器程序用于完善题库。接口没有任何权限,只会记录正确答题答案,并不会记录其他信息。
> 以上过程全由插件自动提交,还请大家不要故意上传错误的答案哦 (๑• . •๑)
> 因为超星慕课全站启用了`https`,所以服务器配置需要`https`。
```bash
npm install
npm run server
```
## 安装
### 油猴安装
> 2.0.0之后油猴可以在源码中修改配置,支持全部的功能啦
### 贡献流程
1. `Fork Repo`
2. 发起`Pull Request`,并简要描述更改内容。
3. `Travis CI 检查通过`
4. `CodeReview`
5. 合并到项目仓库
地址链接:[https://greasyfork.org/zh-CN/scripts/376190-cxmooc-tools](https://greasyfork.org/zh-CN/scripts/376190-cxmooc-tools)
### 火狐安装
> 发布了火狐的版本
扩展地址:[https://addons.mozilla.org/zh-CN/firefox/addon/%E8%B6%85%E6%98%9F%E6%85%95%E8%AF%BE%E5%B0%8F%E5%B7%A5%E5%85%B7/](https://addons.mozilla.org/zh-CN/firefox/addon/%E8%B6%85%E6%98%9F%E6%85%95%E8%AF%BE%E5%B0%8F%E5%B7%A5%E5%85%B7/)
### 方法1:
> 能够体验到最新的功能,需要按照[准备工作](#准备工作)的方法步骤配置本地环境,可能会存在一些BUG。
1. 执行`npm run build`,此时会在`build/cxmooc-tools`目录下生成插件文件。
2. 打开Chrome浏览器的更多工具选项,打开扩展程序页面并启用开发者模式。
3. 加载已解压的扩展程序,路径选择`build/cxmooc-tools`
### 方法2(推荐):
下载发布的版本[cxmooc-tools.crx](https://github.com/CodFrm/cxmooc-tools/releases)无需安装环境,下载即可使用。
1. 下载发布的版本cxmooc-tools.crx文件,修改后缀为.zip,并将其解压到目录`cxmooc-tools`
2. 打开Chrome浏览器的更多工具选项,打开扩展程序页面并启用开发者模式。
3. 加载已解压的扩展程序,路径选择你解压的路径`cxmooc-tools/`
解压后`cxmooc-tools`目录应包含以下文件
```
.
├── img
| └── some files
├── src
| └── some files
└── manifest.json
```
**以Chrome浏览器为例:**
![](build/cxmooc-tools/img/1.png)
![](build/cxmooc-tools/img/2.png)
加载完成后,打开超星慕课的课程或者题目页面之后就可以正常使用了。
### 方法3:
下载[发布版本](https://github.com/CodFrm/cxmooc-tools/releases)cxmooc-tools.crx文件,直接拖入浏览器安装
某些浏览器允许直接拖入扩展进行安装。(内核为Chromium,如果不行,请按照方法2来)
支持列表
* [x] 360极速浏览器
* [x] QQ浏览器
...
## 说明
使用已安装扩展插件的浏览器打开超星慕课学习页面,在视频上方会显示相关功能按钮。扩展图标点击可展示配置项目,将鼠标放在配置项上可以看见配置详情。
油猴版本请打开源码查看,config中修改配置值
**秒过视频**功能可直接将视频看完,但是**有一定的风险**
## 题库
1. 题库大部分答案来源于用户答题后的页面采集,**所以需要有人第一次做过**,后来的人才能搜索到题目。
2. 可以配置随机题目,当题库中没有的题目则会自动随机选择一个选项
3. 考试题库收集,需要考试完毕后,进入考试答案页面,插件会自动收集.
**[注意]**某些多核浏览器默认使用**兼容模式**,需要切换到**极速模式**才能使用
题库记录提示:
插件功能:(勾为已实现的功能,空为将更新的内容)
* [x] 刷课挂机
* [x] 视频秒过
* [x] 视频加速
* [x] 视频静音
* [x] 自动答题
* [x] 自动阅读
* [ ] 视频内题目填充
* [ ] 考试答题
![](/dist/images/3.webp)
...
## 关于反馈
您可以通过Issues反馈,反馈时请尽量提供足够明确的信息。
![](/build/cxmooc-tools/img/soft/soft_01.png)
![](/build/cxmooc-tools/img/soft/soft_02.png)
### 题库
## 其他
GitHub项目地址:[https://github.com/CodFrm/cxmooc-tools](https://github.com/CodFrm/cxmooc-tools)
关于题库,可以访问该页面:[https://github.com/CodFrm/cxmooc-tools/issues/16](https://github.com/CodFrm/cxmooc-tools/issues/16)
Blog地址:[http://blog.icodef.com/2018/01/25/1304](http://blog.icodef.com/2018/01/25/1304)
1. 不定期的更新题库文件,因为没有手动的去收集题目,所以大部分题目**需要有人第一次做过**,后来的人才能搜索到题目。
2. 可以配置随机题目,当题库中没有的题目则会自动随机选择一个选项
[telegram群组](https://t.me/joinchat/MHU8Gg2fP3Q51HLY2wqmQA)
题库自动收集提示:
![](/build/cxmooc-tools/img/3.png)
[QQ群614202391](https://shang.qq.com/wpa/qunwpa?idkey=9bddd2564d84bd999940de422d1c0c70f87ecaf02fe9d7c60389fc2b376179eb)
## 其他
## 免责声明
本项目完全开源,免费,仅供技术学习和交流,**开发者团队并未授权任何组织、机构以及个人将其用于商业或者盈利性质的活动。也从未使用本项目进行任何盈利性活动。未来也不会将其用于开展营利性业务。个人或者组织,机构如果使用本项目产生的各类纠纷,法律问题,均由其本人承担。**
GitHub项目地址:[https://github.com/CodFrm/cxmooc-tools](https://github.com/CodFrm/cxmooc-tools)
如果您开始使用本项目,即视为同意项目免责声明中的一切条款,条款更新不再另行通知。**开发者仅接受和捐赠者之间不构成购买或雇佣关系的捐赠或者赞赏。** 如果您选择捐赠此项目,我们会列出一份捐赠者名单(包含捐赠金额,日期),但不会公布您的捐赠账号。如果您选择捐赠,那么我将视之为您完全自愿的,没有任何雇佣,购买关系的捐赠。
Blog地址:[http://blog.icodef.com/2018/01/25/1304](http://blog.icodef.com/2018/01/25/1304)
The project is completely open source, free, and is for technical learning and communication only. **The developer team does not authorize any organization, organization, or individual to use it for commercial or profitable activities. Never use this project for any profitable activities. It will not be used for profit-making business in the future. Individuals or organizations and organizations that use the various disputes arising from the project and legal issues shall be borne by themselves.**
QQ群:[614202391](https://shang.qq.com/wpa/qunwpa?idkey=9bddd2564d84bd999940de422d1c0c70f87ecaf02fe9d7c60389fc2b376179eb)
\ No newline at end of file
If you start using this project, you are deemed to agree to all the terms in the project disclaimer, and the terms are updated without further notice. **Developers only accept donations or appreciations that do not constitute a purchase or employment relationship with the donor.** If you choose to donate this item, we will list a list of donors (including donation amount, date), but will not announce your donation account. If you choose to donate, then I will treat you as completely voluntary, without any employment, donation of the relationship.
\ No newline at end of file
{
"manifest_version": 2,
"name": "超星慕课小工具",
"version": "2.0.1",
"version": "2.1",
"description": "用于超星慕课的小工具",
"icons": {
"16": "img/logo.png",
......@@ -31,7 +31,12 @@
"*://*/work/doHomeWorkNew?*",
"*://*/work/selectWorkQuestionYiPiYue?*",
"*://*/exam/test/reVersionTestStartNew?*",
"*://*/ztnodedetailcontroller/visitnodedetail?*"
"*://*/ztnodedetailcontroller/visitnodedetail?*",
"*://*/antispiderShowVerify.ac*",
"*://*/html/processVerify.ac?*",
"*://study.zhihuishu.com/learning/videoList*",
"*://*/exam/test/reVersionPaperMarkContentNew?*",
"*://examh5.zhihuishu.com/stuExamWeb.html*"
],
"js": [
"src/start.js"
......
文件已添加
文件已添加
文件已添加
文件已添加
......@@ -5,4 +5,10 @@ services:
image: mongo
container_name: cx_db
ports:
- 27017:27017
\ No newline at end of file
- 27017:27017
redis:
image: redis
container_name: cx_redis
ports:
- 6379:6379
// module.exports = {
// configureWebpack: {
// resolve: {
// alias: {
// '@alias': '.vuepress/img'
// }
// }
// }
// }
module.exports = {
title: '超星慕课小工具',
base: '/',
themeConfig: {
nav: [
{ text: '首页', link: '/' },
{
text: '使用教程',
items: [
{ text: '开始', link: '/1-UserGuide/' },
{ text: 'Chrome 扩展', link: '/1-UserGuide/1-1-chrome.html' },
{ text: 'FireFox 扩展', link: '/1-UserGuide/1-2-firefox.html' },
{ text: 'Tampermonkey 脚本', link: '/1-UserGuide/1-3-tampermonkey.html' },
{ text: '功能说明', link: '/1-UserGuide/featured.html' },
{ text: '配置说明', link: '/1-UserGuide/1-4-config.html' }
]
},
{ text: '免责声明', link: '/3-Disclaimer/' },
{ text: '捐赠', link: '/4-Reward/' },
{
text: '语言选项',
items: [
{ text: '简体中文', link: '/' },
{ text: 'English', link: '/en-us/' }
]
},
//{ text: 'Github', link: 'https://github.com/CodFrm/cxmooc-tools' },
],
// sidebar: 'auto',
sidebar: {
'/1-UserGuide/': [
'',
'1-0-developer.html',
'1-1-chrome.html', /* /foo/ */
'1-2-firefox.html', /* /foo/one.html */
'1-3-tampermonkey.html',
'featured.html',
'1-4-config.html'
],
},
serviceWorker: {
updatePopup: true, // Boolean | Object, 默认值是 undefined.
// 如果设置为 true, 默认的文本配置将是:
// updatePopup: {
// message: "New content is available.",
// buttonText: "Refresh"
// }
updatePopup: {
message: "文档有更新,新的内容已准备就绪",
buttonText: "刷新获取新内容"
}
},
// 假定是 GitHub. 同时也可以是一个完整的 GitLab URL
repo: 'CodFrm/cxmooc-tools',
// 自定义仓库链接文字。默认从 `themeConfig.repo` 中自动推断为
// "GitHub"/"GitLab"/"Bitbucket" 其中之一,或是 "Source"。
repoLabel: 'GitHub',
// 以下为可选的编辑链接选项
// 假如文档不是放在仓库的根目录下:
docsDir: 'docs',
// 假如文档放在一个特定的分支下:
docsBranch: 'master',
// 默认是 false, 设置为 true 来启用
editLinks: true,
// 默认为 "Edit this page"
editLinkText: '在 GitHub 上编辑此页',
lastUpdated: 'Last Updated', // string | boolean
},
plugins: [
['@vuepress/back-to-top'],
[
'@vuepress/google-analytics',
{
'ga': 'UA-138255059-2'
}
]
]
}
\ No newline at end of file
cx-doc.xloli.top
\ No newline at end of file
---
title: 开发者
---
## 准备工作
### 环境:
* Node.js
* webpack
### Build
```bash
git clone https://github.com/CodFrm/cxmooc-tools.git
cd cxmooc-tools
npm install
npm run build
# 开发模式请使用
npm run dev
# 打包生成crx和油猴脚本
npm run pack
```
### Server
> 搭建了一个服务器程序用于完善题库。接口没有任何权限,只会记录正确答题答案,并不会记录其他信息。
> 以上过程全由插件自动提交,还请大家不要故意上传错误的答案哦 (๑• . •๑)
> 因为超星慕课全站启用了`https`,所以服务器配置需要`https`。
```bash
npm install
npm run server
```
### 构建之后
> 能够体验到最新的功能,需要按照[准备工作](#准备工作)的方法步骤配置本地环境,可能会存在一些BUG。
1. 执行`npm run build`,此时会在`build/cxmooc-tools`目录下生成插件文件。
2. 打开Chrome浏览器的更多工具选项,打开扩展程序页面并启用开发者模式。
3. 加载已解压的扩展程序,路径选择`build/cxmooc-tools`
\ No newline at end of file
---
title: Chrome插件
---
## Chrome扩展
下载发布的版本[cxmooc-tools.crx](https://github.com/CodFrm/cxmooc-tools/releases)无需安装环境,下载即可使用。
1. 下载发布的版本cxmooc-tools.crx文件,修改后缀为.zip,并将其解压到目录`cxmooc-tools`
2. 打开Chrome浏览器的更多工具选项,打开扩展程序页面并启用开发者模式。
3. 加载已解压的扩展程序,路径选择你解压的路径`cxmooc-tools/`
解压后`cxmooc-tools`目录应包含以下文件
```
.
├── img
| └── some files
├── src
| └── some files
└── manifest.json
```
**图文步骤**
![](/img/1.webp)
![](/img/2.webp)
加载完成后,打开超星慕课的课程或者题目页面之后就可以正常使用了。
## 拖拽安装CRX模式
下载[发布版本](https://github.com/CodFrm/cxmooc-tools/releases)cxmooc-tools.crx文件,直接拖入浏览器安装
某些浏览器允许直接拖入扩展进行安装。(内核为Chromium,如果不行,请按照方法2来)
#### 支持列表
> 可以通过下方**在 GitHub 上编辑此页**来进行补充
* 360极速浏览器
* QQ浏览器
## 打包版浏览器
为了方便安装,我们还提供了一个浏览器打包的版本,请在[releases页面](https://github.com/CodFrm/cxmooc-tools/releases)查看详情,适合小白用户(但是版本更新可能较慢)
如果更新插件版本,可以用[拖拽安装CRX模式](/1-UserGuide/1-1-chrome.html#%E6%8B%96%E6%8B%BD%E5%AE%89%E8%A3%85crx%E6%A8%A1%E5%BC%8F)的方式来更新
![](/img/4.webp)
然后直接进入慕课网站直接开始
## 手机版本
> 待完善
---
title: FireFox插件
---
## 火狐浏览器扩展
如果你是火狐浏览器用户,请直接前往
[应用市场](https://addons.mozilla.org/zh-CN/firefox/addon/%E8%B6%85%E6%98%9F%E6%85%95%E8%AF%BE%E5%B0%8F%E5%B7%A5%E5%85%B7/)
下载安装插件。
## 火狐手机版(Android)
> 待完善,可以下载app后在商店安装,但是功能并不保证稳定(超星手机浏览器无法完成视频任务点)
---
title: Tampermonkey 脚本
---
## 安装
Tampermonkey,以下都称为油猴
油猴脚本使用需要去安装另外一个**Tampermonkey**插件,然后在 **[Greasy Fork/376190-cxmooc-tools](https://greasyfork.org/zh-CN/scripts/376190-cxmooc-tools)** 页面获取本插件
- [智慧树小工具](https://greasyfork.org/zh-CN/scripts/382037-%E6%99%BA%E6%85%A7%E6%A0%91%E5%B0%8F%E5%B7%A5%E5%85%B7)
### 配置修改
在油猴的管理面板中,选择编辑
![](/img/5.webp)
```js
let config = {
answer_ignore: false, //忽略题目,勾选此处将不会答题
auto: true, //全自动挂机,无需手动操作,即可自动观看视频等
interval: 5, //时间间隔,当任务点完成后,会等待5分钟然后跳转到下一个任务点
rand_answer: false, //随机答案,没有答案的题目将自动的生成一个答案
video_multiple: 1, //视频播放倍速,视频播放的倍数,建议不要改动,为1即可,这是危险的功能
video_mute: true, //视频静音,视频自动静音播放
vtoken: "user", //鉴权token(进群私聊机器人发送token获取)
};
```
根据代码中的说明进行配置,之后点击左上角文件,进行保存,或者快捷键 Ctrl+S 也可以保存,刷新一次页面就成功生效了.
![](/img/6.webp)
\ No newline at end of file
---
title: 配置说明
---
默认配置为:自动挂机,视频静音,1倍速,间隔5分钟;请按需调整.
> 待完善
\ No newline at end of file
---
title: 开始
---
本插件提供多种使用方式,请按照需求查阅相应的文档支持
## 小白
小白用户建议使用FireFox浏览器,前往FireFox商店下载更新:[**FireFox**](/1-UserGuide/1-2-firefox.html)
或者使用已经打包好了的浏览器版本使用:[**打包版浏览器**](/1-UserGuide/1-1-chrome.html#打包版浏览器),但是这个更新速度较慢,也可以自己手动更新
## 油猴
超星油猴脚本:[https://greasyfork.org/zh-CN/scripts/376190-超星慕课小工具](https://greasyfork.org/zh-CN/scripts/376190-%E8%B6%85%E6%98%9F%E6%85%95%E8%AF%BE%E5%B0%8F%E5%B7%A5%E5%85%B7)
智慧树油猴脚本:[https://greasyfork.org/zh-CN/scripts/382037-智慧树小工具](https://greasyfork.org/zh-CN/scripts/382037-%E6%99%BA%E6%85%A7%E6%A0%91%E5%B0%8F%E5%B7%A5%E5%85%B7)
**插件是全部整合的**
[telegram群](https://t.me/joinchat/MHU8Gg2fP3Q51HLY2wqmQA) [QQ群](https://shang.qq.com/wpa/qunwpa?idkey=9bddd2564d84bd999940de422d1c0c70f87ecaf02fe9d7c60389fc2b376179eb)
- 开发者
- Chrome插件
- FireFox插件
- 油猴脚本
- 功能说明
- 使用说明
\ No newline at end of file
---
title: 功能说明
---
## 超星
* [x] 视频挂机
* [x] 视频秒过
* [x] 视频倍速
* [x] 静音播放
* [x] 自动答题
* [x] 自动阅读
* [x] 自动填写验证码
* [x] 考试答题
* [x] 作业答题
* [x] 手机任务解锁
## 智慧树
* [x] 视频挂机
* [x] 视频秒过
* [x] 视频倍速
* [x] 静音播放
* [x] 题目屏蔽
* [x] 检测答题
---
title: 免责声明
---
## 免责声明
本项目完全开源,免费,仅供技术学习和交流,**开发者团队并未授权任何组织、机构以及个人将其用于商业或者盈利性质的活动。也从未使用本项目进行任何盈利性活动。未来也不会将其用于开展营利性业务。个人或者组织,机构如果使用本项目产生的各类纠纷,法律问题,均由其本人承担。**
如果您开始使用本项目,即视为同意项目免责声明中的一切条款,条款更新不再另行通知。**开发者仅接受和捐赠者之间不构成购买或雇佣关系的捐赠或者赞赏。** 如果您选择捐赠此项目,我们会列出一份捐赠者名单(包含捐赠金额,日期),但不会公布您的捐赠账号。如果您选择捐赠,那么我将视之为您完全自愿的,没有任何雇佣,购买关系的捐赠。
The project is completely open source, free, and is for technical learning and communication only. **The developer team does not authorize any organization, organization, or individual to use it for commercial or profitable activities. Never use this project for any profitable activities. It will not be used for profit-making business in the future. Individuals or organizations and organizations that use the various disputes arising from the project and legal issues shall be borne by themselves.**
If you start using this project, you are deemed to agree to all the terms in the project disclaimer, and the terms are updated without further notice. **Developers only accept donations or appreciations that do not constitute a purchase or employment relationship with the donor.** If you choose to donate this item, we will list a list of donors (including donation amount, date), but will not announce your donation account. If you choose to donate, then I will treat you as completely voluntary, without any employment, donation of the relationship.
\ No newline at end of file
---
title: 捐赠
---
<center>微信扫一扫,赏个鸡腿?</center>
<center><img src="/img/reward.png" alt=""></center>
## 捐赠名单
> 如果你有捐赠,但是未在列表上或者想修改信息,请发送邮件到:love@xloli.top 联系
>
> 赞赏可以叠加哦(肥宅偷笑.jpg)
|金额|渠道|捐赠者|备注|
|----|----|----|----|
|¥ 10.00|QQ红包|幻蓝|打赏了一个鸡腿|
|¥ 10.00|微信赞赏码|温瞳_|验证码接口推荐换成若快等,(会考虑增加)|
|¥ 5.00|微信赞赏码|xbei|ᕕ(˵•̀෴•́˵)ᕗ
|¥ 10.00|微信赞赏码|嗯?|差点白嫖|
|¥ 10.00|微信赞赏码|Simpler||
|¥ 1.00|微信赞赏码|以梦为北|(ง •̀_•́)ง|
|¥ 6.66|微信赞赏码|Moshi||
|¥ 4.00|微信赞赏码|蛆||
|¥ 5.00|QQ红包|小宝||
|¥ 5.00|QQ红包|503 py服务器已自闭||
---
home: true
heroImage:
heroText: 超星慕课小工具
tagline: 方便 快捷 安全
actionText: 开始使用
actionLink: /1-UserGuide/
features:
- title: 功能齐全
details: 支持视频挂机,自动答题,自动打码
- title: 支持广泛
details: 可以以浏览器插件,油猴脚本等方式运行
- title: 安全可靠
details: 代码完全开源,透明
footer: MIT Licensed | Copyright © 2018 CXmooc-tool developer Team
---
![GitHub stars](https://img.shields.io/github/stars/codfrm/cxmooc-tools.svg)
![Build Status](https://www.travis-ci.org/CodFrm/cxmooc-tools.svg?branch=master)
![GitHub All Releases](https://img.shields.io/github/downloads/codfrm/cxmooc-tools/total.svg)
![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/codfrm/cxmooc-tools.svg?label=version)
## 关于超星慕课小工具
> 2.1版本以后开始支持智慧树,名字嘛不改了
一个超星(学习通)和智慧树(知到)刷课工具,火狐,谷歌,油猴支持.全自动任务,视频倍速秒过,作业考试题库,验证码自动打码(੧ᐛ੭挂科模式,启动)
### 浏览器适配列表
> 国内大多数浏览器使用的chrome内核,所以360,QQ等之类的也可以使用
* Chrome for PC
* Firefox for PC
* Firefox for Mobile
* QQ 浏览器 for PC
* Tampermonkey
* Chrome 系浏览器
### 功能支持列表
**详情请看->[功能说明](/1-UserGuide/featured.html)**
---
title: 开发者模式
---
## 开发者模式:
### 准备工作
> 如果你想参与开发,请阅读下面内容,如果只是使用本插件,请移步 **[使用文档](https://cx-doc.xloli.top/)**
### 环境:
* Node.js
* webpack
### Build
```bash
git clone https://github.com/CodFrm/cxmooc-tools.git
cd cxmooc-tools
npm install
npm run build
# 开发模式请使用
npm run dev
# 打包生成crx和油猴脚本
npm run pack
```
### Server
> 搭建了一个服务器程序用于完善题库。接口没有任何权限,只会记录正确答题答案,并不会记录其他信息。
> 以上过程全由插件自动提交,还请大家不要故意上传错误的答案哦 (๑• . •๑)
> 因为超星慕课全站启用了`https`,所以服务器配置需要`https`。
```bash
npm install
npm run server
```
### 构建之后
> 能够体验到最新的功能,需要按照[准备工作](#准备工作)的方法步骤配置本地环境,可能会存在一些BUG。
1. 执行`npm run build`,此时会在`build/cxmooc-tools`目录下生成插件文件。
2. 打开Chrome浏览器的更多工具选项,打开扩展程序页面并启用开发者模式。
3. 加载已解压的扩展程序,路径选择`build/cxmooc-tools`
---
title: Chrome插件
---
## Chrome扩展:
下载发布的版本[cxmooc-tools.crx](https://github.com/CodFrm/cxmooc-tools/releases)无需安装环境,下载即可使用。
1. 下载发布的版本cxmooc-tools.crx文件,修改后缀为.zip,并将其解压到目录`cxmooc-tools`
2. 打开Chrome浏览器的更多工具选项,打开扩展程序页面并启用开发者模式。
3. 加载已解压的扩展程序,路径选择你解压的路径`cxmooc-tools/`
解压后`cxmooc-tools`目录应包含以下文件
```
.
├── img
| └── some files
├── src
| └── some files
└── manifest.json
```
**图文步骤**
![](/img/1.webp)
![](/img/2.webp)
加载完成后,打开超星慕课的课程或者题目页面之后就可以正常使用了。
## 拖拽安装CRX模式:
下载[发布版本](https://github.com/CodFrm/cxmooc-tools/releases)cxmooc-tools.crx文件,直接拖入浏览器安装
某些浏览器允许直接拖入扩展进行安装。(内核为Chromium,如果不行,请按照方法2来)
- 支持列表
* [x] 360极速浏览器
* [x] QQ浏览器
\ No newline at end of file
---
title: FireFox插件
---
## [推荐]火狐浏览器扩展
如果你是火狐浏览器用户,请直接前往
[应用市场](https://addons.mozilla.org/zh-CN/firefox/addon/%E8%B6%85%E6%98%9F%E6%85%95%E8%AF%BE%E5%B0%8F%E5%B7%A5%E5%85%B7/)
下载安装插件。
*注意,本插件支持Firefox for Mobile*
为了方便安装,我们还提供了一个浏览器打包的版本,请在[releases页面](https://github.com/CodFrm/cxmooc-tools/releases)查看详情
![](/img/4.webp)
\ No newline at end of file
---
title: 油猴脚本
---
不再赘述,请自行配置使用。[Greasy Fork/376190-cxmooc-tools](https://greasyfork.org/zh-CN/scripts/376190-cxmooc-tools)
\ No newline at end of file
---
title: 使用教程
---
本插件提供多种使用方式
请按照需求查阅相应的文档支持
- 开发者模式
- Chrome插件
- FireFox插件
- 油猴脚本
\ No newline at end of file
---
title: Disclaimer
---
## Disclaimer
The project is completely open source, free, and is for technical learning and communication only. **The developer team does not authorize any organization, organization, or individual to use it for commercial or profitable activities. Never use this project for any profitable activities. It will not be used for profit-making business in the future. Individuals or organizations and organizations that use the various disputes arising from the project and legal issues shall be borne by themselves.**
If you start using this project, you are deemed to agree to all the terms in the project disclaimer, and the terms are updated without further notice. **Developers only accept donations or appreciations that do not constitute a purchase or employment relationship with the donor.** If you choose to donate this item, we will list a list of donors (including donation amount, date), but will not announce your donation account. If you choose to donate, then I will treat you as completely voluntary, without any employment, donation of the relationship.
\ No newline at end of file
---
home: true
heroImage:
heroText: 超星慕课小工具
tagline: 方便 快捷 安全
actionText: 开始使用
actionLink: /1-Browser extension/
features:
- title: 功能齐全
details: 支持视频挂机,自动答题,自动打码
- title: 支持广泛
details: 可以以浏览器插件,油猴脚本等方式运行
- title: 安全可靠
details: 代码完全开源,透明
footer: MIT Licensed | Copyright © 2018 CXmooc-tool developer Team
---
## 关于超星慕课小工具
`cxmooc-tools`,一个可以辅助观看超星慕课的浏览器扩展,支持自动观看,自动答题等功能。兼容主流浏览器以及`Tampermonkey`脚本。
### 浏览器适配列表
* Chrome for PC
* Firefox for PC
* Firefox for Mobile
* QQ 浏览器 for PC
* Tampermonkey
### 功能支持列表
* 视频挂机
* 视频秒过
* 视频倍速
* 静音播放
* 自动答题
* 自动阅读
* 自动填写验证码
此差异已折叠。
{
"name": "cxmooc-tools",
"version": "2.0.1",
"version": "2.1.0",
"description": "> 一个快速学习超星慕课的chrome扩展工具(੧ᐛ੭挂科模式,启动)\r > 初次开发chrome扩展,有兴趣的朋友可以一起来哦",
"main": "mooc.js",
"scripts": {
"test": "echo \"Hello,World\nDeveloper Blog:blog.icodef.com\" && exit 1",
"build": "webpack --mode production --config webpack.prod.js",
"dev": "webpack --mode development --config webpack.dev.js",
"build": "node_modules/.bin/webpack --mode production --config webpack.config.js",
"tampermonkey": "node_modules/.bin/webpack --config webpack.tampermonkey.js",
"dev": "node_modules/.bin/webpack --mode development --config webpack.dev.js",
"server": "node src/server/listen.js",
"pack": "npm run build && node src/pack-crx.js && npm run build"
"pack": "node src/pack-crx.js",
"docs:dev": "node_modules/.bin/vuepress dev docs",
"docs:build": "node_modules/.bin/vuepress build docs"
},
"repository": {
"type": "git",
......@@ -21,8 +24,13 @@
},
"homepage": "https://github.com/CodFrm/cxmooc-tools#readme",
"devDependencies": {
"@vuepress/plugin-back-to-top": "^1.0.0-alpha.47",
"@vuepress/plugin-google-analytics": "^1.0.0-alpha.0",
"crx": "^4.0.1",
"css-loader": "^2.1.1",
"html-webpack-plugin": "^3.2.0",
"style-loader": "^0.23.1",
"vuepress": "^1.0.0-alpha.47",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2",
"webpack-merge": "^4.1.4"
......@@ -30,7 +38,10 @@
"dependencies": {
"body-parser": "^1.18.3",
"express": "^4.16.3",
"hashmap": "^2.3.0",
"md5": "^2.2.1",
"mongodb": "^3.1.10"
"mongodb": "^3.1.10",
"node-telegram-bot-api": "^0.30.0",
"redis": "^2.8.0"
}
}
module.exports = {
url: "https://blog.icodef.com:8081/",
version: 2.01,
url: "http://cx.icodef.com/",
version: 2.10,
update: 'https://github.com/CodFrm/cxmooc-tools/releases',
enforce: false,
cx: {
player: 'https://blog.icodef.com:8081/player/cxmooc-tools.swf',
resplugin: 'https://blog.icodef.com:8081/player/ResourcePlug.swf'
player: 'https://cx.icodef.com/player/cxmooc-tools.swf',
resplugin: 'https://cx.icodef.com/player/ResourcePlug.swf'
},
injection: ''
injection: '',
hotversion: {
v2_10: 2.10,
v2_08: 2.083,
v2_07: 2.071,
v2_06: 2.06,
},
getHotVersion: function (ver) {
let dealver = 'v' + ('' + ver || this.version).replace('.', '_');
hotversion = this.hotversion[dealver] || this.version;
return hotversion;
}
}
\ No newline at end of file
......@@ -2,7 +2,7 @@ const moocConfig = require('../config');
//更新检测
var xhr = new XMLHttpRequest();
xhr.open("GET", moocConfig.url + 'update', true);
xhr.open("GET", moocConfig.url + 'update?ver=' + moocConfig.version, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (this.status == 200) {
......@@ -11,7 +11,8 @@ xhr.onreadystatechange = function () {
chrome.storage.local.set({
'version': json.version,
'url': json.url,
'enforce': json.enforce
'enforce': json.enforce,
'hotversion': json.hotversion
});
if (moocConfig.version < json.version) {
chrome.browserAction.setBadgeText({
......@@ -21,7 +22,50 @@ xhr.onreadystatechange = function () {
color: [255, 0, 0, 255]
});
}
} else {
chrome.storage.local.set({
'version': moocConfig.version,
'url': moocConfig.url,
'enforce': moocConfig.enforce,
'hotversion': moocConfig.version,
});
}
}
}
xhr.send();
\ No newline at end of file
xhr.send();
//监听消息
chrome.runtime.onConnect.addListener(function (port) {
if (port.name != 'tools') {
return;
}
port.onMessage.addListener(function (request) {
switch (request.type) {
case 'GM_xmlhttpRequest': {
request.param.onreadystatechange = function (req) {
req.event = 'onreadystatechange';
req.type = 'GM_xmlhttpRequest';
port.postMessage(req);
}
GM_xmlhttpRequest(request.param);
break;
}
}
});
});
function GM_xmlhttpRequest(request) {
var xhr = new XMLHttpRequest();
xhr.open(request.method, request.url, true);
for (let key in request.headers) {
xhr.setRequestHeader(key, request.headers[key]);
}
xhr.onreadystatechange = function () {
request.onreadystatechange && request.onreadystatechange({
readyState: xhr.readyState,
status: xhr.status,
responseText: xhr.responseText,
});
}
xhr.send(request.data || null);
}
\ No newline at end of file
......@@ -2,16 +2,21 @@
* 超星刷课功能集合
*/
const common = require('../common');
const until = require('./until');
const util = require('./util');
const Video = require('./video');
const Topic = require('./topic');
const Vcode = require('./vcode');
const Exam = require('./exam');
module.exports = function () {
let self = this;
this.list = new Array();
this.list = undefined;
this.index = 0;
this.iframe = undefined;
this.tag = Math.random();
this.document = undefined;
this.complete_num = 0;
this.vcode = new Vcode();
this.inSwitch = false;
/**
* 查找iframe
* @param iframeElement
......@@ -24,7 +29,9 @@ module.exports = function () {
let obj = undefined;
if ($(iframeElement[i]).hasClass('ans-insertvideo-online')) {
obj = new Video();
} else if ($(iframeElement[i]).attr('src').indexOf('modules/work') > 0) {
//解锁phone
global.allowPhone && (iframeElement[i].contentWindow.Ext.isChaoxing = true);
} else if ($(iframeElement[i]).attr('src') != undefined && $(iframeElement[i]).attr('src').indexOf('modules/work') > 0) {
obj = new Topic();
}
if (obj != undefined) {
......@@ -55,25 +62,39 @@ module.exports = function () {
}
}
let lastTimeout = 0;
//hook
let hookChangeDisplayContent = window.changeDisplayContent;
window.changeDisplayContent = function (num, totalnum, chapterId, courseId, clazzid, knowledgestr) {
clearTimeout(lastTimeout);
hookChangeDisplayContent(num, totalnum, chapterId, courseId, clazzid, knowledgestr);
}
let hookGetTeacherAjax = window.getTeacherAjax;
window.getTeacherAjax = function (courseId, clazzid, chapterId, cpi, chapterVerCode) {
clearTimeout(lastTimeout);
hookGetTeacherAjax(courseId, clazzid, chapterId, cpi, chapterVerCode);
}
/**
* 延迟切换
*/
function lazySwitch(callback) {
//无任务
let duration = (config.interval || 1) * 60000;
setTimeout(function () {
config.auto && self.notice(config.interval + "分钟后插件将自动切换下一节任务");
config.auto && common.log(config.interval + " after switch")
clearTimeout(lastTimeout);
lastTimeout = setTimeout(function () {
if (callback == undefined) {
switchTask();
} else {
callback();
}
}, duration);
}, config.duration);
}
this.loadover = function (event) {
if (event == self.list[0]) {
//第一个加载完成
config.auto && ignoreCompile(event);
event.pause && config.auto && ignoreCompile(event);
}
}
......@@ -82,10 +103,12 @@ module.exports = function () {
if (config.answer_ignore && self.list[self.index] instanceof Topic) {
switchTask();
} else {
if (until.isFinished(event.iframe) || !until.isTask(event.iframe)) {
if (util.isFinished(event.iframe) || !util.isTask(event.iframe)) {
//完成了,或者非任务点
switchTask();
} else {
//判断是否切换了页面
self.complete_num++;
event.start();
}
}
......@@ -96,9 +119,10 @@ module.exports = function () {
return;
}
//判断是否切换了页面
console.log(self.iframe, self.tag);
if ($(self.iframe).attr('tag') != self.tag) {
return;
if (self.list[self.index] != undefined) {
common.log(self.list[self.index].iframe.className + " " + self.index + " switch")
} else {
common.log("null " + self.index + " switch")
}
//切换下一个未完成的任务
if (self.list.length > 0 && self.index < self.list.length - 1) {
......@@ -106,6 +130,15 @@ module.exports = function () {
ignoreCompile(self.list[self.index]);
return;
}
if (self.complete_num <= 0) {
self.complete_num = 1;
if (self.list.length > 0) {
lazySwitch();
} else {
switchTask();
}
return;
}
let folder = $('.tabtags').find('span');
for (let i = 0; i < folder.length; i++) {
if ($(folder[i]).hasClass('currents')) {
......@@ -138,27 +171,36 @@ module.exports = function () {
}
this.studentstudy = function () {
common.log("studentstudy load");
varInit();
let iframe = $('iframe');
self.iframe = iframe;
$(iframe).attr('tag', self.tag);
self.document = self.iframe[0].contentDocument
self.notice(config.auto ? '正在自动挂机中' : '');
findIframe(iframe);
for (let i = 0; i < self.list.length; i++) {
self.list[i].init();
}
//无任务
if (self.list.length <= 0) {
setTimeout(function () {
switchTask();
}, (config.interval || 0.1) * 60000);
lazySwitch();
}
}
function varInit() {
self.list = new Array();
self.index = 0;
self.complete_num = 0;
clearTimeout(lastTimeout);
}
this.read = function () {
let timer = undefined;
let slide = function () {
if (document.body.getScrollHeight() - document.body.getHeight() <= document.documentElement.scrollTop + 40) {
let next = $('.ml40.nodeItem.r');
if (next.length <= 0) {
self.notice('看完啦~');
alert('看完啦~');
} else {
next[0].click();
......@@ -172,5 +214,30 @@ module.exports = function () {
slide();
}
this.notice = function (text) {
let el = undefined;
if ($(self.document.body).find('.prompt-line-cxmooc-notice').length > 0) {
el = $(self.document.body).find('.prompt-line-cxmooc-notice')[0];
} else {
el = common.createLine(text, 'cxmooc-notice');
$(el).css('text-align', 'center');
$(self.document.body).prepend(el);
}
$(el).text(text);
}
this.exam = function () {
Exam.exam();
}
this.homework = function () {
Exam.homework();
}
this.collectHomeWork = function () {
Exam.collect('home');
}
this.collectExam = function () {
Exam.collect('exam');
}
return this;
}
const util = require('./util');
const common = require('../common');
const moocServer = require('../../config');
// const css = require('../html/common.css');
module.exports = {
notic: undefined,
getTopic: function () {
let topic = $('.Cy_TItle.clearfix .clearfix');
if (topic.length <= 0) {
this.notic.text('未搜索到题目');
return undefined;
}
let text = common.removeHTML($(topic).html());
text = text.substr(0, text.lastIndexOf('分)'));
text = text.substr(0, text.lastIndexOf('('));
return text;
},
getHomeworkTopic: function () {
let topic = $('.Zy_TItle.clearfix .clearfix');
if (topic.length <= 0) {
return undefined;
}
let ret = [];
for (let i = 0; i < topic.length; i++) {
let text = common.removeHTML($(topic[i]).html());
let options = $(topic[i]).parent().next();
let elClass = $(options).attr('class');
let type = 0;
if (elClass.indexOf('Zy_ulTk') >= 0 && /第.空/.test($(options).text())) {
type = 4;
} else if (elClass.indexOf('Zy_ulBottom') >= 0) {
type = 3;
} else if (elClass.indexOf('clearfix') >= 0) {
//多选/单选
type = $(options).find('[type="radio"]').length > 0 ? 1 : 2;
} else {
common.signleLine('暂不支持的类型', 'answer' + i, undefined, options);
continue;
}
ret.push({
index: i,
topic: text,
type: type,
options: options
});
}
return ret;
},
createBtn: function (className, after) {
let btn = util.createBtn('搜索答案', '搜索题目答案');
if (after == true) {
$(className).after(btn);
} else {
$(className).append(btn);
}
return btn;
},
homework: function () {
let self = this;
let btn = self.createBtn('.CyTop');
btn.onclick = function () {
$(btn).text('搜索中...');
//搜索答案
let topic = self.getHomeworkTopic();
if (topic == undefined) {
return false;
}
common.requestAnswer(topic, 'cx', 0, function (topic, answer) {
let index = topic.index;
if (answer == undefined) {
common.signleLine('无答案', 'answer' + index, undefined, topic.options);
return;
}
self.fillHomeWorkAnswer(topic, answer);
}, () => { $(btn).text('搜索完成'); },
() => { $(btn).text('网络错误'); }
);
return false;
}
},
fillHomeWorkAnswer: function (topic, answer) {
let correct = answer.correct;
switch (topic.type) {
case 1:
case 2: {
let options = $(topic.options).find('input');
let noticText = this.fillSelect(options, correct);
common.signleLine(noticText, 'answer' + topic.index, undefined, topic.options);
break;
}
case 3: {
let options = $(topic.options).find('input');
this.fillJudge(options, correct);
common.signleLine('答案:' + correct[0].option, 'answer' + topic.index, undefined, topic.options);
break;
}
case 4: {
let options = $(topic.options).find('input[type="text"]');
let notic = '';
for (let i = 0; i < options.length; i++) {
let pos = common.substrEx($(options[i]).parent().find('.red.fb.font14').text(), '', '');
for (let n = 0; n < correct.length; n++) {
if (correct[n].option == pos) {
notic += '' + pos + '空:' + correct[n].content + '<br/>';
$(options[n]).val(correct[n].content);
break;
}
}
}
common.signleLine(notic, 'answer' + topic.index, undefined, topic.options);
break;
}
}
},
exam: function () {
let self = this;
let btn = self.createBtn('.Cy_ulBottom.clearfix.w-buttom,.Cy_ulTk,.Cy_ulBottom.clearfix', true);
btn.onclick = function () {
//搜索答案
self.notic = common.signleLine('搜索答案中...', 'answer', btn.parentElement);
let topic = self.getTopic();
if (topic == undefined) {
return false;
}
common.gm_post(moocServer.url + 'v2/answer?platform=cx', 'topic[0]=' + topic, false, function (data) {
let json = JSON.parse(data);
if (json[0].result.length <= 0) {
return self.notic.text('未找到答案');
}
let answer = json[0].result[Math.floor(Math.random() * Math.floor(json[0].result.length))];
//填充
self.fillAnswer(answer);
}).error(function () {
self.notic.text('网络错误');
});
return false;
}
if (config.auto) {
btn.onclick();
}
},
fillSelect: function (options, correct) {
let noticText = '';
$(options).removeAttr('checked');
for (let i = 0; i < correct.length; i++) {
let index = (correct[i].option.charCodeAt() | 32) - 97;
$(options[index]).click();
noticText += correct[i].option + ':' + correct[i].content + '<br/>';
}
return noticText;
},
fillJudge: function (options, correct) {
$(options).removeAttr('checked');
let index = 1;
if (correct[0].option) {
index = 0;
}
// $(options[index]).attr('checked', true);
$(options[index]).click();
},
fillAnswer: function (answer) {
let correct = answer.correct;
switch (answer.type) {
case 1:
case 2: {
let options = $('.Cy_ulBottom.clearfix.w-buttom li input');
if (options.length <= 0) {
this.notic.text('答案搜索错误');
return false;
}
let noticText = this.fillSelect(options, correct);
$(this.notic).html(noticText);
break;
}
case 3: {
let options = $('.Cy_ulBottom.clearfix li input');
if (options.length <= 0) {
this.notic.text('答案搜索错误');
return false;
}
this.fillJudge(options, correct);
$(this.notic).html('答案:' + correct[0].option);
break;
}
case 4: {
let options = $('.Cy_ulTk .XztiHover1');
if (options.length <= 0) {
this.notic.text('答案搜索错误');
return false;
}
let notic = '';
for (let i = 0; i < options.length; i++) {
let pos = common.substrEx($(options[i]).find('.fb.font14').text(), '', '');
for (let n = 0; n < correct.length; n++) {
if (correct[n].option == pos) {
notic += '' + pos + '空:' + correct[n].content + '<br/>';
var uedit = $(options[n]).find('textarea');
if (uedit.length <= 0) {
this.notic.text('答案搜索错误');
return false;
}
UE.getEditor(uedit.attr('name')).setContent(correct[n].content);
break;
}
}
}
$(this.notic).html(notic);
break;
}
default: {
this.notic.text('不支持的答案类型:' + JSON.stringify(correct));
return false;
}
}
return true;
},
collect: function (college_type) {
let timu = $('.TiMu');
let answer = [];
for (let i = 0; i < timu.length; i++) {
let topic = undefined;
if (college_type == 'home') {
topic = $(timu[i]).find('.Zy_TItle.clearfix .clearfix div:first-child');
} else {
topic = $(timu[i]).find('.Cy_TItle.clearfix .clearfix');
}
if (topic.length <= 0) {
continue;
}
let correct = $(timu[i]).find('.Py_answer.clearfix,.Py_tk');
if ($(correct).text().indexOf('正确答案') >= 0 ||
$(correct).find('.dui').length > 0) {
correct = common.removeHTML($(correct).find('span:first,p:first').html());
} else {
continue;
}
let topicText = common.removeHTML(topic.html());
let options = undefined;
if (college_type == 'home') {
options = $(timu[i]).find('.Cy_ulTop li,.Zy_ulTop li');
} else {
options = $(timu[i]).find('.Cy_ulTop li');
topicText = topicText.substr(0, topicText.lastIndexOf('('));
}
let pushOption = { topic: topicText, answers: [], correct: [] };
if (options.length <= 0) {
//非选择
let is = false;
if ((is = correct.indexOf('')) > 0 || correct.indexOf('×') > 0) {
pushOption.correct.push({ option: (is > 0), content: (is > 0) });
pushOption.type = 3
} else {
let options = undefined;
if (college_type == 'home') {
options = $(timu[i]).find('div.font14');
} else {
options = $(timu[i]).find('.Py_answer div:first .font14.clearfix');
}
for (let n = 0; n < options.length; n++) {
if ($(options[n]).find('.dui').length <= 0) {
continue;
}
let option = $(options[n]).find('.fb.fl').text();
if (option == null) {
break;
}
option = common.substrEx(option, '', '');
let content = undefined;
if (college_type == 'home') {
content = $(options[n]).find('div.clearfix').html();
} else {
content = $(options[n]).find('div.fl').html();
}
pushOption.correct.push({ option: option, content: common.removeHTML(content) });
}
pushOption.type = 4;
}
} else {
let correctText = correct.match(/\w+/);
if (correctText == null) {
continue;
}
correctText = correctText[0];
for (let n = 0; n < options.length; n++) {
let option = $(options[n]).find('.fl:first-child').text().replace('', '');
let tmp = {
option: option,
content: common.removeHTML($(options[n]).find('.clearfix,.fl:last-child').html())
};
if (correctText.indexOf(option) >= 0) {
pushOption.correct.push(tmp);
}
pushOption.answers.push(tmp);
}
pushOption.type = correctText.length <= 1 ? 1 : 2;
}
answer.push(pushOption);
}
// console.log(answer);
common.gm_post(moocServer.url + 'answer?platform=cx', JSON.stringify(answer), true, function () {
let box = common.pop_prompt("√ 答案自动记录成功");
$(document.body).append(box);
setTimeout(function () { box.style.opacity = "1"; }, 500);
});
}
};
\ No newline at end of file
const common = require('../common');
const until = require('./until');
const until = require('./util');
const moocServer = require('../../config');
module.exports = function () {
......@@ -8,16 +8,16 @@ module.exports = function () {
this.document = undefined;
this.complete = undefined;
this.loadover = undefined;
this.topicBtn = undefined;
this.hangBtn = undefined;
this.pause = true;
this.searchAnswer = function () {
if (self.pause) {
self.pause = false;
config.auto && $(self.topicBtn).text('暂停挂机');
config.auto && $(self.hangBtn).text('暂停挂机');
} else {
self.pause = true;
$(self.topicBtn).text('搜索题目');
$(self.hangBtn).text('搜索题目');
return;
}
let TiMu = $(self.document).find('.Zy_TItle.clearfix');
......@@ -29,7 +29,7 @@ module.exports = function () {
for (let i in topic) {
data += 'topic[' + i + ']=' + topic[i].topic + '&type[' + i + ']=' + topic[i].type + '&';
}
common.post(moocServer.url + 'v2/answer', data, false, function (data) {
common.gm_post(moocServer.url + 'v2/answer?platform=cx', data, false, function (data) {
let json = JSON.parse(data);
let answer_null = false;
for (let i = 0; i < json.length; i++) {
......@@ -38,18 +38,24 @@ module.exports = function () {
}
}
if (answer_null) {
alert('有题目没有找到答案,并且未设置随机答案,请手动填入');
//切换下一个任务点
$(self.hangBtn).text('答案不全跳过');
self.complete();
return;
}
common.log(self.iframe.className + " topic complete")
if (config.auto) {
self.complete(1);
} else {
self.complete();
}
}).error(function () {
common.log(self.iframe.className + " topic error")
$(self.hangBtn).text('网络错误跳过');
self.complete();
});
}
this.pushTopic = function () {
if (self.pause) {
return;
......@@ -61,17 +67,17 @@ module.exports = function () {
alert('提示:' + prompt);
return;
}
prompt = document.getElementById('validate');
if (prompt.style.display != 'none') {
if (!show) {
show = true;
alert('需要输入验证码');
let timer = setInterval(function () {
prompt = document.getElementById('validate');
if (prompt.style.display != 'none') {
//等待验证码接管
return;
}
return;
}
//确定提交
let submit = $(self.document).find('.bluebtn');
submit[0].click();
clearInterval(timer);
//确定提交
let submit = $(self.document).find('.bluebtn');
submit[0].click();
}, 2000);
}
let submit = function () {
let submit = $(self.document).find('.Btn_blue_1');
......@@ -87,16 +93,16 @@ module.exports = function () {
* 创建按钮
*/
this.createButton = function () {
self.topicBtn = until.createBtn('搜索题目', '点击自动从网络上的题库中查找答案');
self.hangBtn = until.createBtn('搜索题目', '点击自动从网络上的题库中查找答案');
let prev = $(self.iframe).prev();
if (prev.length <= 0) {
prev = $(self.iframe).parent();
$(prev).prepend(self.topicBtn);
$(prev).prepend(self.hangBtn);
} else {
$(prev).append(self.topicBtn);
$(prev).append(self.hangBtn);
}
until.dealTaskLabel(prev);
self.topicBtn.onclick = self.searchAnswer;
self.hangBtn.onclick = self.searchAnswer;
}
this.init = function () {
......@@ -106,6 +112,7 @@ module.exports = function () {
}
function reloadInit() {
common.log(self.iframe.className + " topic reload init")
if (until.isFinished(self.iframe)) {
self.collect();
} else {
......@@ -118,12 +125,16 @@ module.exports = function () {
//监听框架,跳转抓取题目
function listenIframe() {
$($(self.iframe.contentDocument).find('#frame_content')[0]).on("load", function () {
self.document = this.contentDocument;
reloadInit();
common.log("topic load " + this.contentWindow.location.href);
if (this.contentWindow.location.href.indexOf('selectWorkQuestionYiPiYue') > 0) {
self.document = this.contentDocument;
reloadInit();
}
});
}
this.start = function () {
common.log(self.iframe.className + " topic start")
self.searchAnswer();
}
......@@ -140,11 +151,16 @@ module.exports = function () {
}
answer.push(tmp);
}
let box = until.pop_prompt("√ 答案自动记录成功");
let box = common.pop_prompt("√ 答案自动记录成功");
$(document.body).append(box);
setTimeout(function () { box.style.opacity = "1"; }, 500);
common.post(moocServer.url + 'answer', JSON.stringify(answer));
self.complete(2);
common.gm_post(moocServer.url + 'answer?platform=cx', JSON.stringify(answer), true, function () {
common.log(self.iframe.className + " topic answer complete")
self.complete(2);
}).error(function () {
common.log(self.iframe.className + " topic answer complete")
self.complete(2);
});
}
return this;
}
......@@ -280,14 +296,14 @@ function fillTopic(TiMu, answer, sourceTopic) {
result = genRandAnswer(sourceTopic[answer.index].type);
rand = true;
} else {
until.createLine('没有答案', 'answer', $(optionEl).next());
common.createLine('没有答案', 'answer', $(optionEl).next());
return false;
}
if (result.correct.length <= 0) {
until.createLine('不支持的随机答案类型', 'answer', $(optionEl).next());
common.createLine('不支持的随机答案类型', 'answer', $(optionEl).next());
return false;
} else {
until.createLine('这是随机生成的答案', 'answer', $(optionEl).next());
common.createLine('这是随机生成的答案', 'answer', $(optionEl).next());
}
}
let options = {}
......@@ -311,7 +327,7 @@ function fillTopic(TiMu, answer, sourceTopic) {
if (!$(options[n]).attr('checked')) {
options[n].click();
}
until.createLine(options[n].value + ':' + $(content).text(), 'answer', $(optionEl).next());
common.createLine(options[n].value + ':' + $(content).text(), 'answer', $(optionEl).next());
options.splice(n, 1);
break;
} else if ($(options[n]).attr('checked')) {
......@@ -323,10 +339,10 @@ function fillTopic(TiMu, answer, sourceTopic) {
case 3: {
if (result.correct[0].option) {
options[0].click();
until.createLine('对√', 'answer', $(optionEl).next());
common.createLine('对√', 'answer', $(optionEl).next());
} else {
options[1].click();
until.createLine('错×', 'answer', $(optionEl).next());
common.createLine('错×', 'answer', $(optionEl).next());
}
break;
}
......@@ -334,7 +350,7 @@ function fillTopic(TiMu, answer, sourceTopic) {
for (let n = 0; n < options.length; n++) {
if (common.substrEx(options[n].innerText, '', '') == result.correct[i].option) {
$(options[n]).find('.inp').val(result.correct[i].content);
until.createLine(options[n].innerText + ':' + result.correct[i].content, 'answer', $(optionEl).next());
common.createLine(options[n].innerText + ':' + result.correct[i].content, 'answer', $(optionEl).next());
options.splice(n, 1);
break;
}
......@@ -342,7 +358,7 @@ function fillTopic(TiMu, answer, sourceTopic) {
break;
}
default: {
until.createLine('不支持的类型', 'answer', $(optionEl).next());
common.createLine('不支持的类型', 'answer', $(optionEl).next());
break;
}
}
......
......@@ -39,22 +39,6 @@ export function dealTaskLabel(label) {
span.css('margin-left', '0');
}
/**
* 创建一行
* @param {string} text
*/
export function createLine(text, label, append) {
let p = $('<p></p>');
p.css('color', 'red');
p.css('font-size', '14px');
p.attr('class', 'prompt-line-' + label);
p.text(text);
if (append != undefined) {
$(append).append(p);
}
return p;
}
export function isFinished(el) {
if ($(el).parents('.ans-attach-ct.ans-job-finished').length > 0) {
return true;
......@@ -68,26 +52,3 @@ export function isTask(el) {
}
return false;
}
export function pop_prompt(text, sec = 4) {
var box = document.createElement('div');
box.style.position = "absolute";
box.style.background = "#aeffab";
box.style.fontSize = "18px";
box.style.padding = "4px 20px";
box.style.borderRadius = "20px";
box.style.top = "50%";
box.style.left = "50%";
box.style.transform = "translate(-50%,-50%)";
box.style.transition = "1s";
box.style.opacity = "0";
box.innerText = text;
setTimeout(function () {
box.style.opacity = "0";
setTimeout(function () {
box.remove();
}, 1000)
}, sec * 1000);
return box;
}
const common = require('../common');
const serverConfig = require('../../config');
module.exports = function () {
let self = this;
this.monitorVcode = function () {
//验证码监控加载
//作业处验证码
if (document.getElementById('imgVerCode')) {
$('#imgVerCode').on('load', function () {
if ($('#imgVerCode').attr('src').indexOf('?') < 0) {
//节约可能的一次打码
return;
}
let notic = common.signleLine('cxmooc自动打码中...', 'dama', $('#sub').parents('td'));
let img = document.getElementById('imgVerCode');
getVcode('/img/code?' + new Date().getTime(), img, function (code, msg) {
if (code === undefined) {
alert(msg);
$(notic).html(msg);
return;
}
$(notic).html('cxmooc打码成功,准备提交');
$('input#code').val(code);
setTimeout(function () {
$('a#sub').click();
}, 3000);
}, true);
});
}
//异常验证码
let yc = document.getElementById('ccc');
if (yc != undefined) {
yc.onclick = function () {
getVcode('/processVerifyPng.ac?t=' + Math.floor(2147483647 * Math.random()), yc, function (code, msg) {
if (code === undefined) {
alert(msg);
return;
}
document.getElementById('ucode').value = code;
setTimeout(function () {
document.getElementsByClassName('submit')[0].click();
}, 3000);
});
}
}
//保障账号安全验证码
window.showChapterVerificationCodeTip = window.showChapterVerificationCode || 0;
window.chapterVerifyCode = function () {
let notic = common.signleLine('cxmooc自动打码中...', 'dama1', $('.DySearch'));
$(notic).css('float', 'left');
let img = $('.fl[name=chapterNumVerCode]');
if (img.length <= 0) {
return;
}
img = img[0];
getVcode('/verifyCode/studychapter?' + (new Date()).valueOf(), img, function (code, msg) {
if (code === undefined) {
alert(msg);
$(notic).html(msg);
return;
}
$(notic).html('cxmooc打码成功,准备提交');
$('input#identifyCodeRandom').val(code);
setTimeout(function () {
continueGetTeacherAjax();
}, 3000);
});
}
}
function getVcode(url, img, callback, show) {
let vcodeimg = show ? img : document.createElement('img');
let dmStart = function () {
let base64 = common.getImageBase64(vcodeimg, 'jpeg');
if (!show) {
img.src = base64;
}
if (false && config.is_ruokuai) {
//若快打码
} else {
common.gm_post(serverConfig.url + 'vcode', 'img=' + encodeURIComponent(base64.substr('data:image/jpeg;base64,'.length)), false, function (ret) {
let json = JSON.parse(ret);
if (json.code == -2) {
callback(undefined, json.msg);
//TODO:无权限
} else if (json.msg) {
callback(json.msg);
} else {
setTimeout(() => { getVcode(url, img, callback); },3000);
}
}).error(function () {
callback(undefined, '网络请求失败');
});
}
}
if (show) {
dmStart();
} else {
vcodeimg.onload = dmStart;
vcodeimg.src = url;
}
}
self.monitorVcode();
}
\ No newline at end of file
const common = require('../common');
const until = require('./until');
const until = require('./util');
const md5 = require("md5");
module.exports = function () {
......@@ -73,8 +73,15 @@ module.exports = function () {
}
initVideoTopic();
initCdn(self.video);
//点击切换记录cdn
$(self.document).find("[title='Playline']+.vjs-menu .vjs-menu-content .vjs-menu-item-text").click(function () {
localStorage['cdn'] = $(this).text();
});
//失败的切换记录
$(self.document).find('.vjs-error-display.vjs-modal-dialog').on('click', '.ans-vjserrdisplay-opts li.ans-vjserrdisplay-opt label"', function () {
localStorage['cdn'] = $(this).text();
});
let play = function () {
localStorage['cdn'] = $(self.document).find("[title='Playline']+.vjs-menu .vjs-menu-content .vjs-menu-item.vjs-selected .vjs-menu-item-text").text();
//静音和倍速选项
self.video.muted = config.video_mute;
self.video.playbackRate = config.video_multiple;
......@@ -90,15 +97,27 @@ module.exports = function () {
}
}
});
let tag = Math.random();
localStorage['now_video_tag'] = tag;
let pauseTimer = setInterval(function () {
//以防万一的暂停- -
if (!self.pause && localStorage['now_video_tag'] == tag) {
self.video.paused && self.video.play();
} else if (localStorage['now_video_tag'] != tag) {
clearInterval(pauseTimer);
}
}, 10000);
$(self.video).on('ended', function () {
if (undefined != self.complete) {
self.complete();
}
clearInterval(pauseTimer);
});
}
this.start = function () {
common.log(self.iframe.className + " video start")
self.startPlay();
}
......@@ -116,7 +135,6 @@ module.exports = function () {
setTimeout(function () {
self.video.play();
}, 0);
}
/**
......
const moocServer = require('../config');
/**
* 注入js资源
* @param doc
......@@ -8,7 +10,7 @@ export function injected(doc, url) {
temp.setAttribute('type', 'text/javascript');
temp.src = url;
temp.className = "injected-js";
doc.head.appendChild(temp);
doc.documentElement.appendChild(temp);
return temp;
}
......@@ -27,17 +29,16 @@ export function removeinjected(doc) {
* @param {*} url
*/
export function get(url, success) {
try {
var xmlhttp = createRequest();
xmlhttp.open("GET", url, true);
xmlhttp.send();
} catch (e) {
return false;
}
let xmlhttp = createRequest();
xmlhttp.open("GET", url, true);
xmlhttp.send();
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
success && success(this.responseText);
success && success(this.responseText, this.resource);
} else {
xmlhttp.errorCallback && xmlhttp.errorCallback(this);
}
}
}
......@@ -51,22 +52,22 @@ export function get(url, success) {
* @param {*} json
*/
export function post(url, data, json = true, success) {
try {
var xmlhttp = createRequest();
xmlhttp.open("POST", url, true);
if (json) {
xmlhttp.setRequestHeader("Content-Type", "application/json");
} else {
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
}
xmlhttp.send(data);
} catch (e) {
return false;
let xmlhttp = createRequest();
xmlhttp.open("POST", url, true);
xmlhttp.setRequestHeader('Authorization', config.vtoken || '');
if (json) {
xmlhttp.setRequestHeader("Content-Type", "application/json");
} else {
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
}
xmlhttp.send(data);
xmlhttp.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
success && success(this.responseText);
} else {
xmlhttp.errorCallback && xmlhttp.errorCallback(this);
}
}
}
......@@ -124,6 +125,10 @@ function createRequest() {
} else {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.error = function (callback) {
xmlhttp.errorCallback = callback;
return xmlhttp;
}
return xmlhttp;
}
......@@ -136,4 +141,353 @@ export function randNumber(minNum, maxNum) {
default:
return 0;
}
}
Date.prototype.format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt;
}
export function log(msg) {
global.log += "cxmooc-tools [" + (new Date()).format("yyyy-MM-dd hh:mm:ss") + "] " + msg + "\n";
}
export function getImageBase64(img, ext) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, img.width, img.height);
var dataURL = canvas.toDataURL("image/" + ext, 0.75);//节省可怜的流量>_<,虽然好像没有啥
canvas = null;
return dataURL;
}
export function boom_btn() {
if (localStorage['boom_no_prompt'] == undefined || localStorage['boom_no_prompt'] != 1) {
let msg = prompt('秒过视频会产生不良记录,是否继续?如果以后不想再弹出本对话框请在下方填写yes')
if (msg === null) return false;
if (msg === 'yes') localStorage['boom_no_prompt'] = 1;
}
return true;
}
//消息发送
export function clientMessage(type, eventCallback) {
let self = {};
self.tag = Math.random();
window.addEventListener('message', function (event) {
if (event.data.recv_tag && event.data.recv_tag == self.tag) {
eventCallback && eventCallback(event.data.param, event);
}
});
self.send = function (param) {
window.postMessage({ type: type, send_tag: self.tag, param: param }, '*');
return self;
};
return self;
}
export function serverMessage(type, eventCallback) {
let self = {};
window.addEventListener('message', function (event) {
if (event.data.type && event.data.type == type && event.data.send_tag) {
eventCallback && eventCallback(event.data.param, function (param) {
self.send(param, event.data.send_tag);
});
}
});
self.send = function (param, tag) {
window.postMessage({ type: type, recv_tag: tag, param: param }, '*');
return self;
}
return self;
}
/**
* 跨域的post请求
* @param {*} url
* @param {*} data
* @param {*} json
* @param {*} success
*/
export function gm_post(url, data, json = true, success) {
let self = {};
GM_xmlhttpRequest({
url: url,
method: 'POST',
headers: {
'Authorization': config.vtoken || '',
'X-Version': moocServer.version,
'Content-Type': json ? 'application/json' : 'application/x-www-form-urlencoded',
},
data: data,
onreadystatechange: function (response) {
if (response.readyState == 4) {
if (response.status == 200) {
success && success(response.responseText);
} else {
self.errorCallback && self.errorCallback(response);
}
}
}
});
self.error = function (errorCallback) {
self.errorCallback = errorCallback;
}
return self;
}
/**
* 跨域的get请求
* @param {*} url
* @param {*} data
* @param {*} json
* @param {*} success
*/
export function gm_get(url, success) {
let self = {};
GM_xmlhttpRequest({
url: url,
method: 'GET',
onreadystatechange: function (response) {
if (response.readyState == 4) {
if (response.status == 200) {
success && success(response.responseText);
} else {
self.errorCallback && self.errorCallback(response);
}
}
}
});
self.error = function (errorCallback) {
self.errorCallback = errorCallback;
}
return self;
}
//实现GM_xmlhttpRequest
if (window.GM_xmlhttpRequest == undefined) {
window.GM_xmlhttpRequest = function (param) {
let send = {};
send.url = param.url;
send.method = param.method;
send.data = param.data;
send.headers = param.headers;
clientMessage('GM_xmlhttpRequest', function (response, event) {
if (response.event || response.event == 'onreadystatechange') {
param.onreadystatechange && param.onreadystatechange(response);
}
}).send(send);
}
}
export function isPhone() {
return /Android|iPhone/i.test(navigator.userAgent);
}
export function switchTopicType(typeTtile) {
let type = typeTtile;
switch (type) {
case '单选题': {
type = 1;
break;
}
case '多选题': {
type = 2;
break;
}
case '判断题': {
type = 3;
break;
}
case '填空题': {
type = 4;
break;
}
default: {
type = -1;
break;
}
}
return type;
}
export function postAnswer(topic, platform, collect, compile, error) {
let answer = [];
for (let i = 0; i < topic.length; i++) {
let tmp = collect(topic[i]);
if (tmp) {
answer.push(tmp);
}
}
gm_post(moocServer.url + 'answer?platform=' + platform, JSON.stringify(answer), true, compile).error(error);
}
export function pop_prompt(text, sec = 4) {
var box = document.createElement('div');
box.style.position = "fixed";
box.style.background = "#aeffab";
box.style.fontSize = "18px";
box.style.padding = "4px 20px";
box.style.borderRadius = "20px";
box.style.top = "50%";
box.style.left = "50%";
box.style.transform = "translate(-50%,-50%)";
box.style.transition = "1s";
box.style.opacity = "0";
box.innerText = text;
setTimeout(function () {
box.style.opacity = "0";
setTimeout(function () {
box.remove();
}, 1000)
}, sec * 1000);
return box;
}
export function requestAnswer(topic, platform, page, answer, compile, error, count, time) {
page = page || 0;
count = count || 5;
time = time || 2000;
let post = '';
for (let i = (page * count), n = 0; i < topic.length && n < count; i++ , n++) {
post += 'topic[' + n + ']=' + topic[i].topic + '&type[' + n + ']=' + topic[i].type + '&';
}
if (post == '') {
compile && compile();
return;
}
gm_post(moocServer.url + 'v2/answer?platform=' + platform, post, false, function (data) {
let json = JSON.parse(data);
for (let i = 0; i < json.length; i++) {
let index = json[i].index + page * count;
if (json[i].result.length <= 0) {
answer(topic[index]);
continue;
}
answer(topic[index], json[i].result[Math.floor(Math.random() * Math.floor(json[i].result.length))]);
}
setTimeout(() => { requestAnswer(topic, platform, page + 1, answer, compile, error); }, time);
}).error(function () {
error && error();
});
}
//数字转大写
export function numToZh(num) {
const data = {
'0': '',
'1': '',
'2': '',
'3': '',
'4': '',
'5': '',
'6': '',
'7': '',
'8': '',
'9': '',
};
let result = ('' + num).split('').map(v => data[v] || v).join('');
return result;
}
export function fillAnswer(topic, answer, fill, findOption) {
let correct = answer.correct;
let noticText = '';
switch (topic.type) {
case 1:
case 2: {
let options = findOption(topic.options, 2);
noticText = fill.select(options, correct);
break;
}
case 3: {
let options = findOption(topic.options, 3);
noticText = fill.judge(options, correct);
break;
}
case 4: {
let options = findOption(topic.options, 4);
noticText = fill.text(options, correct);
break;
}
default: {
noticText = fill.other();
}
}
return noticText;
}
export function fillSelect(options, correct, isTrue) {
let noticText = '';
for (let i = 0; i < correct.length; i++) {
isTrue(options, correct[i], 2);
noticText += correct[i].option + ':' + correct[i].content + '<br/>';
}
return noticText;
}
export function fillJudge(options, correct) {
$(options).removeAttr('checked');
let index = 1;
if (correct[0].option) {
index = 0;
}
$(options[index]).click();
}
export function oaForEach(object, callback) {
for (let i = 0; i < object.length; i++) {
if (callback(object[i], i)) {
break;
}
}
}
// export function fillText(options, correct) {
// }
/**
* 创建一行
* @param {string} text
*/
export function createLine(text, label, append, after) {
let p = $('<p></p>');
p.css('color', 'red');
p.css('font-size', '14px');
p.attr('class', 'prompt-line-' + label);
p.html(text);
if (append != undefined) {
$(append).append(p);
}
if (after != undefined) {
$(after).after(p);
}
return p;
}
export function signleLine(text, label, append, after) {
let p = $('.prompt-line-' + label);
if (p.length <= 0) {
p = createLine(text, label, append, after);
} else {
$(p).html(text);
}
p.text = function (text) {
$(this).html(text);
}
return p;
}
\ No newline at end of file
#cxtools{
position: absolute;
left: 250px;
top: 2px;
width: 100px;
}
#zhs-video-boom{
color:#fff;
background: #ff9d34;
}
#zhs-video-boom:hover{
background: #ff3838;
}
.zhs-search-answer{
border: 0;
outline: none;
}
.zhs-search-answer:hover{
opacity: .85;
}
\ No newline at end of file
......@@ -10,23 +10,18 @@
</title>
</head>
<style>
p {
margin: 0;
}
label{
label {
font-family: FangSong_GB2312;
font-size: 14px;
}
.ps {
text-align: right;
color: #cccccc;
margin-top: 30px;
}
h4 {
......@@ -34,14 +29,14 @@
margin-top: 4px;
}
a{
a {
text-decoration: none;
color: #336699;
transition: all .3s;
border-bottom: 1px solid white;
}
a:hover{
a:hover {
border-bottom: 1px solid;
color: #CCCC33;
......@@ -49,11 +44,13 @@
.config-item {
display: inline-block;
width: 120px;
width: 50%;
float: left;
height: 26px;
line-height: 26px;
font-size: 14px;
}
.rdo {
width: 0px;
height: 12px;
......@@ -65,22 +62,28 @@
border-radius: 50%;
position: relative;
}
.rdo:hover:before{
.rdo:hover:before {
border: 1px solid #ea879a;
}
.rdo:hover:after{
background-color:#ea879a;
.rdo:hover:after {
background-color: #ea879a;
}
.rdo:hover{
border-color:#ea879a;
.rdo:hover {
border-color: #ea879a;
}
.rdo:before,.rdo:after {
.rdo:before,
.rdo:after {
content: '';
display: block;
position: absolute;
border-radius: 50%;
transition: .3s ease;
}
.rdo:before {
top: 0px;
left: 0px;
......@@ -90,6 +93,7 @@
border: 1px solid #888;
cursor: pointer;
}
.rdo:after {
top: 6px;
left: 6px;
......@@ -98,20 +102,22 @@
background-color: #fff;
cursor: pointer;
}
.rdo:checked:after {
top: 4px;
left: 4px;
width: 12px;
height: 12px;
background-color:#ea879a;
background-color: #ea879a;
cursor: pointer;
}
.rdo:checked:before {
border-color:#ea879a;
border-color: #ea879a;
}
/*input倍数对齐*/
.input_text{
.input_text {
margin-top: -2px;
margin-bottom: 1px;
vertical-align: middle;
......@@ -121,11 +127,13 @@
font-size: 10px;
transition: .3s ease;
width: 30px;
border-radius:2px;
border:1px solid #ccc;
border-radius: 2px;
border: 1px solid #ccc;
height: 15px;
}
.input_text:hover{
border:1px solid #CCFFFF;
.input_text:hover {
border: 1px solid #CCFFFF;
box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 4px;
-moz-box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 4px;
-webkit-box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 4px;
......@@ -134,7 +142,6 @@
/*新的*/
body {
width: 400px;
/*background: #F5F5F5;*/
margin: 0 auto;
}
......@@ -142,49 +149,68 @@
font-family: STZhongsong;
color: #ffffff;
font-size: 16px;
margin: 0;
margin-left: 30px;
}
.title span{
color:#3399CC;
.title span {
color: #3399CC;
}
/*字体*/
.two_font{
.two_font {
font-family: SimHei;
font-size: 18px;
padding-bottom: 10px;
text-align: left;
}
.three_font{
.three_font {
font-family: FangSong_GB2312;
font-size: 14px;
text-align: left;
margin-bottom: 7px;
}
/*头部*/
.head{
.head {
width: 100%;
height: 72px;
line-height: 72px;
text-align: left;
background-image: url("../image/navtu.png");
background-image: url("../img/navtu.webp");
}
/*居中对齐*/
.center-float-left{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:-o-flex;display:flex;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;line-height:1.4;justify-content:center}
.center-float-left {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: -o-flex;
display: flex;
-webkit-align-items: center;
-moz-align-items: center;
-ms-align-items: center;
-o-align-items: center;
align-items: center;
line-height: 1.4;
justify-content: center
}
.content_top{
.content_top {
width: 100%;
height: auto;
margin-top: 30px;
margin-top: 0px;
}
/*内容第一层*/
.content_topleft{
width: 40%;
height: 130px;
.content_topleft {
color: #003366;
margin-right: 5%;
width: 100%;
padding: 0 20px;
}
.content_topright{
.content_topright {
width: 40%;
height: 130px;
/*直接设置固定高度了,要加内容注意看高度*/
......@@ -192,105 +218,199 @@
}
/*分类标题*/
.one_title{
.one_title {
border-bottom: 1px solid #CCCCCC;
font-family: STHeiti;
height: 30px;
padding: 4px 0;
font-size: 14px;
}
/*标题下内容*/
.three_font span{
.three_font span {
color: #333333;
}
.mt10{
.mt10 {
margin-top: 10px;
}
/*底部分类*/
.content_bottom{
width: 85%;
margin: 0 auto;
color: #003366;
margin-top: 10px;
}
.content_bottom .one_title{
.content_bottom {
overflow: hidden;
padding: 0 20px;
margin: 0 auto;
color: #003366;
margin-top: 10px;
}
.content_bottom .one_title {
margin-bottom: 10px;
}
.width_50{
width: 48%;
text-align: center;
.width_50 {
margin-top: 10px;
}
/*底部项目链接*/
.bottom_div{
width: 85%;
margin: 0 auto;
.bottom_div {
padding: 0 20px;
margin: 0 auto;
color: #003366;
margin-top: 10px;
}
.bottom_div p{
.bottom_div p {
margin-right: 20px;
display: inline-block;
margin-top: 10px;
}
/*移上去变手*/
.shou{
.shou {
cursor: pointer;
}
#tiku {
float: left;
width: 80px;
}
#vtoken,
#dama {
float: right;
}
.edit {
width: 150px;
}
#vtoken {
margin-top: 1px;
}
.btn {
height: 20px;
line-height: 16px;
background-color: #008CBA;
border: none;
color: white;
text-align: center;
text-decoration: none;
display: inline-block;
}
#dama {
width: 80px;
}
#dama-confirm {
width: 40px;
}
#dama-pop {
position: absolute;
right: 0;
}
.page {
overflow: hidden;
}
#dama-config {
position: absolute;
margin-top: 10px;
z-index: 100;
width: 100%;
height: 40px;
background: #fff;
height: 0;
overflow: hidden;
transition: .4s;
}
.comment {
font-size: 12px;
color: #000000;
font-weight: normal;
}
</style>
<body>
<div class="head">
<h3 class="title"><span>超星慕课</span>小工具</h3>
<div class="head">
<h3 class="title"><span>超星慕课</span>小工具</h3>
</div>
<div class="content_top center-float-left">
<div class="content_topleft">
<h4 class="one_title">公告</h4>
<div id="injection">
</div>
<div class="content_top center-float-left">
<div class="content_topleft">
<h4 class="one_title">公告</h4>
<p class="three_font mt10 shou"><span><a href="http://blog.icodef.com:8080/query.html">最新的查题地址</a></span></p>
<p class="three_font"><span>最新版本为3.1</span></p>
<!--<p class="three_font"><span>合作宣传请联系我们</span></p>-->
</div>
<div class="content_topright">
<h4 class="one_title">说明</h4>
<p class="three_font mt10"><span>秒过有危险,请不要滥用</span></p>
<p class="three_font"><span>2倍数及以下为最安全的</span></p>
<p class="three_font"><span>谷歌浏览器是最稳定的</span></p>
</div>
</div>
<div class="content_bottom">
<h4 class="one_title"><span>插件配置:</span></h4>
</div>
<div class="content_bottom">
<h4 class="one_title"><span>插件配置:</span>
<button id="dama" class="btn" style="display:none">打码设置</button>
<input type="text" style="float: right" class="input_text edit" placeholder="token" config-key="vtoken" />
<div id="dama-config">
<span>若快打码设置:</span>
<br>
<p class="comment">请自行注册若快购买进行配置</p>
<input type="text" class="input_text edit" config-key="ruokuai_user" placeholder="若快账号" />
<input type="text" class="input_text edit" config-key="ruokuai_pwd" placeholder="若快密码" />
<div class="config-item">
<input type="checkbox" id="ruokuai" class="rdo check" config-key="is_ruokuai" />
<label for="ruokuai" title="打码调用若快打码,不使用token了">使用若快打码</label>
</div>
<button id="dama-confirm" class="btn">确定</button>
</div>
</h4>
<div id="config" class="page">
<div class="config-item width_50">
<input type="checkbox" id="rand-answer" class="rdo" />
<label for="rand-answer" title="没有正确的答案会随机选择">随机答案</label>
</div>
<div class="config-item width_50">
<input type="checkbox" id="auto" class="rdo" />
<label for="auto" title="进入一个页面就会自动开始挂机,完成一个任务之后会自动进行下一个">自动挂机</label>
<label for="auto" title="进入一个页面就会自动开始挂机,完成一个任务之后会自动进行下一个">自动挂机</label>
</div>
<br>
<div class="config-item width_50">
<input type="checkbox" id="video-mute" class="rdo" />
<label for="video-mute" title="自动挂机时,视频静音">视频静音</label>
</div>
<div id="ignore" class="config-item width_50" style="">
<input class="rdo" type="checkbox" id="answer-ignore"/>
<label for="answer-ignore" title="自动挂机时,忽略掉题目不做,直接跳过">忽略题目</label>
<label for="video-mute" title="播放视频时,自动开启静音">视频静音</label>
</div>
<div class="config-item width_50" style="color:#ff0000">
<label for="video-multiple" title="视频播放的倍数,1为正常速度(最高16倍,该功能有一定危险)">播放速度:</label>
<input class="input_text" type="text" id="video-multiple" placeholder="1" />
<div id="ignore" class="config-item width_50">
<input class="rdo" type="checkbox" id="answer-ignore" />
<label for="answer-ignore" title="自动挂机时,忽略掉题目不做,直接跳过">忽略题目</label>
</div>
<div id="auto-m" class="config-item width_50">
<label for="interval" title="播放(题目)完成后n分钟再继续下一个任务">间隔时间:</label>
<input type="text" class="input_text" id="interval" placeholder="2" />
<div>
<div class="config-item width_50" style="color:#ff0000">
<label for="video-multiple" title="视频播放的倍数,1为正常速度(最高16倍,该功能有一定危险)">倍速播放:</label>
<input type="text" class="input_text" id="video-multiple" placeholder="1" />
</div>
<div id="auto-m" class="config-item width_50">
<label for="interval" title="播放(题目)完成后n分钟再继续下一个任务">间隔时间:</label>
<input type="text" class="input_text" id="interval" placeholder="5" />
</div>
</div>
</div>
<div class="bottom_div">
<h4 class="one_title"><span>地址:</span></h4>
<p><a class="three_font" href="https://github.com/CodFrm/cxmooc-tools" target="_black">GitHub开源地址</a></p>
<p><a class="three_font" href="https://github.com/CodFrm/cxmooc-tools/issues" target="_black">Bug/意见/题目反馈地址</a></p>
<p><a target="_blank" href="https://shang.qq.com/wpa/qunwpa?idkey=9bddd2564d84bd999940de422d1c0c70f87ecaf02fe9d7c60389fc2b376179eb">交流qq群&nbsp614202391</a></p>
</div>
</div>
<div class="bottom_div">
<h4 class="one_title"><span>其他:</span></h4>
<p><a class="three_font" href="https://github.com/CodFrm/cxmooc-tools" target="_black">GitHub开源地址</a></p>
<p><a class="three_font" href="https://cx-doc.xloli.top" target="_black">使用文档</a></p>
<br>
<p><a class="three_font" href="https://github.com/CodFrm/cxmooc-tools/issues" target="_black">Bug/意见/题目反馈地址</a>
</p>
<p><a target="_blank"
href="https://shang.qq.com/wpa/qunwpa?idkey=9bddd2564d84bd999940de422d1c0c70f87ecaf02fe9d7c60389fc2b376179eb">交流qq群&nbsp614202391</a>
</p>
</div>
<div style="padding:0 20px;margin-top: 10px;">
<img id="tiku" src="https://img.shields.io/badge/%E9%A2%98%E5%BA%93-success-brightgreen.svg">
<p class="ps">PS:本扩展全部是免费的</p>
<p id="version" class="ps"></p>
</div>
</body>
</html>
</html>
\ No newline at end of file
import '../tampermonkey/cxmooc-pack';
import '../tampermonkey/zhihuishu-pack';
const common = require('./common');
const chaoxing = require('./chaoxing/chaoxing');
common.removeinjected(document);
global.config = JSON.parse(localStorage['config']);
global.timer = new Array();
if (window.location.href.indexOf('mycourse/studentstudy?') > 0) {
//超星学习页面
document.addEventListener('load', function (ev) {
var ev = ev || event;
var _this = ev.srcElement || ev.target;
if (_this.id == 'iframe') {
factory('chaoxing').studentstudy();
}
}, true);
var frame = document.getElementById('iframe');
if (frame != null) {
factory('chaoxing').studentstudy();
}
} else if (window.location.href.indexOf('ztnodedetailcontroller/visitnodedetail') > 0) {
//超星阅读页面
factory('chaoxing').read();
}
/**
* 工厂
* @param {string} object
* @return plugin
*/
function factory(object) {
switch (object) {
case 'chaoxing': {
return new chaoxing();
}
}
}
common.serverMessage('cxconfig', function (param) {
global.config[param.key] = param.value
});
const moocConfig = require('../config');
const common = require('./common');
window.onload = function () {
let edit = document.getElementsByClassName('edit');
for (let i = 0; i < edit.length; i++) {
edit[i].onblur = function () {
sendConfig(edit[i].getAttribute('config-key'), edit[i].value);
chrome.storage.sync.set({
[edit[i].getAttribute('config-key')]: edit[i].value
});
}
chrome.storage.sync.get(edit[i].getAttribute('config-key'), function (items) {
edit[i].value = items[edit[i].getAttribute('config-key')] || '';
});
}
let check = document.getElementsByClassName('check');
for (let i = 0; i < check.length; i++) {
check[i].onchange = function () {
sendConfig(check[i].getAttribute('config-key'), check[i].checked);
chrome.storage.sync.set({
[check[i].getAttribute('config-key')]: check[i].checked
});
}
chrome.storage.sync.get(check[i].getAttribute('config-key'), function (items) {
check[i].checked = items[check[i].getAttribute('config-key')] || false;
});
}
document.getElementById('version').innerHTML = 'v' + moocConfig.version.toString();
var xhr = new XMLHttpRequest();
xhr.open("GET", moocConfig.url + 'update', true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (this.status == 200) {
var json = JSON.parse(this.responseText);
if (moocConfig.version < json.version) {
var p = document.createElement('p');
p.style.color = "#ff0000";
p.innerHTML = '有新的版本更新:<a href="' + json.url + '" style="float:right;" target="_blank">点我去下载</a> 最新版本:v' + json.version;
document.getElementsByTagName('body')[0].appendChild(p);
}
document.getElementById("injection").innerHTML = json.injection
}
common.gm_get(moocConfig.url + 'update?ver=' + moocConfig.version, function (data) {
var json = JSON.parse(data);
chrome.storage.local.set({
'version': json.version,
'url': json.url,
'enforce': json.enforce,
'hotversion': json.hotversion
});
if (moocConfig.version < json.version) {
var p = document.createElement('p');
p.style.color = "#ff0000";
p.innerHTML = '有新的版本更新:<a href="' + json.url + '" style="float:right;" target="_blank">点我去下载</a> 最新版本:v' + json.version;
document.getElementsByTagName('body')[0].appendChild(p);
}
document.getElementById("injection").innerHTML = json.injection
document.getElementById('version').innerHTML = 'v' + (moocConfig.version > json.hotversion ? moocConfig.version : json.hotversion);
}).error(function () {
chrome.storage.local.set({
'version': moocConfig.version,
'url': moocConfig.url,
'enforce': moocConfig.enforce,
'hotversion': moocConfig.version,
});
document.getElementById("tiku").src = "https://img.shields.io/badge/%E9%A2%98%E5%BA%93-error-red.svg"
});
document.getElementById('dama').onclick = function () {
document.getElementById('dama-config').style.height = document.getElementById('dama-config').style.height == '80px' ? '0' : '80px';
}
xhr.send();
chrome.storage.sync.get(['rand_answer', 'video_mute', 'answer_ignore'], function (items) {
document.getElementById('video-mute').checked = (items.video_mute == undefined ? true : items.video_mute);
delete items.video_mute;
for (item in items) {
document.getElementById(item.replace('_', '-')).checked = items[item];
}
......@@ -29,7 +72,7 @@ window.onload = function () {
});
chrome.storage.sync.get('auto', function (items) {
document.getElementById('auto').checked = items.auto;
document.getElementById('auto').checked = (items.auto == undefined ? true : items.auto);
document.getElementById('auto').onchange();
});
......@@ -38,6 +81,7 @@ window.onload = function () {
});
document.getElementById('answer-ignore').onclick = function () {
sendConfig('answer_ignore', document.getElementById('answer-ignore').checked);
chrome.storage.sync.set({
'answer_ignore': document.getElementById('answer-ignore').checked
});
......@@ -45,6 +89,7 @@ window.onload = function () {
}
document.getElementById('rand-answer').onclick = function () {
sendConfig('rand_answer', document.getElementById('rand-answer').checked);
chrome.storage.sync.set({
'rand_answer': document.getElementById('rand-answer').checked
});
......@@ -52,6 +97,7 @@ window.onload = function () {
}
document.getElementById('video-mute').onclick = function () {
sendConfig('video_mute', document.getElementById('video-mute').checked);
chrome.storage.sync.set({
'video_mute': document.getElementById('video-mute').checked
});
......@@ -59,7 +105,7 @@ window.onload = function () {
}
document.getElementById('auto').onchange = function () {
check = document.getElementById('auto');
let check = document.getElementById('auto');
if (check.checked) {
document.getElementById('auto-m').style.display = 'inline-block';
document.getElementById('ignore').style.display = '';
......@@ -67,18 +113,51 @@ window.onload = function () {
document.getElementById('auto-m').style.display = 'none';
document.getElementById('ignore').style.display = 'none';
}
sendConfig('auto', check.checked);
chrome.storage.sync.set({
'auto': check.checked
});
}
document.getElementById('interval').onblur = function () {
sendConfig('interval', document.getElementById('interval').value);
chrome.storage.sync.set({
'interval': document.getElementById('interval').value
});
}
document.getElementById('video-multiple').onblur = function () {
if (localStorage['boom_multiple'] == undefined || localStorage['boom_multiple'] != 1) {
let msg = prompt('这是一个很危险的功能,建议不要进行调整,如果你想调整播放速度请在下方填写yes')
if (msg === null || msg !== 'yes') {
document.getElementById('video-multiple').value = 1;
return;
} else {
localStorage['boom_multiple'] = 1;
}
}
sendConfig('video_multiple', document.getElementById('video-multiple').value);
chrome.storage.sync.set({
'video_multiple': document.getElementById('video-multiple').value
});
}
}
\ No newline at end of file
}
//实现GM_xmlhttpRequest(兼容油猴),完成跨域
common.serverMessage('GM_xmlhttpRequest', function (param, sendResponse) {
//向background发送消息
let connect = chrome.runtime.connect({ name: 'tools' });
connect.postMessage({ type: "GM_xmlhttpRequest", param: param });
connect.onMessage.addListener(function (response) {
if (response.type == 'GM_xmlhttpRequest') {
sendResponse(response);
}
});
});
//即时同步配置
function sendConfig(key, value) {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
for (let i = 0; i < tabs.length; i++) {
chrome.tabs.sendMessage(tabs[i].id, { type: 'config', 'key': key, 'value': value });
}
});
}
const moocConfig = require('../config');
const common = require('./common');
window.onload = function () {
(function () {
//注入mooc.js
chrome.storage.local.get(['version', 'url', 'enforce'], function (items) {
chrome.storage.local.get(['version', 'url', 'enforce', 'hotversion'], function (items) {
console.log(items);
let serverConfig = items;
if (items.version > moocConfig.version) {
if (items.enforce) {
alert('刷课扩展要求强制更新');
......@@ -19,15 +21,51 @@ window.onload = function () {
'video_mute',
'answer_ignore',
'video_multiple',
'vtoken',
'is_ruokuai', 'ruokuai_user', 'ruokuai_pwd'
], function (items) {
items.interval = items.interval >= 0 ? items.interval : 5;
items.rand_answer = items.rand_answer || false;
items.video_multiple = items.video_multiple || 1;
items.video_mute = items.video_mute || false;
items.video_mute = items.video_mute == undefined ? true : items.video_mute;
items.auto = items.auto == undefined ? true : items.auto;
//热更新处理
let littleVersion = serverConfig.hotversion - moocConfig.version
let isHotUpdate = false;
if (littleVersion < 0.01 && littleVersion > 0) {
//切换热更新
console.log('use hot update version:' + serverConfig.hotversion);
isHotUpdate = serverConfig.hotversion;
}
//设置一下配置
localStorage['rand-answer'] = items.rand_answer;
items.vtoken = items.vtoken || 'user|' + (isHotUpdate || moocConfig.version);
localStorage['config'] = JSON.stringify(items);
common.injected(document, chrome.extension.getURL('src/mooc.js'));
console.log(items);
if (isHotUpdate) {
//拥有一个热更新版本
common.injected(document, moocConfig.url + 'js/' + isHotUpdate + '.js');
} else {
common.injected(document, chrome.extension.getURL('src/mooc.js'));
}
});
})
}
})();
//实现GM_xmlhttpRequest(兼容油猴),完成跨域
common.serverMessage('GM_xmlhttpRequest', function (param, sendResponse) {
//向background发送消息
let connect = chrome.runtime.connect({ name: 'tools' });
connect.postMessage({ type: "GM_xmlhttpRequest", param: param });
connect.onMessage.addListener(function (response) {
if (response.type == 'GM_xmlhttpRequest') {
sendResponse(response);
}
});
});
//监听配置改动
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.type && request.type == 'config') {
common.clientMessage('cxconfig').send(request);
}
});
const css = require('../html/common.css');
const common = require('../common');
module.exports = {
btn: undefined,
stuExam: function () {
let self = this;
let timer = setInterval(function () {
let ul = $('.examPaper_partTit.mt20 ul');
if (ul.length <= 0) {
return;
}
if ($('.examInfo.infoList.clearfix').length > 0) {
//答案采集
self.collect();
} else {
self.btn = $(ul).append($('<li><button class="zhs-search-answer green">搜索答案</button></li>')).find('button');
$(self.btn).click(() => { self.searchAnswer() });
}
clearInterval(timer);
}, 1000);
},
getTopicList: function () {
let topic = $('.examPaper_subject.mt20');
let ret = [];
for (let i = 0; i < topic.length; i++) {
let text = common.removeHTML($(topic[i]).find('.subject_stem.clearfix').html());
let type = common.switchTopicType(common.substrEx(text, '', ''));
let options = $(topic[i]).find('.subject_node.mt10');
if (type == -1) {
common.signleLine('暂不支持的类型', 'answer' + i, undefined, topic.options);
continue;
}
text = text.substr(text.indexOf(') ') + ') '.length);
ret.push({
topic: text,
type: type,
options: options,
index: i
});
}
return ret;
},
findOption: function (options, type) {
if (type <= 3) {
return $(options).find('.examquestions-answer');
} else if (type == 4) {
return $(options).find('textarea');
}
},
isTrue: function (options, correct, type) {
if (type <= 2) {
for (let i = 0; i < options.length; i++) {
let tmpContent = common.removeHTML($(options[i]).html());
if (tmpContent == correct.content) {
$(options[i]).parent().find('input').click();
return true;
}
}
}
return false;
},
searchAnswer: function () {
let self = this;
let topic = this.getTopicList();
$(self.btn).text('搜索中...');
common.requestAnswer(topic, 'zhs', 0,
function (topic, answer) {
let index = topic.index;
if (answer == undefined) {
common.signleLine('无答案', 'answer' + index, undefined, topic.options);
return;
}
//填写答案
let text = common.fillAnswer(topic, answer, {
select: (options, correct) => {
$(options).parent().find('input').removeAttr('checked');
return common.fillSelect(options, correct, self.isTrue);
},
judge: (options, correct) => {
correct = correct[0];
common.oaForEach(options, function (item) {
let tmpContent = common.removeHTML($(item).html());
if ({ '': true, '': false }[tmpContent] == correct.option) {
$(item).parent().find('input').click();
return true;
}
});
return '答案:' + correct.option;
},
text: (options, correct) => {
let retNotic = '';
common.oaForEach(options, function (item, index) {
common.oaForEach(correct, function (item2) {
if (common.numToZh(index + 1) == item2.option) {
$(item).val(item2.content);
retNotic += '' + item2.option + '空:' + item2.content+'<br/>';
}
});
});
return retNotic;
},
other: () => { return '暂不支持的类型'; }
}, self.findOption);
if (text == '') {
return common.signleLine('没有合适的答案', 'answer' + index, undefined, topic.options);;
}
common.signleLine(text, 'answer' + index, undefined, topic.options[topic.options.length-1]);
},
() => { $(self.btn).text('搜索完成'); },
() => { $(self.btn).text('网络错误'); },
);
},
collect: function () {
let self = this;
let topic = option = this.getTopicList();
common.postAnswer(topic, 'zhs', function (topic) {
if ($(topic.options).find('.key_yes').length <= 0) {
return undefined;
}
let pushOption = { topic: topic.topic, type: topic.type, answers: [], correct: [] };
let options = self.findOption(topic.options, topic.type);
switch (topic.type) {
case 1:
case 2: {
for (let i = 0; i < options.length; i++) {
let tmpContent = common.removeHTML($(options[i]).html());
let tmp = {
option: String.fromCharCode((65 + i)),
content: tmpContent
};
pushOption.answers.push(tmp);
if ($(options[i]).parent().find('input').attr('checked')) {
pushOption.correct.push(tmp);
}
}
break;
}
case 3: {
for (let i = 0; i < options.length; i++) {
let tmpContent = common.removeHTML($(options[i]).html());
if ($(options[i]).parent().find('input').attr('checked')) {
pushOption.correct.push({ option: tmpContent == '', content: tmpContent == '' });
}
}
break;
}
case 4: {
return undefined;
}
}
return pushOption;
}, function () {
let box = common.pop_prompt("√ 答案自动记录成功");
$(document.body).append(box);
setTimeout(function () { box.style.opacity = "1"; }, 500);
});
}
}
\ No newline at end of file
export function createVideoButton(){
}
\ No newline at end of file
const css = require('../html/common.css');
const common = require('../common');
module.exports = {
id: undefined,
innerTimer: undefined,
videoInfo: undefined,
compile: function () {
if ($('.progressbar_box_tip').text().indexOf('100%') < 0) {
return;
}
//完成切换
common.log('zhs video switch');
let self = this;
this.innerTimer && clearTimeout(this.innerTimer);
this.innerTimer = setTimeout(function () {
config.auto && $(self.id + ' #nextBtn').click();
}, config.duration);
},
start: function () {
let self = this;
self.createToolsBar();
//hook智慧树视频
let hookPlayerStarter = PlayerStarter;
PlayerStarter.hookCreatePlayer = PlayerStarter.createPlayer;
PlayerStarter.createPlayer = function ($container, options, callback) {
self.innerTimer && clearTimeout(self.innerTimer);
self.id = $container.selector;
let hookPause = callback.onPause;
let hookComplete = callback.onComplete;
let hookReady = callback.onReady;
let video = undefined;
callback.onReady = function () {
console.log('准备');
hookReady();
//倍速,启动!
video = $(self.id + ' video')[0]
video.playbackRate = config.video_multiple;
//又是以防万一的暂停,顺带检测进度
self.innerTimer = setInterval(function () {
try {
config.auto && video.play();
} catch (e) { }
if ($('.progressbar_box_tip').text().indexOf('100%') >= 0) {
self.compile();
}
}, 10000);
}
callback.onPause = function () {
console.log('暂停');
hookPause();
config.auto && video.play();
}
callback.onComplete = function () {
console.log('完成');
hookComplete();
}
if (config.video_mute) {
options.volume = 0;
}
console.log(options);
options.autostart = true;
// options.control.nextBtn = true;
this.hookCreatePlayer($container, options, callback);
}
},
createToolsBar: function () {
let tools = $('<div class="entrance_div" id="cxtools"><ul></ul></div>');
let boomBtn = $('<li><a href="#" id="zhs-video-boom">秒过视频</a></li>');
let self = this;
$(tools).find('ul').append(boomBtn);
$(boomBtn).click(function () {
if (common.boom_btn()) {
self.sendBoomPack();
}
});
$('.videotop_box.clearfix').append(tools);
},
sendBoomPack: function () {
//发送秒过包
//ev算法
let evFun = D26666.Z;
let timeStr = $('#video-' + this.videoInfo.videoId + ' .time.fl').text();
let time = 0;
let temp = timeStr.match(/[\d]+/ig);
for (let i = 0; i < 3; i++) {
time += temp[i] * Math.pow(60, 2 - i);
}
time += common.randNumber(60, 666);
let ev = [
this.videoInfo.rid, this.videoInfo.chapterId, this.videoInfo.courseId, this.videoInfo.lessonId,
timeStr, time, this.videoInfo.videoId, (this.videoInfo.lessonVideoId && this.videoInfo.lessonVideoId != null ? this.videoInfo.lessonVideoId : 0)
];
let postData = '__learning_token__=' + encodeURIComponent(btoa('' + this.videoInfo.studiedLessonDto.id)) + '&watchPoint=' +
'&ev=' + evFun(ev) + (this.videoInfo.lessonVideoId && this.videoInfo.lessonVideoId != null ? '&lessonVideoId=' + this.videoInfo.lessonVideoId : '');
common.post('/json/learning/saveCacheIntervalTime?time=' + (new Date().valueOf()), postData, false, function (res) {
let json = JSON.parse(res);
if (json.studyTotalTime >= time) {
alert('秒过成功,刷新后查看效果');
} else {
alert('秒过失败');
}
});
},
hookAjax: function () {
let self = this;
window.hookXMLHttpRequest = window.hookXMLHttpRequest || XMLHttpRequest;
XMLHttpRequest = function () {
let retAjax = new window.hookXMLHttpRequest();
retAjax.hookOpen = retAjax.open;
retAjax.open = function (p1, p2, p3, p4, p5) {
if (p2.indexOf('learning/loadVideoPointerInfo') >= 0) {
console.log('题目来了');
//TODO:先实现屏蔽题目,后面实现自动填充(虽然这好像没有意义)
Object.defineProperty(retAjax, 'responseText', {
get: function () {
let retText = retAjax.response.replace(/"lessonDtoMap":{.*?},"lessonId"/gm, '"lessonDtoMap":{},"lessonId"');;
return retText;
}
});
} else if (p2.indexOf('learning/prelearningNote') >= 0) {
//拦截数据
Object.defineProperty(retAjax, 'responseText', {
get: function () {
self.videoInfo = JSON.parse(retAjax.response);
return retAjax.response;
}
});
}
return retAjax.hookOpen(p1, p2, p3, p4, p5);
}
return retAjax;
}
}
}
\ No newline at end of file
const video = require('./video');
const topic = require('./topic');
module.exports = {
video: function () {
video.hookAjax();
let timer = setInterval(function () {
try {
video.start();
clearInterval(timer);
} catch (e) { }
}, 499);
},
stuExam: function () {
topic.stuExam();
}
};
const fs = require('fs');
const ChromeExtension = require('crx');
const config = require('./config')
const { exec } = require('child_process');
let version = dealVersion(config.version)
// build manifest
......@@ -14,6 +13,7 @@ const crx = new ChromeExtension({
});
crx.load(['./build/cxmooc-tools/manifest.json',
'./build/cxmooc-tools/img/navtu.webp',
'./build/cxmooc-tools/img/logo.png',
'./build/cxmooc-tools/src/*'
]).then(crx => crx.pack()).then(crxBuffer => {
......@@ -23,12 +23,15 @@ crx.load(['./build/cxmooc-tools/manifest.json',
});
// build tampermonkey
exec('webpack --mode development --config webpack.config.js', function () {
let tampermonkey = fs.readFileSync('tampermonkey.js')
tampermonkey = tampermonkey.toString().replace(/@version\s+.*/, '@version ' + version)
tampermonkey += fs.readFileSync('./build/cxmooc-tools/src/mooc.js')
fs.writeFileSync('./build/tampermonkey.js', tampermonkey)
})
let tampermonkey_cx = fs.readFileSync('./src/tampermonkey/cxmooc.js');
tampermonkey_cx = tampermonkey_cx.toString().replace(/@version\s+.*/, '@version ' + config.getHotVersion());
tampermonkey_cx += fs.readFileSync('./build/tampermonkey-cxmooc.js');
fs.writeFileSync('./build/cxmooc.js', tampermonkey_cx);
let tampermonkey_zhs = fs.readFileSync('./src/tampermonkey/zhihuishu.js');
tampermonkey_zhs = tampermonkey_zhs.toString().replace(/@version\s+.*/, '@version ' + config.getHotVersion());
tampermonkey_zhs += fs.readFileSync('./build/tampermonkey-zhihuishu.js');
fs.writeFileSync('./build/zhihuishu.js', tampermonkey_zhs);
function dealVersion(version) {
let reg = /\d/g;
......
......@@ -4,47 +4,46 @@ const app = express();
const moocModel = require('./mooc');
const md5 = require("md5");
const config = require('../config');
var path = require('path');
var fs = require('fs');
const serverConfig = require('./config');
const path = require('path');
const fs = require('fs');
const http = require('http');
const https = require('https');
const redisCli = require('./redis');
const vcodePack = require('./vcode');
var privateKey = fs.readFileSync(path.join(__dirname, './certificate/private.key'), 'utf8');
var certificate = fs.readFileSync(path.join(__dirname, './certificate/file.crt'), 'utf8');
var credentials = {
key: privateKey,
cert: certificate
};
var httpServer = http.createServer(app);
var httpsServer = https.createServer(credentials, app);
var PORT = 8080;
var SSLPORT = 8081;
const PORT = 8080;
const SSLPORT = 8081;
var httpServer = http.createServer(app);
//创建http服务器
httpServer.listen(PORT, function () {
console.log('HTTP Server is running on: http://localhost:%s', PORT);
});
//创建https服务器
httpsServer.listen(SSLPORT, function () {
console.log('HTTPS Server is running on: https://localhost:%s', SSLPORT);
});
if (serverConfig.env == 'prod') {
var privateKey = fs.readFileSync(path.join(__dirname, './certificate/private.key'), 'utf8');
var certificate = fs.readFileSync(path.join(__dirname, './certificate/file.crt'), 'utf8');
var credentials = {
key: privateKey,
cert: certificate
};
var httpsServer = https.createServer(credentials, app);
//创建https服务器
httpsServer.listen(SSLPORT, function () {
console.log('HTTPS Server is running on: https://localhost:%s', SSLPORT);
});
var vcode = new vcodePack();
}
app.set('trust proxy', 'loopback, 127.0.0.1/8');
var mooc = new moocModel();
var redis = new redisCli();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.all('/player/*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
next();
});
app.use(express.static(path.join(__dirname, 'static'), {
maxage: '7d'
}));
......@@ -56,32 +55,48 @@ app.get('/', function (req, res) {
res.send(ret);
})
app.all('/(|v2/)answer', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
//在线人数中间件
app.use(function (req, res, next) {
var ip = getClientIp(req);
redis.onlineAdd(ip);
res.header("Access-Control-Allow-Origin", req.headers['origin']);
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization,Accept,X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
if (req.method == "OPTIONS") {
res.send(200);
return res.status(200).send('success');
} else {
next();
return next();
}
})
});
app.all('/player/*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
next();
});
app.post('/answer', function (req, res) {
let token = req.header('Authorization') || '';
let platform = req.query.platform || 'cx';
var ip = getClientIp(req);
var ret = [];
if (req.body.length <= 0) {
res.send({
return res.send({
code: 0,
msg: 'success'
});
return;
}
let num = 0;
for (let i in req.body) {
let topic = req.body[i];
if (topic.correct == undefined || topic.type == undefined || topic.topic == undefined) {
if (topic.correct == undefined || topic.type == undefined || topic.topic == undefined ||
topic.correct.length <= 0 || topic.type.length <= 0 || topic.topic.length <= 0
) {
continue;
}
num++;
let type = parseInt(topic.type);
let hash = md5(topic.topic + type.toString());
let cond = {
......@@ -95,9 +110,11 @@ app.post('/answer', function (req, res) {
cond.hash = data.hash;
data.ip = ip;
data.time = Date.parse(new Date());
data.platform = platform;
data.token = token;
mooc.insert('answer', data);
} else if (type == 4 && result.type == 4) {
//填空,答案合并
} else if ((type == 4 && result.type == 4) || (type == 2 && result.type == 2)) {
//填空多选,答案合并
try {
let correct = mergeAnswer(result.correct, topic.correct);
mooc.updateOne('answer', cond, {
......@@ -110,7 +127,7 @@ app.post('/answer', function (req, res) {
}
}
ret.push(cond);
if (ret.length == req.body.length) {
if (ret.length == num) {
res.send({
code: 0,
msg: 'success',
......@@ -143,33 +160,35 @@ function mergeAnswer(source, answer) {
}
app.get('/update', function (req, res) {
res.send({
version: config.version,
url: config.update,
enforce: config.enforce,
injection: config.injection
redis.onlineNum(function (err, data) {
//分发各个版本热更新
let hotversion = config.getHotVersion(req.query.ver || config.version);
return res.send({
version: config.version,
url: config.update,
enforce: config.enforce,
injection: config.injection,
onlinenum: data,
hotversion: hotversion
});
});
})
function getClientIp(req) {
return req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress;
return req.ip || 'error-ip';
}
app.post('/v2/answer', function (req, res) {
var topic = req.body.topic || [];
var type = req.body.type || [];
let platform = req.query.platform || 'cx';
selectAnswer(topic, res, function (i) {
var where = {};
topic[i] = dealSymbol(topic[i]);
var topic_n = topic[i];
let where = {};
let topic_n = dealSymbol(topic[i].replace(/[-\/\\^$*+?.|[\]{}]/g, '\\$&'));
// topic[i] = topic;
if (type[i] != undefined) {
where = { topic: { $regex: topic_n }, type: parseInt(type[i]) };
} else {
where = { topic: { $regex: topic_n } };
where = { type: parseInt(type[i]) };
}
where.topic = { $regex: '^'+topic_n };
return where;
});
});
......@@ -186,6 +205,7 @@ function dealSymbol(topic) {
app.get('/answer', function (req, res) {
var topic = req.query.topic || [];
let platform = req.query.platform || 'cx';
selectAnswer(topic, res, function (i) {
return { topic: topic[i] };
});
......@@ -194,11 +214,10 @@ app.get('/answer', function (req, res) {
function selectAnswer(topic, res, where) {
var ret = [];
if (topic.length <= 0) {
res.send({
return res.send({
code: 0,
msg: 'success'
});
return;
}
for (let i = 0; i < topic.length; i++) {
mooc.find('answer', where(i), {
......@@ -210,7 +229,7 @@ function selectAnswer(topic, res, where) {
time: 1,
correct: 1
}
}).limit(10).toArray(function (err, result) {
}).limit(5).toArray(function (err, result) {
var pushData = {
topic: topic[i],
index: i
......@@ -220,8 +239,61 @@ function selectAnswer(topic, res, where) {
}
ret.push(pushData);
if (ret.length == topic.length) {
res.send(ret);
return res.send(ret);
}
});
}
}
\ No newline at end of file
}
//api统计
app.use('/vcode', function (req, res, next) {
var ip = getClientIp(req);
//限制,ua 12,ip 80
redis.callStatis('vcode');
let ua = req.get('User-Agent');
if (!ua) {
return res.send({ code: -1, msg: 'ua null' });
}
redis.vtoken(req.header('Authorization') || '', function (val) {
redis.apiLimit('vcode', ua, 12, ip);
if (val > 0) {
redis.callStatis('vcode-vtoken', req.header('Authorization'));
return next();
} else {
return res.send({ code: -2, msg: '超出限制,<a href="https://github.com/CodFrm/cxmooc-tools/issues/74" target="_blank">请点击查看详情</a>' });
}
});
});
app.post('/vcode', function (req, res) {
if (req.body.img.length <= 0) {
return res.send({ code: -1, msg: 'img null' });
}
vcode.vcodesend(new Buffer(req.body.img, 'base64'), function (pack) {
if (pack != undefined && pack.data != undefined && pack.data != '') {
redis.callStatis('vcode-success');
res.send({ code: 0, msg: pack.data });
} else {
res.send({ code: -1, msg: 'error' });
}
});
});
app.use('/gen-token', function (req, res) {
if (req.query.token != serverConfig.genToken) {
return res.send('e');
}
if (!req.query.user) {
return res.send('e1');
}
redis.hget('cxmooc:genuser', req.query.user, function (err, val) {
if (val != undefined) {
return res.send({ code: 1, token: val });
} else {
let retToken = Math.random().toString(36).substr(2);
redis.hset('cxmooc:genuser', req.query.user, retToken);
redis.set('cxmooc:vtoken:' + retToken, 100);
res.send({ code: 1, token: retToken });
}
});
});
\ No newline at end of file
var redis = require('redis');
module.exports = function () {
var client = redis.createClient(6379, "127.0.0.1");
client.on("error", function (err) {
console.log("Redis error:" + err);
});
this.onlineAdd = function (ip) {
client.zadd("cxmooc:online", [(new Date()).valueOf(), ip]);
}
this.onlineNum = function (call) {
var time = (new Date()).valueOf();
client.zcount("cxmooc:online", [time - (5 * 60 * 1000), time], function (err, res) {
call(err, res)
});
}
this.callStatis = function (api, param) {
let date = new Date();
client.hincrby("cxmooc:api-statis-" + api, (param ? param + '_' : '') + date.getFullYear() + '_' + (date.getMonth() + 1) + '_' + (date.getDate()), 1);
}
this.apiLimit = function (api, ua, max, ip, numCall) {
let key = "cxmooc:" + api + "-limit-" + (new Date()).getDate();
client.hincrby('u_i_' + key, ua + ip, 1, function (err1, num1) {
if (num1 > max) {
return numCall && numCall(num1, 0);
}
client.hincrby('i_' + key, ip, 1, function (err2, num2) {
numCall && numCall(num1, num2);
});
});
}
this.vtoken = function (token, callback) {
if (!token) {
return callback && callback(0);
}
client.decr('cxmooc:vtoken:' + token, function (err, res) {
callback && callback(res);
});
}
this.set = function (key, value) {
client.set(key, value);
}
this.hget = function (key, field, callback) {
client.hget(key, field, callback);
}
this.hset = function (key, field, value, callback) {
client.hset(key, field, value, callback);
}
this.hincrby = function (key, field, num, callback) {
client.hincrby(key, field, num, callback);
}
this.hexists = function (key, field, callback) {
client.hexists(key, field, callback);
}
this.exists = function (key, call) {
client.exists(key, call);
}
return this
}
\ No newline at end of file
*
!.gitignore
\ No newline at end of file
const net = require('net');
const config = require('./config');
const HashMap = require('hashmap');
const MAX_CONNECT = 10;
module.exports = function () {
//10连接池
let client = new Array(MAX_CONNECT)
let last = 0;
let task = new HashMap();
for (let i = 0; i < MAX_CONNECT; i++) {
client[i] = net.Socket();
function connect() {
client[i].connect(config.vcodeport, config.vcodehost, function () {
console.log('client connect success');
});
}
connect();
client[i].on('data', function (data) {
//解包
let pack = unpack(toArrayBuffer(data));
let send = task.get(pack.tag);
if (send != undefined && send.callback != undefined) {
send.callback(pack);
}
task.delete(pack.tag);
});
client[i].on("end", function () {
console.log("client disconnect,reconnect");
connect();
});
client[i].on("error", function () {
console.log("client error,reconnect");
connect();
});
client[i].on("onclose", function () {
console.log("client error,reconnect");
connect();
});
}
this.vcodesend = function (vcode, callback) {
let tag = randomWord(false, 8);
let send = {
version: 'v001',
tag: tag,
data: vcode
};
client[getSendIndex()].write(pack(send));
send.callback = callback;
task.set(tag, send);
}
function getSendIndex() {
last++;
if (last >= MAX_CONNECT) {
last = 0;
}
return last;
}
//定时删除超时任务
setInterval(function () {
let now = timestamp();
task.forEach(function (v, k) {
if (v.time + 15 < now) {
if (v.callback != undefined) {
v.callback();
}
task.delete(k);
}
});
}, 5000);
return this;
}
// type Packgee struct {
// Conn net.Conn
// Version [4]byte
// Len int32
// Tag [8]byte
// Time int64
// Data []byte
// }
function unpack(byte) {
let dataview = new DataView(byte);
let datalen = dataview.getInt32(4);
let time = dataview.getBigInt64(16);
return {
version: String.fromCharCode.apply(null, new Uint8Array(byte.slice(0, 4))),
len: datalen,
tag: String.fromCharCode.apply(null, new Uint8Array(byte.slice(8, 16))),
time: time,
data: String.fromCharCode.apply(null, new Uint8Array(byte.slice(24))),
}
}
function pack(struct) {
struct.len = struct.data.length + 24;
struct.time = timestamp();
let ret = new ArrayBuffer(struct.len);
let dataview = new DataView(ret);
dataview.setUint8(0, struct.version.charCodeAt(0))
dataview.setUint8(1, struct.version.charCodeAt(1))
dataview.setUint8(2, struct.version.charCodeAt(2))
dataview.setUint8(3, struct.version.charCodeAt(3))
dataview.setInt32(4, struct.len)
//tag
for (let i = 0; i < 8; i++) {
dataview.setUint8(8 + i, struct.tag.charCodeAt(i))
}
//time
dataview.getBigInt64(16, struct.time)
//data
for (let i = 0; i < struct.len - 24; i++) {
dataview.setUint8(24 + i, struct.data[i])
}
return toBuffer(ret);
}
function timestamp() {
var tmp = Date.parse(new Date()).toString();
tmp = tmp.substr(0, 10);
return tmp;
}
/**
* randomWord 产生任意长度随机字母数字组合
* @param randomFlag 是否任意长度 min-任意长度最小位[固定位数] max-任意长度最大位
* @param min
* @param max
* @returns {string}
*/
function randomWord(randomFlag, min, max) {
var str = "",
range = min,
arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
// 随机产生
if (randomFlag) {
range = Math.round(Math.random() * (max - min)) + min;
}
for (var i = 0; i < range; i++) {
pos = Math.round(Math.random() * (arr.length - 1));
str += arr[pos];
}
return str;
}
function toBuffer(ab) {
var buf = Buffer.alloc(ab.byteLength);
var view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
buf[i] = view[i];
}
return buf;
}
function toArrayBuffer(buf) {
var ab = new ArrayBuffer(buf.length);
var view = new Uint8Array(ab);
for (var i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return ab;
}
\ No newline at end of file
global.config = JSON.parse(localStorage['config']);
Object.defineProperty(global.config, 'duration', {
get: function () {
return (config.interval || 0.1) * 60000;
}
});
import './common';
const common = require('../cxmooc-tools/common');
const chaoxing = require('../cxmooc-tools/chaoxing/chaoxing');
window.onload = function () {
let cx = new chaoxing();
if (window.location.href.indexOf('mycourse/studentstudy?') > 0) {
//手机检测
if (common.isPhone()) {
if (confirm('移动设备刷课将带来一定的不良风险,点击确定解锁移动端任务点通过功能')) {
global.allowPhone = true;
}
}
//超星学习页面
document.addEventListener('load', function (ev) {
var ev = ev || event;
var _this = ev.srcElement || ev.target;
if (_this.id == 'iframe') {
cx.studentstudy();
}
}, true);
var frame = document.getElementById('iframe');
if (frame != null) {
cx.studentstudy();
}
} else if (window.location.href.indexOf('ztnodedetailcontroller/visitnodedetail') > 0) {
//超星阅读页面
cx.read();
} else if (window.location.href.indexOf('exam/test/reVersionTestStartNew') > 0) {
cx.exam();
} else if (window.location.href.indexOf('exam/test/reVersionPaperMarkContentNew') > 0) {
cx.collectExam();
} else if (window.location.href.indexOf('work/doHomeWorkNew') > 0) {
cx.homework();
}else if(window.location.href.indexOf('work/selectWorkQuestionYiPiYue')>0){
cx.collectHomeWork();
}
}
// ==UserScript==
// @name 超星慕课小工具
// @namespace https://github.com/CodFrm/cxmooc-tools
// @version 2.0.8
// @description 一个超星慕课刷课工具,火狐,谷歌,油猴支持.全自动任务,视频倍速秒过,作业考试题库,验证码自动打码(੧ᐛ੭挂科模式,启动)
// @author CodFrm
// @match *://*/mycourse/studentstudy?*
// @match *://*/ztnodedetailcontroller/visitnodedetail?*
// @match *://*/antispiderShowVerify.ac*
// @match *://*/html/processVerify.ac?*
// @match *://*/exam/test/reVersionPaperMarkContentNew?*
// @match *://*/exam/test/reVersionTestStartNew?*
// @grant GM_xmlhttpRequest
// @license MIT
// ==/UserScript==
let config = {
answer_ignore: false, //忽略题目,勾选此处将不会答题
auto: true, //全自动挂机,无需手动操作,即可自动观看视频等
interval: 5, //时间间隔,当任务点完成后,会等待5分钟然后跳转到下一个任务点
rand_answer: false, //随机答案,没有答案的题目将自动的生成一个答案
video_multiple: 1, //视频播放倍速,视频播放的倍数,建议不要改动,为1即可,这是危险的功能
video_mute: true, //视频静音,视频自动静音播放
vtoken: "user", //鉴权token
is_ruokuai: false, //使用若快打码
ruokuai_user: "", //若快打码账号
ruokuai_pwd: "" //若快打码密码
};
localStorage['config'] = JSON.stringify(config);
import './common';
const zhihuishu = require('../cxmooc-tools/zhihuishu/zhihuishu');
if (window.location.href.indexOf('zhihuishu.com/learning/videoList') > 0) {
zhihuishu.video();
} else if (window.location.href.indexOf('stuExamWeb.htm') > 0) {
zhihuishu.stuExam();
}
\ No newline at end of file
// ==UserScript==
// @name 智慧树小工具
// @namespace https://github.com/CodFrm/cxmooc-tools
// @version 2.0.7
// @description 一个知到智慧树的小工具,火狐,谷歌,油猴支持.支持视频倍速秒过,屏蔽题目(੧ᐛ੭挂科模式,启动)
// @author CodFrm
// @run-at document-start
// @match *://study.zhihuishu.com/learning/videoList*
// @grant none
// @license MIT
// ==/UserScript==
let config = {
auto: true, //全自动挂机,无需手动操作,即可自动观看视频等
interval: 5, //时间间隔,当任务点完成后,会等待5分钟然后跳转到下一个任务点
rand_answer: false, //随机答案,没有答案的题目将自动的生成一个答案
video_multiple: 1, //视频播放倍速,视频播放的倍数,建议不要改动,为1即可,这是危险的功能
video_mute: true, //视频静音,视频自动静音播放
vtoken: "user", //鉴权token
};
localStorage['config'] = JSON.stringify(config);
const TelegramBot = require('node-telegram-bot-api');
const fs = require("fs");
const { exec } = require('child_process');
const config = require('./config');
const botToken = process.env.BOT_TOKEN || '';
const chat_id = process.env.GROUP_ID || '';
const commit_range = process.env.TRAVIS_COMMIT_RANGE || '';
const branch = process.env.TRAVIS_BRANCH || 'develop';
const tag = process.env.TRAVIS_TAG || false;
const tgBot = new TelegramBot(botToken, { polling: false });
let lastTag = '';
if (branch == tag) {
//获取上一个tag
exec('git describe --tags HEAD^^', (err, stdout, stderr) => {
let match = stdout.toString().match(/([v\.\d]+)-/);
lastTag = match[1];
push();
});
} else {
push();
}
function push() {
let range = commit_range;
if (branch == tag) {
range = tag + '...' + lastTag;
}
exec('git log --pretty=format:"%s" ' + range + (range.search('.') < 0 ? ' -1' : ''), (err, stdout, stderr) => {
let sendText = '';
let end = '';
if (branch == tag) {
sendText += "*有一个新版本发布*\n";
end = '\n[前去release查看](https://github.com/CodFrm/cxmooc-tools/releases)';
} else if (branch == 'develop') {
sendText += "*有一个内测版本发布*\n";
end = '如果发现有什么BUG,记得[反馈](https://github.com/CodFrm/cxmooc-tools/issues)哦';
} else if (branch == 'hotfix') {
//热修复处理
sendText += "*有一个bug修复,准备热更新*\n";
sendText += hotUpdate();
}
sendText += "更新了以下内容:\n```\n" + stdout + "\n```\n" + end;
console.log(sendText);
tgBot.sendMessage(chat_id, sendText, { parse_mode: 'Markdown' });
tgBot.sendDocument(chat_id, fs.createReadStream('build/cxmooc-tools.crx'));
});
}
function hotUpdate() {
let ret = '热更新版本号为:' + (config.hotversion[('v' + config.version).replace('.', '_')]) + "\n";
return ret;
}
\ No newline at end of file
// ==UserScript==
// @name 超星慕课小工具
// @namespace https://github.com/CodFrm/cxmooc-tools
// @version 2.0.0
// @description 一个快速学习超星慕课的chrome扩展工具(੧ᐛ੭挂科模式,启动)
// @author CodFrm
// @match *://*/mycourse/studentstudy?*
// @match *://*/ztnodedetailcontroller/visitnodedetail?*
// @grant none
// ==/UserScript==
let config = {
answer_ignore: true, //忽略题目
auto: true, //全自动挂机
interval: "5", //时间间隔
rand_answer: true, //随机答案
video_multiple: "1", //视频播放倍速
video_mute: true, //视频静音
};
localStorage['config'] = JSON.stringify(config);
......@@ -22,5 +22,13 @@ module.exports = {
},
chunks: ['popup']
})
]
],
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
}
]
}
}
\ No newline at end of file
module.exports = {
mode: 'development',
entry: {
cxmooc: __dirname + '/src/tampermonkey/cxmooc-pack.js',
zhihuishu: __dirname + '/src/tampermonkey/zhihuishu-pack.js',
},
output: {
path: __dirname + '/build',
filename: 'tampermonkey-[name].js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
}
]
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册