Skip to content
This repository has been archived by the owner on Dec 2, 2023. It is now read-only.

Commit

Permalink
Finnished test task.
Browse files Browse the repository at this point in the history
  • Loading branch information
TurboHsu committed Mar 17, 2023
1 parent de502e1 commit eec39cf
Show file tree
Hide file tree
Showing 9 changed files with 380 additions and 39 deletions.
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

### WIP
- 正在尝试让他自动化。
- 测试任务
- 测试任务 (已完成一部分)

### Tip
使用```-proxy=false```参数可以使程序在打开时不对系统代理进行操作
Expand All @@ -23,17 +23,30 @@
3. **维护者目前只接触到CET4的一些课堂任务,只见过部分题型,(题型一样TopicMode也可能不同),后续遇到相关题型我会继续更新。**

### 如何使用?
#### 学习任务
1. 下载release中的压缩包并且解压
2. 运行vocab-master,他会在对应平台的应用数据存储区中生成cert文件夹,只需要将其中的.cer文件添加到系统的信任根证书中。这个文件夹可以用程序中的一个按钮打开。
3. 对于Windows,你需要把Release中的fonts拷贝到程序数据文件夹和cert同级的目录中,不然你可能看不到中文。(打算重构UI,这个问题将会得到解决。)
4. 打开一个课堂任务,```重新选词```,and feel great ;)

#### 测试任务
** 测试任务需要您获取全部词库,参见数据库控制台 **
1. 在打开词达人之前打开程序,勾选```Javascript Hijack```,以绕过手机端检测。
2. 导入词库。
3. You nailed it.

### 关于数据控制台
#### 导入数据
点击导入数据,选一个数据文件打开即可。
#### 抓取数据
1. 抓取词库时,首先勾选```Fetch Identify```,启用Cookie/Header抓取。
2. 输入Course ID。他可能长这样:```CET6_hx```
3. 点击开始抓取,为了保证不达到单个```Token```达到使用限制,请您在程序抓取时**不断操作词达人**,你只需要到处点点,浏览浏览词汇。注意控制台输出。
4. 结束后可导出。存到你喜欢的地方即可。

### 我要编译
这是个go module,go ahead!

#### 关于项目的开发
自学任务由于需要再次分析,暂时搁置。

