diff --git a/dist/qrcode.js b/dist/qrcode.js new file mode 100644 index 0000000..f3be5da --- /dev/null +++ b/dist/qrcode.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.jrQrcode=e():t.jrQrcode=e()}(this,function(){return function(t){function e(o){if(r[o])return r[o].exports;var n=r[o]={exports:{},id:o,loaded:!1};return t[o].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){"use strict";t.exports=r(3)},function(t,e){"use strict";!function(){Object.assign||Object.defineProperty(Object,"assign",{enumerable:!1,configurable:!0,writable:!0,value:function(t){if(void 0===t||null===t)throw new TypeError("Cannot convert first argument to object");for(var e=Object(t),r=1;r=1&&n<=127?e+=t.charAt(r):n>2047?(e+=String.fromCharCode(224|n>>12&15),e+=String.fromCharCode(128|n>>6&63),e+=String.fromCharCode(128|n>>0&63)):(e+=String.fromCharCode(192|n>>6&31),e+=String.fromCharCode(128|n>>0&63));return e},t.utf8to16=function(t){var e,r,o,n,i,a;for(e="",o=t.length,r=0;r>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:e+=t.charAt(r-1);break;case 12:case 13:i=t.charCodeAt(r++),e+=String.fromCharCode((31&n)<<6|63&i);break;case 14:i=t.charCodeAt(r++),a=t.charCodeAt(r++),e+=String.fromCharCode((15&n)<<12|(63&i)<<6|(63&a)<<0)}return e},t}()},function(t,e,r){"use strict";r(1),r(4);var o=r(2),n=function(){function t(t){var e=new QRCode(t.typeNumber,t.correctLevel);e.addData(t.text),e.make();var r=document.createElement("canvas");r.width=t.width,r.height=t.height;var o=r.getContext("2d"),n=(t.width-2*t.padding)/e.getModuleCount(),i=(t.height-2*t.padding)/e.getModuleCount();if(t.reverse){var a="rgba(0, 0, 0, 0)";o.fillStyle=a,t.foreground=a}else o.fillStyle=t.background;o.fillRect(0,0,r.width,r.height);for(var s=0;s=7&&this.setupTypeNumber(t),null==this.dataCache&&(this.dataCache=o.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,e)},setupPositionProbePattern:function(t,e){for(var r=-1;r<=7;r++)if(!(t+r<=-1||this.moduleCount<=t+r))for(var o=-1;o<=7;o++)e+o<=-1||this.moduleCount<=e+o||(0<=r&&r<=6&&(0==o||6==o)||0<=o&&o<=6&&(0==r||6==r)||2<=r&&r<=4&&2<=o&&o<=4?this.modules[t+r][e+o]=!0:this.modules[t+r][e+o]=!1)},getBestMaskPattern:function(){for(var t=0,e=0,r=0;r<8;r++){this.makeImpl(!0,r);var o=f.getLostPoint(this);(0==r||t>o)&&(t=o,e=r)}return e},createMovieClip:function(t,e,r){var o=t.createEmptyMovieClip(e,r),n=1;this.make();for(var i=0;i>r&1);this.modules[Math.floor(r/3)][r%3+this.moduleCount-8-3]=o}for(var r=0;r<18;r++){var o=!t&&1==(e>>r&1);this.modules[r%3+this.moduleCount-8-3][Math.floor(r/3)]=o}},setupTypeInfo:function(t,e){for(var r=this.errorCorrectLevel<<3|e,o=f.getBCHTypeInfo(r),n=0;n<15;n++){var i=!t&&1==(o>>n&1);n<6?this.modules[n][8]=i:n<8?this.modules[n+1][8]=i:this.modules[this.moduleCount-15+n][8]=i}for(var n=0;n<15;n++){var i=!t&&1==(o>>n&1);n<8?this.modules[8][this.moduleCount-n-1]=i:n<9?this.modules[8][15-n-1+1]=i:this.modules[8][15-n-1]=i}this.modules[this.moduleCount-8][8]=!t},mapData:function(t,e){for(var r=-1,o=this.moduleCount-1,n=7,i=0,a=this.moduleCount-1;a>0;a-=2)for(6==a&&a--;;){for(var s=0;s<2;s++)if(null==this.modules[o][a-s]){var u=!1;i>>n&1));var h=f.getMask(e,o,a-s);h&&(u=!u),this.modules[o][a-s]=u,n--,n==-1&&(i++,n=7)}if(o+=r,o<0||this.moduleCount<=o){o-=r,r=-r;break}}}},o.PAD0=236,o.PAD1=17,o.createData=function(t,e,r){for(var n=i.getRSBlocks(t,e),s=new a,u=0;u8*l)throw new Error("code length overflow. ("+s.getLengthInBits()+">"+8*l+")");for(s.getLengthInBits()+4<=8*l&&s.put(0,4);s.getLengthInBits()%8!=0;)s.putBit(!1);for(;;){if(s.getLengthInBits()>=8*l)break;if(s.put(o.PAD0,8),s.getLengthInBits()>=8*l)break;s.put(o.PAD1,8)}return o.createBytes(s,n)},o.createBytes=function(t,e){for(var r=0,o=0,i=0,a=new Array(e.length),s=new Array(e.length),u=0;u=0?v.get(m):0}}for(var p=0,g=0;g=0;)e^=f.G15<=0;)e^=f.G18<>>=1;return e},getPatternPosition:function(t){return f.PATTERN_POSITION_TABLE[t-1]},getMask:function(t,e,r){switch(t){case h.PATTERN000:return(e+r)%2==0;case h.PATTERN001:return e%2==0;case h.PATTERN010:return r%3==0;case h.PATTERN011:return(e+r)%3==0;case h.PATTERN100:return(Math.floor(e/2)+Math.floor(r/3))%2==0;case h.PATTERN101:return e*r%2+e*r%3==0;case h.PATTERN110:return(e*r%2+e*r%3)%2==0;case h.PATTERN111:return(e*r%3+(e+r)%2)%2==0;default:throw new Error("bad maskPattern:"+t)}},getErrorCorrectPolynomial:function(t){for(var e=new n([1],0),r=0;r5&&(r+=3+i-5)}for(var o=0;o=256;)t-=255;return l.EXP_TABLE[t]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},g=0;g<8;g++)l.EXP_TABLE[g]=1<>>7-t%8&1)},put:function(t,e){for(var r=0;r>>e-r-1&1))},getLengthInBits:function(){return this.length},putBit:function(t){var e=Math.floor(this.length/8);this.buffer.length<=e&&this.buffer.push(0),t&&(this.buffer[e]|=128>>>this.length%8),this.length++}},window.QRCode=o,window.QRErrorCorrectLevel=u;try{t.exports={QRCode:o,QRErrorCorrectLevel:u}}catch(t){}}])}); \ No newline at end of file diff --git a/dist/scheme.html b/dist/scheme.html new file mode 100644 index 0000000..3562476 --- /dev/null +++ b/dist/scheme.html @@ -0,0 +1,42 @@ + + + + + Title + + + + + +
+
+ # +
+ + + \ No newline at end of file diff --git a/lib/respond.go b/lib/respond.go index 996d193..87aec91 100644 --- a/lib/respond.go +++ b/lib/respond.go @@ -1,13 +1,20 @@ package lib import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" rand2 "math/rand" + "net/http" "regexp" "strings" "time" + "github.com/imroc/req/v3" "github.com/mxschmitt/playwright-go" log "github.com/sirupsen/logrus" + "github.com/tidwall/gjson" "github.com/huoxue1/study_xxqg/model" ) @@ -23,6 +30,12 @@ div:nth-child(7) > div.my-points-card-footer > div.buttonbox > div` div > div.my-points-section > div.my-points-content > div:nth-child(6) > div.my-points-card-footer > div.buttonbox > div` ) +// RespondDaily +/* @Description: + * @receiver c + * @param user + * @param model + */ func (c *Core) RespondDaily(user *model.User, model string) { defer func() { err := recover() @@ -110,9 +123,22 @@ func (c *Core) RespondDaily(user *model.User, model string) { return } - err = page.Click(WEEKEND) + // err = page.Click(WEEKEND) + // if err != nil { + // log.Errorln("跳转到积分页面错误") + // return + //} + id, err := getweekID(user.ToCookies()) if err != nil { - log.Errorln("跳转到积分页面错误") + return + } + _, err = page.Goto(fmt.Sprintf("https://pc.xuexi.cn/points/exam-weekly-detail.html?id=%d", id), playwright.PageGotoOptions{ + Referer: playwright.String(MyPointsUri), + Timeout: playwright.Float(10000), + WaitUntil: playwright.WaitUntilStateDomcontentloaded, + }) + if err != nil { + log.Errorln("跳转到答题页面错误" + err.Error()) return } c.Push("text", "已加载每周答题模块") @@ -125,10 +151,23 @@ func (c *Core) RespondDaily(user *model.User, model string) { return } - err = page.Click(SPECIALBUTTON) + // err = page.Click(SPECIALBUTTON) + // if err != nil { + // log.Errorln("跳转到积分页面错误") + // + // return + //} + id, err := getSpecialID(user.ToCookies()) if err != nil { - log.Errorln("跳转到积分页面错误") - + return + } + _, err = page.Goto(fmt.Sprintf("https://pc.xuexi.cn/points/exam-paper-detail.html?id=%d", id), playwright.PageGotoOptions{ + Referer: playwright.String(MyPointsUri), + Timeout: playwright.Float(10000), + WaitUntil: playwright.WaitUntilStateDomcontentloaded, + }) + if err != nil { + log.Errorln("跳转到答题页面错误" + err.Error()) return } c.Push("text", "已加载专项答题模块") @@ -136,9 +175,9 @@ func (c *Core) RespondDaily(user *model.User, model string) { } time.Sleep(5 * time.Second) // 跳转到答题页面,若返回true则说明已答完 - if getAnswerPage(page, model) { - return - } + // if getAnswerPage(page, model) { + // return + //} tryCount := 0 for true { @@ -595,3 +634,75 @@ func RemoveRepByLoop(slc []string) []string { } return result } + +func getSpecialID(cookies []*http.Cookie) (int, error) { + c := req.C() + c.SetCommonCookies(cookies...) + repo, err := c.R().SetQueryParams(map[string]string{"pageSize": "1000", "pageNo": "1"}).Get(querySpecialList) + if err != nil { + log.Errorln("获取专项答题列表错误" + err.Error()) + return 0, err + } + dataB64, err := repo.ToString() + if err != nil { + log.Errorln("获取专项答题列表获取string错误" + err.Error()) + return 0, err + } + data, err := base64.StdEncoding.DecodeString(gjson.Get(dataB64, "data_str").String()) + if err != nil { + log.Errorln("获取专项答题列表转换b64错误" + err.Error()) + return 0, err + } + list := new(SpecialList) + err = json.Unmarshal(data, list) + if err != nil { + log.Errorln("获取专项答题列表转换json错误" + err.Error()) + return 0, err + } + log.Infoln(fmt.Sprintf("共获取到专项答题%d个", list.TotalCount)) + for _, s := range list.List { + if s.TipScore == 0 { + log.Infoln(fmt.Sprintf("获取到未答专项答题: %v,id: %v", s.Name, s.Id)) + return s.Id, nil + } + } + log.Warningln("你已不存在未答的专项答题了") + return 0, errors.New("未找到专项答题") +} + +func getweekID(cookies []*http.Cookie) (int, error) { + c := req.C() + c.SetCommonCookies(cookies...) + repo, err := c.R().SetQueryParams(map[string]string{"pageSize": "500", "pageNo": "1"}).Get(queryWeekList) + if err != nil { + log.Errorln("获取每周答题列表错误" + err.Error()) + return 0, err + } + dataB64, err := repo.ToString() + if err != nil { + log.Errorln("获取每周答题列表获取string错误" + err.Error()) + return 0, err + } + data, err := base64.StdEncoding.DecodeString(gjson.Get(dataB64, "data_str").String()) + if err != nil { + log.Errorln("获取每周答题列表转换b64错误" + err.Error()) + return 0, err + } + list := new(WeekList) + err = json.Unmarshal(data, list) + if err != nil { + log.Errorln("获取每周答题列表转换json错误" + err.Error()) + return 0, err + } + log.Infoln(fmt.Sprintf("共获取到每周答题%d个", list.TotalCount)) + for _, s := range list.List { + for _, practice := range s.Practices { + if practice.TipScore == 0 { + log.Infoln(fmt.Sprintf("获取到未答每周答题: %v,id: %v", practice.Name, practice.Id)) + return practice.Id, nil + } + } + } + log.Warningln("你已不存在未答的每周答题了") + return 0, errors.New("未找到每周答题") +} diff --git a/lib/score.go b/lib/score.go index 5f9326e..547093f 100644 --- a/lib/score.go +++ b/lib/score.go @@ -26,7 +26,7 @@ func GetUserScore(cookies []*http.Cookie) (Score, error) { var score Score var resp []byte // 获取用户总分 - err := gout.GET(user_totalScore_url).SetCookies(cookies...).SetHeader(gout.H{ + err := gout.GET(userTotalscoreUrl).SetCookies(cookies...).SetHeader(gout.H{ "Cache-Control": "no-cache", }).BindBody(&resp).Do() if err != nil { @@ -43,7 +43,7 @@ func GetUserScore(cookies []*http.Cookie) (Score, error) { score.TotalScore = int(gjson.GetBytes(resp, "data.score").Int()) // 获取用户今日得分 - err = gout.GET(user_todayTotalScore_url).SetCookies(cookies...).SetHeader(gout.H{ + err = gout.GET(userTodaytotalscoreUrl).SetCookies(cookies...).SetHeader(gout.H{ "Cache-Control": "no-cache", }).BindBody(&resp).Do() if err != nil { @@ -54,7 +54,7 @@ func GetUserScore(cookies []*http.Cookie) (Score, error) { // log.Debugln(gjson.GetBytes(resp, "@this|@pretty")) score.TodayScore = int(gjson.GetBytes(resp, "data.score").Int()) - err = gout.GET(user_rateScore_url).SetCookies(cookies...).SetHeader(gout.H{ + err = gout.GET(userRatescoreUrl).SetCookies(cookies...).SetHeader(gout.H{ "Cache-Control": "no-cache", }).BindBody(&resp).Do() if err != nil { diff --git a/lib/url.go b/lib/url.go index 077225c..0f4a1a3 100644 --- a/lib/url.go +++ b/lib/url.go @@ -1,8 +1,79 @@ package lib const ( - user_Info_url = "https://pc-api.xuexi.cn/open/api/user/info" - user_totalScore_url = "https://pc-api.xuexi.cn/open/api/score/get" - user_todayTotalScore_url = "https://pc-api.xuexi.cn/open/api/score/today/query" - user_rateScore_url = "https://pc-proxy-api.xuexi.cn/api/score/days/listScoreProgress?sence=score&deviceType=2" + userInfoUrl = "https://pc-api.xuexi.cn/open/api/user/info" + userTotalscoreUrl = "https://pc-api.xuexi.cn/open/api/score/get" + userTodaytotalscoreUrl = "https://pc-api.xuexi.cn/open/api/score/today/query" + userRatescoreUrl = "https://pc-proxy-api.xuexi.cn/api/score/days/listScoreProgress?sence=score&deviceType=2" + + // pageSize=1000&pageNo=1 + querySpecialList = "https://pc-proxy-api.xuexi.cn/api/exam/service/paper/pc/list" + queryWeekList = "https://pc-proxy-api.xuexi.cn/api/exam/service/practice/pc/weekly/more" ) + +type SpecialList struct { + PageNo int `json:"pageNo"` + PageSize int `json:"pageSize"` + TotalPageCount int `json:"totalPageCount"` + TotalCount int `json:"totalCount"` + List []struct { + TipScore int `json:"tipScore"` + EndDate string `json:"endDate"` + Achievement struct { + Score int `json:"score"` + Total int `json:"total"` + Correct int `json:"correct"` + } `json:"achievement"` + Year int `json:"year"` + SeeSolution bool `json:"seeSolution"` + Score int `json:"score"` + ExamScoreId int `json:"examScoreId"` + UsedTime int `json:"usedTime"` + Overdue bool `json:"overdue"` + Month int `json:"month"` + Name string `json:"name"` + QuestionNum int `json:"questionNum"` + AlreadyAnswerNum int `json:"alreadyAnswerNum"` + StartTime string `json:"startTime"` + Id int `json:"id"` + ExamTime int `json:"examTime"` + Forever int `json:"forever"` + StartDate string `json:"startDate"` + Status int `json:"status"` + } `json:"list"` + PageNum int `json:"pageNum"` +} + +type WeekList struct { + PageNo int `json:"pageNo"` + PageSize int `json:"pageSize"` + TotalPageCount int `json:"totalPageCount"` + TotalCount int `json:"totalCount"` + List []struct { + Month string `json:"month"` + Practices []struct { + SeeSolution bool `json:"seeSolution"` + TipScore int `json:"tipScore"` + ExamScoreId int `json:"examScoreId"` + Overdue bool `json:"overdue"` + Achievement struct { + Total int `json:"total"` + Correct int `json:"correct"` + } `json:"achievement"` + Name string `json:"name"` + BeginYear int `json:"beginYear"` + StartTime string `json:"startTime"` + Id int `json:"id"` + BeginMonth int `json:"beginMonth"` + Status int `json:"status"` + TipScoreReasonType int `json:"tipScoreReasonType"` + } `json:"practices"` + } `json:"list"` + PageNum int `json:"pageNum"` +} + +/* + +{"month":"5月","practices":[{"seeSolution":true,"tipScore":4,"examScoreId":-1,"overdue":false,"achievement":{"total":5,"correct":4},"name":"2022年5月第四周答题","beginYear":2022,"startTime":"2022-05-23 10:35:00","id":276,"beginMonth":5,"status":2,"tipScoreReasonType":0},{"seeSolution":true,"tipScore":4,"examScoreId":-1,"overdue":false,"achievement":{"total":5,"correct":4},"name":"2022年5月第三周答题","beginYear":2022,"startTime":"2022-05-16 09:00:00","id":275,"beginMonth":5,"status":2,"tipScoreReasonType":0},{"seeSolution":true,"tipScore":4,"examScoreId":-1,"overdue":false,"achievement":{"total":5,"correct":4},"name":"2022年5月第二周答题","beginYear":2022,"startTime":"2022-05-09 08:30:00","id":274,"beginMonth":5,"status":2,"tipScoreReasonType":0},{"seeSolution":true,"tipScore":5,"examScoreId":-1,"overdue":false,"achievement":{"total":5,"correct":5},"name":"2022年5月第一周答题","beginYear":2022,"startTime":"2022-05-02 08:30:00","id":273,"beginMonth":5,"status":2,"tipScoreReasonType":0}]} + +*/ diff --git a/lib/user.go b/lib/user.go index 6f70d53..bad2ce4 100644 --- a/lib/user.go +++ b/lib/user.go @@ -20,7 +20,7 @@ import ( */ func GetUserInfo(cookies []*http.Cookie) (string, string, error) { var resp []byte - err := gout.GET(user_Info_url). + err := gout.GET(userInfoUrl). SetCookies(cookies...). SetHeader(gout.H{ "Cache-Control": "no-cache", diff --git a/utils/file.go b/utils/file.go index 889d237..ccc5cc0 100644 --- a/utils/file.go +++ b/utils/file.go @@ -1,3 +1,5 @@ +// Package utils +// @Description: package utils import ( @@ -6,6 +8,11 @@ import ( "os" ) +// FileIsExist +/* @Description: + * @param path + * @return bool + */ func FileIsExist(path string) bool { _, err := os.Stat(path) if err == nil { @@ -17,6 +24,11 @@ func FileIsExist(path string) bool { return false } +// StrMd5 +/* @Description: + * @param str + * @return retMd5 + */ func StrMd5(str string) (retMd5 string) { h := md5.New() h.Write([]byte(str)) diff --git a/web/controller.go b/web/controller.go index 6124cfe..a977cf0 100644 --- a/web/controller.go +++ b/web/controller.go @@ -1,3 +1,5 @@ +// Package web +// @Description: package web import ( @@ -23,7 +25,11 @@ var ( state = sync.Map{} ) -func CheckToken() gin.HandlerFunc { +// checkToken +/* @Description: + * @return gin.HandlerFunc + */ +func checkToken() gin.HandlerFunc { return func(ctx *gin.Context) { token := ctx.Param("token") config := conf.GetConfig() @@ -48,7 +54,7 @@ func CheckToken() gin.HandlerFunc { } } -func Login() gin.HandlerFunc { +func userLogin() gin.HandlerFunc { return func(ctx *gin.Context) { type user struct { Account string `json:"account"` @@ -176,7 +182,7 @@ func getUsers() gin.HandlerFunc { } } -func Cors() gin.HandlerFunc { +func cors() gin.HandlerFunc { return func(c *gin.Context) { method := c.Request.Method origin := c.Request.Header.Get("Origin") // 请求头部 diff --git a/web/router.go b/web/router.go index 5d390ee..4e05513 100644 --- a/web/router.go +++ b/web/router.go @@ -1,3 +1,5 @@ +// Package web +// @Description: 封装了所以web相关的内容 package web import ( @@ -10,6 +12,7 @@ import ( "github.com/huoxue1/study_xxqg/utils" ) +// 将静态文件嵌入到可执行程序中来 //go:embed xxqg/build var static embed.FS @@ -18,41 +21,46 @@ var static embed.FS // @return *gin.Engine func RouterInit() *gin.Engine { router := gin.Default() - router.Use(Cors()) - - router.Group("/wx", func(context *gin.Context) { - - }) + router.Use(cors()) + // 挂载静态文件 router.StaticFS("/static", http.FS(static)) + // 访问首页时跳转到对应页面 router.GET("/", func(ctx *gin.Context) { ctx.Redirect(301, "/static/xxqg/build/home.html") }) + // 对权限的管理组 auth := router.Group("/auth") - auth.POST("/login", Login()) - auth.POST("/check/:token", CheckToken()) + // 用户登录的接口 + auth.POST("/login", userLogin()) + // 检查登录状态的token是否正确 + auth.POST("/check/:token", checkToken()) + // 对于用户可自定义挂载文件的目录 if utils.FileIsExist("dist") { router.StaticFS("/dist", gin.Dir("./dist/", true)) } + // 对用户管理的组 user := router.Group("/user", check()) // 添加用户 user.POST("", addUser()) - + // 获取所以已登陆的用户 user.GET("/", getUsers()) - + // 删除用户 user.DELETE("/", deleteUser()) + // 获取用户成绩 router.GET("/score", getScore()) - + // 让一个用户开始学习 router.POST("/study", study()) - + // 让一个用户停止学习 router.POST("/stop_study", check(), stopStudy()) - + // 获取程序当天的运行日志 router.GET("/log", check(), getLog()) + // 登录xxqg的三个接口 router.GET("/sign/*proxyPath", check(), sign()) router.GET("/login/*proxyPath", check(), generate()) router.POST("/login/*proxyPath", check(), generate())