### 鸣谢
- [fyne.io](https://fyne.io)
- [github.com/Trisia/gosysproxy](https://github.com/Trisia/gosysproxy)
Expand Down
26 changes: 26 additions & 0 deletions answer/find.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package answer

import (
"fmt"
"log"
"regexp"
"sort"
"strings"
Expand All @@ -11,6 +13,26 @@ var WordList []WordInfo
func FindAnswer(topicID int, vocabTaskInfo VocabTaskStruct, rawJSON string) (ans Answer) {
// Do stuff
switch topicID {
// Choose translation from word
case 15:
stemTrimed := strings.ReplaceAll(vocabTaskInfo.Stem.Content, " ", "")
Loop15:
for i := 0; i < len(WordList); i++ {
if WordList[i].Word == stemTrimed {
// Match the translation
for j := 0; j < len(WordList[i].Content); j++ {
for k := 0; k < len(vocabTaskInfo.Options); k++ {
if compareTranslation(WordList[i].Content[j].Meaning, vocabTaskInfo.Options[k].Content) {
ans.Found = true
ans.Detail.Translation = WordList[i].Content[j].Meaning
ans.Index = append(ans.Index, k)
break Loop15
}
}
}
}
}

// Choose translation based on some word
case 11:
stemConverted := strings.ReplaceAll(vocabTaskInfo.Stem.Content, " ", " ")
Expand All @@ -34,6 +56,9 @@ func FindAnswer(topicID int, vocabTaskInfo VocabTaskStruct, rawJSON string) (ans
break
}
}
// Debug
log.Println(vocabTaskInfo.Options)


// Choose translation based on some voice
case 22:
Expand Down Expand Up @@ -137,6 +162,7 @@ func FindAnswer(topicID int, vocabTaskInfo VocabTaskStruct, rawJSON string) (ans
}
}

log.Println("[I] Found ans: " + fmt.Sprintln(ans))
return
}

Expand Down
4 changes: 4 additions & 0 deletions automatic/auto.go
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,10 @@ func startAutomation() {
break MainLoop
}


time.Sleep(1 * time.Second)


// Submit and save it
var submitAnswerAndSaveData SubmitAnswerAndSaveStruct
submitAnswerAndSaveData.TopicCode = topicCode
Expand Down
29 changes: 10 additions & 19 deletions grab/grab.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package grab

import (
"compress/flate"
"compress/gzip"
"encoding/base64"
"encoding/json"
"fmt"
Expand All @@ -14,9 +12,13 @@ import (
"time"

"github.com/TurboHsu/Vocab-Master/answer"
"github.com/andybalholm/brotli"
)

var DatasetValid bool
var FetchIdentity bool
var IsDatabaseLoaded bool
var Dataset VocabDataset

func GrabWord(word string, dataset *VocabDataset, delay int) {
time.Sleep(time.Duration(delay) * time.Millisecond)
url := fmt.Sprintf("https://app.vocabgo.com/student/api/Student/Course/StudyWordInfo?course_id=%s&list_id=%s&word=%s&timestamp=%d&version=%s&app_type=1",
Expand All @@ -38,10 +40,14 @@ func GrabWord(word string, dataset *VocabDataset, delay int) {
log.Println("[E]" + err.Error())
}
defer response.Body.Close()
read, _ := switchContentEncoding(response)
read, _, _ := switchContentEncoding(response)
raw, _ := io.ReadAll(read)
var rawData VocabRawJSONStruct
json.Unmarshal(raw, &rawData)
if len(rawData.Data) < 32 {
log.Println("[E] Data length is too short, ERR!")
return
}
rawJSON, _ := base64.StdEncoding.DecodeString(rawData.Data[32:])
var wordInfoRaw WordInfoJSON
json.Unmarshal(rawJSON, &wordInfoRaw)
Expand Down Expand Up @@ -93,19 +99,4 @@ func GrabWord(word string, dataset *VocabDataset, delay int) {
log.Printf("[E] Error when grabbing words: version %s unsupported!\n", wordInfoRaw.Version)
}
answer.WordList = append(answer.WordList, wordInfo)
return
}

func switchContentEncoding(res *http.Response) (bodyReader io.Reader, err error) {
switch res.Header.Get("Content-Encoding") {
case "gzip":
bodyReader, err = gzip.NewReader(res.Body)
case "deflate":
bodyReader = flate.NewReader(res.Body)
case "br":
bodyReader = brotli.NewReader(res.Body)
default:
bodyReader = res.Body
}
return
}
78 changes: 78 additions & 0 deletions grab/net.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package grab
import (
"compress/flate"
"compress/gzip"
"fmt"
"io"
"log"
"net/http"
"strings"

"github.com/andybalholm/brotli"
)

// Do a post request using stored cookies and headers
func doPOST(url string, data string) string {
req, _ := http.NewRequest("POST", url, strings.NewReader(data))
//Add headers and cookies
req.Header = Dataset.RequestInfo.Header
req.Header.Set("Accept", "application/json, text/plain, */*")
req.Header.Set("Accept-Encoding", "gzip, deflate, br")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Content-Length", fmt.Sprint(len(data)))
req.Header.Set("Origin", "https://app.vocabgo.com")

for i := 0; i < len(Dataset.RequestInfo.Cookies); i++ {
req.AddCookie(Dataset.RequestInfo.Cookies[i])
}
//Do request
response, err := http.DefaultClient.Do(req)
if err != nil {
log.Println("[E]" + err.Error())
}
defer response.Body.Close()
read, _, _ := switchContentEncoding(response)
raw, _ := io.ReadAll(read)
return string(raw)
}

// Do a get request using stored cookies and headers
func doGET(url string) string {
req, _ := http.NewRequest("GET", url, nil)
//Add headers and cookies
req.Header = Dataset.RequestInfo.Header
for i := 0; i < len(Dataset.RequestInfo.Cookies); i++ {
req.AddCookie(Dataset.RequestInfo.Cookies[i])
}
//Do request
response, err := http.DefaultClient.Do(req)
if err != nil {
log.Println("[E]" + err.Error())
}
defer response.Body.Close()
read, _, _ := switchContentEncoding(response)
raw, _ := io.ReadAll(read)
return string(raw)
}

func switchContentEncoding(res *http.Response) (bodyReader io.Reader, encoder string, err error) {
encoder = res.Header.Get("Content-Encoding")
switch encoder {
case "gzip":
bodyReader, err = gzip.NewReader(res.Body)
case "deflate":
bodyReader = flate.NewReader(res.Body)
case "br":
bodyReader = brotli.NewReader(res.Body)
default:
bodyReader = res.Body
}
return
}

// Splits the salt and the valid JSON string
func splitSalt(raw string) (salt string, validJSON string) {
salt = raw[0:32]
validJSON = raw[32:]
return
}
66 changes: 66 additions & 0 deletions grab/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,70 @@ type WordInfoJSON struct {
} `json:"example"`
} `json:"content"`
} `json:"options,omitempty"`
}

type ListInfoJson struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
CourseID string `json:"course_id"`
TaskList []struct {
TaskID int `json:"task_id"`
TaskType int `json:"task_type"`
CourseID string `json:"course_id"`
ListID string `json:"list_id"`
TaskName string `json:"task_name"`
Score float64 `json:"score"`
Progress int `json:"progress"`
TimeSpent int `json:"time_spent"`
Free int `json:"free"`
} `json:"task_list"`
CourseName string `json:"course_name"`
CourseImgURL string `json:"course_img_url"`
Progress int `json:"progress"`
TimeSpent int `json:"time_spent"`
Free int `json:"free"`
CourseStatus int `json:"course_status"`
OffInstruction string `json:"off_instruction"`
} `json:"data"`
Jv string `json:"jv"`
Cv string `json:"cv"`
}

type TaskInfoJson struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data struct {
TaskID int `json:"task_id"`
CourseID string `json:"course_id"`
ListID string `json:"list_id"`
TaskName string `json:"task_name"`
WordList []struct {
Progress int `json:"progress"`
Score float64 `json:"score"`
TimeSpent int `json:"time_spent"`
Status int `json:"status"`
CourseID string `json:"course_id"`
ListID string `json:"list_id"`
Word string `json:"word"`
WordType int `json:"word_type"`
WordZh string `json:"word_zh"`
WordAudio string `json:"word_audio"`
} `json:"word_list"`
Grade int `json:"grade"`
GradeInfoList []struct {
Value int `json:"value"`
Text string `json:"text"`
TopicModeNum int `json:"topic_mode_num"`
BaseTime int `json:"base_time"`
Time int `json:"time"`
Remark string `json:"remark"`
} `json:"grade_info_list"`
Score float64 `json:"score"`
Progress int `json:"progress"`
TimeSpent int `json:"time_spent"`
AudioAddr string `json:"audio_addr"`
} `json:"data"`
Jv string `json:"jv"`
Cv string `json:"cv"`
}
Loading

0 comments on commit eec39cf

Please sign in to comment.