diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0e06aac..4994a98 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -11,7 +11,7 @@ on: tag_name: description: 'Tag name for the release' required: true - default: 'v2.0.0-beta.4' # Default tag name + default: 'v2.0.1-beta.1' # Default tag name permissions: contents: write # Allow writing to GitHub releases @@ -23,8 +23,9 @@ env: VERSION: ${{ github.ref_name }} # Dynamic version based on the tag name RELEASE_DIR: release RELEASE_NOTICES: | - - [👏] 更改AI逻辑,使其提高正确率 - - [🔧] 修复部分BUG,提高稳定性 + - [👏] 更新支持新平台重庆工程学院CQIE + - [👏] 更新平台重庆工程学院CQIE支持秒刷 + 注:等GO版本追平Java版本功能后Java版本将不再进行维护,后续将主要针对GO版本进行维护,Java将不会更新新功能和适配新平台。 jobs: diff --git a/config/logo.txt b/config/logo.txt index 750bc32..dd078ec 100644 --- a/config/logo.txt +++ b/config/logo.txt @@ -13,7 +13,7 @@ : \ \; : .' \ | , / `----' ---' ; : ; \ ' ;| , .-./ ---`-' | , / `--` `--`---' ---`-' - Yatori-go-console v2.0.0-Beta.4 + Yatori-go-console v2.0.1-Beta.1 仅用于学习交流,请勿用于违法和商业用途!!! GitHub开源地址:https://github.com/Yatori-Dev/yatori-go-console 个人博客:https://blogs.changbaiqi.top \ No newline at end of file diff --git a/go.mod b/go.mod index 2d31f20..ba61bfe 100644 --- a/go.mod +++ b/go.mod @@ -12,10 +12,11 @@ require ( gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df ) -require github.com/yatori-dev/yatori-go-core v1.0.4 +require github.com/yatori-dev/yatori-go-core v1.0.5 require ( github.com/fsnotify/fsnotify v1.8.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/hajimehoshi/go-mp3 v0.3.4 // indirect github.com/hajimehoshi/oto v0.7.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect diff --git a/go.sum b/go.sum index 798e2f4..39f3fd1 100644 --- a/go.sum +++ b/go.sum @@ -40,6 +40,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= github.com/hajimehoshi/go-mp3 v0.3.4 h1:NUP7pBYH8OguP4diaTZ9wJbUbk3tC0KlfzsEpWmYj68= github.com/hajimehoshi/go-mp3 v0.3.4/go.mod h1:fRtZraRFcWb0pu7ok0LqyFhCUrPeMsGRSVop0eemFmo= @@ -114,8 +116,8 @@ github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/yalue/onnxruntime_go v1.12.1 h1:joCCmBnNjHy04jK9EMP/UV6oPPqySXlRgf3gcUcnI/g= github.com/yalue/onnxruntime_go v1.12.1/go.mod h1:b4X26A8pekNb1ACJ58wAXgNKeUCGEAQ9dmACut9Sm/4= -github.com/yatori-dev/yatori-go-core v1.0.4 h1:ysJF2wUO4/Yk7vDGvGCgQeDQVym5ySCGc1sEnghr5bQ= -github.com/yatori-dev/yatori-go-core v1.0.4/go.mod h1:55fPqQnCunl9jMqP7XzFUJrDPjzyI2Z9PWZPLwBlL3k= +github.com/yatori-dev/yatori-go-core v1.0.5 h1:9UitulFo4c2u7oe5NYeNJQoZ8o+cxOHcAgoIcVr2aSw= +github.com/yatori-dev/yatori-go-core v1.0.5/go.mod h1:55fPqQnCunl9jMqP7XzFUJrDPjzyI2Z9PWZPLwBlL3k= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= diff --git a/logic/Lunch.go b/logic/Lunch.go index 6b3e29e..cdb48eb 100644 --- a/logic/Lunch.go +++ b/logic/Lunch.go @@ -7,6 +7,7 @@ import ( "sync" "time" "yatori-go-console/config" + "yatori-go-console/logic/cqie" "yatori-go-console/logic/enaea" "yatori-go-console/logic/xuexitong" "yatori-go-console/logic/yinghua" @@ -37,6 +38,8 @@ func brushBlock(configData *config.JSONDataForConfig) { yingHuaOperation := yinghua.UserLoginOperation(yingHuaAccount) enaeaAccount := enaea.FilterAccount(configData) enaeaOperation := enaea.UserLoginOperation(enaeaAccount) + cqieAccount := cqie.FilterAccount(configData) + cqieOpertation := cqie.UserLoginOperation(cqieAccount) xueXiTongAccount := xuexitong.FilterAccount(configData) xueXiTongOperation := xuexitong.UserLoginOperation(xueXiTongAccount) @@ -53,6 +56,11 @@ func brushBlock(configData *config.JSONDataForConfig) { enaea.RunBrushOperation(configData.Setting, enaeaAccount, enaeaOperation) //学习公社统一刷课模块 platformLock.Done() }() + platformLock.Add(1) + go func() { + cqie.RunBrushOperation(configData.Setting, cqieAccount, cqieOpertation) //重庆工程学院CQIE刷课模块 + platformLock.Done() + }() //学习通 platformLock.Add(1) go func() { @@ -71,7 +79,7 @@ func configJsonCheck(configData *config.JSONDataForConfig) { //防止用户填完整url for i, v := range configData.Users { - if v.AccountType == "ENAEA" { //跳过学习公社 + if v.AccountType == "ENAEA" || v.Account == "CQIE" { //跳过学习公社和CQIE continue } else if v.URL == "url" { lg.Print(lg.INFO, lg.BoldRed, "请先在config文件中配置好相应账号") diff --git a/logic/cqie/CqiePart.go b/logic/cqie/CqiePart.go new file mode 100644 index 0000000..6dee8bc --- /dev/null +++ b/logic/cqie/CqiePart.go @@ -0,0 +1,179 @@ +package cqie + +import ( + "fmt" + "log" + "sync" + "time" + "yatori-go-console/config" + utils2 "yatori-go-console/utils" + modelLog "yatori-go-console/utils/log" + + "github.com/yatori-dev/yatori-go-core/aggregation/cqie" + cqieApi "github.com/yatori-dev/yatori-go-core/api/cqie" + lg "github.com/yatori-dev/yatori-go-core/utils/log" +) + +var videosLock sync.WaitGroup //视屏锁 +var usersLock sync.WaitGroup //用户锁 + +// 用于过滤Cqie账号 +func FilterAccount(configData *config.JSONDataForConfig) []config.Users { + var users []config.Users //用于收集英华账号 + for _, user := range configData.Users { + if user.AccountType == "CQIE" { + users = append(users, user) + } + } + return users +} + +// 开始刷课模块 +func RunBrushOperation(setting config.Setting, users []config.Users, userCaches []*cqieApi.CqieUserCache) { + //开始刷课 + for i, user := range userCaches { + usersLock.Add(1) + go userBlock(setting, &users[i], user) + + } + usersLock.Wait() +} + +// 用户登录模块 +func UserLoginOperation(users []config.Users) []*cqieApi.CqieUserCache { + var UserCaches []*cqieApi.CqieUserCache + for _, user := range users { + if user.AccountType == "CQIE" { + cache := &cqieApi.CqieUserCache{Account: user.Account, Password: user.Password} + error := cqie.CqieLoginAction(cache) // 登录 + if error != nil { + lg.Print(lg.INFO, "[", lg.Green, cache.Account, lg.White, "] ", lg.Red, error.Error()) + log.Fatal(error) //登录失败则直接退出 + } + UserCaches = append(UserCaches, cache) + } + } + return UserCaches +} + +// 加锁,防止同时过多调用音频通知导致BUG,speak自带的没用,所以别改 +// 以用户作为刷课单位的基本块 +var soundMut sync.Mutex + +func userBlock(setting config.Setting, user *config.Users, cache *cqieApi.CqieUserCache) { + // projectList, _ := enaea.ProjectListAction(cache) //拉取项目列表 + courseList, _ := cqie.CqiePullCourseListAction(cache) + for _, course := range courseList { + videosLock.Add(1) + go func() { + nodeListStudy(setting, user, cache, &course) //多携程刷课 + videosLock.Done() + }() + } + videosLock.Wait() //等待课程刷完 + + lg.Print(lg.INFO, "[", lg.Green, cache.Account, lg.Default, "] ", lg.Purple, "所有待学习课程学习完毕") + if setting.BasicSetting.CompletionTone == 1 { //如果声音提示开启,那么播放 + soundMut.Lock() + utils2.PlayNoticeSound() //播放提示音 + soundMut.Unlock() + } + usersLock.Done() +} + +// 章节节点的抽离函数 +func nodeListStudy(setting config.Setting, user *config.Users, userCache *cqieApi.CqieUserCache, course *cqie.CqieCourse) { + //过滤课程--------------------------------- + //排除指定课程 + if len(user.CoursesCustom.ExcludeCourses) != 0 && config.CmpCourse(course.CourseName, user.CoursesCustom.ExcludeCourses) { + return + } + //包含指定课程 + if len(user.CoursesCustom.IncludeCourses) != 0 && !config.CmpCourse(course.CourseName, user.CoursesCustom.IncludeCourses) { + return + } + //执行刷课--------------------------------- + nodeList, _ := cqie.PullCourseVideoListAndProgress(userCache, course) //拉取对应课程的视屏列表 + //失效重登检测 + modelLog.ModelPrint(setting.BasicSetting.LogModel == 1, lg.INFO, "[", lg.Green, userCache.Account, lg.Default, "] ", "正在学习课程:", lg.Yellow, "【"+course.CourseName+"】 ") + // 提交学时 + for _, node := range nodeList { + //视屏处理逻辑 + switch user.CoursesCustom.VideoModel { + case 1: + videoAction(setting, user, userCache, node) //常规 + break + case 2: + videoActionSecondBrush(setting, user, userCache, node) //暴力模式(秒刷 + break + } + } + modelLog.ModelPrint(setting.BasicSetting.LogModel == 1, lg.INFO, "[", lg.Green, userCache.Account, lg.Default, "] ", lg.Green, "课程", "【"+course.CourseName+"】 ", "学习完毕") + +} + +// videoAction 刷视频逻辑抽离 +func videoAction(setting config.Setting, user *config.Users, UserCache *cqieApi.CqieUserCache, node cqie.CqieVideo) { + if user.CoursesCustom.VideoModel == 0 { //是否打开了自动刷视屏开关 + return + } + + modelLog.ModelPrint(setting.BasicSetting.LogModel == 0, lg.INFO, "[", lg.Green, UserCache.Account, lg.Default, "] ", lg.Yellow, "正在学习视屏:", lg.Default, "【"+node.VideoName+"】 ") + nowTime := time.Now() + startPos := node.StudyTime + stopPos := node.StudyTime + maxPos := node.StudyTime + err := cqie.SaveVideoStudyTimeAction(UserCache, &node, startPos, stopPos) //每次刷课前都得先获取一遍,因为要获取学习分配的id + if err != nil { + lg.Print(lg.INFO, `[`, UserCache.Account, `] `, lg.BoldRed, err.Error()) + } + for { + if maxPos >= node.TimeLength+3 { //+3是为了防止漏时 + startPos = node.TimeLength + stopPos = node.TimeLength + maxPos = node.TimeLength + break + } + if stopPos >= maxPos { + maxPos = startPos + 3 + } + fmt.Println(startPos, stopPos, maxPos) + err := cqie.SubmitStudyTimeAction(UserCache, &node, nowTime, startPos, stopPos, maxPos) + if err != nil { + fmt.Println(err) + } + modelLog.ModelPrint(setting.BasicSetting.LogModel == 0, lg.INFO, "[", lg.Green, UserCache.Account, lg.Default, "] ", "【"+node.VideoName+"】 >>> ", "提交状态:", "成功", lg.Default, " ", "观看进度:", fmt.Sprintf("%.2f", float32(node.StudyTime)/float32(node.TimeLength)), "%") + startPos = startPos + 3 + stopPos = stopPos + 3 + time.Sleep(3 * time.Second) + } + err = cqie.SaveVideoStudyTimeAction(UserCache, &node, startPos, stopPos) //学完之后保存学习点 + if err != nil { + lg.Print(lg.INFO, "[", lg.Green, UserCache.Account, lg.Default, "] ", "【"+node.VideoName+"】", lg.BoldRed, "保存学习点异常:", err.Error()) + } + modelLog.ModelPrint(setting.BasicSetting.LogModel == 0, lg.INFO, "[", lg.Green, UserCache.Account, lg.Default, "] ", lg.Yellow, "视屏:", lg.Default, "【"+node.VideoName+"】 ", lg.Green, "学习完毕") +} + +// videoAction 刷视频逻辑抽离(秒刷版本) +func videoActionSecondBrush(setting config.Setting, user *config.Users, UserCache *cqieApi.CqieUserCache, node cqie.CqieVideo) { + if user.CoursesCustom.VideoModel == 0 { //是否打开了自动刷视屏开关 + return + } + nowTime := time.Now() + startPos := node.StudyTime + stopPos := node.StudyTime + maxPos := node.StudyTime + err := cqie.SaveVideoStudyTimeAction(UserCache, &node, startPos, stopPos) //每次刷课前都得先获取一遍,因为要获取学习分配的id + if err != nil { + lg.Print(lg.INFO, `[`, UserCache.Account, `] `, lg.BoldRed, err.Error()) + } + err1 := cqie.SubmitStudyTimeAction(UserCache, &node, nowTime, startPos, stopPos, maxPos) + if err1 != nil { + fmt.Println(err) + } + err = cqie.SaveVideoStudyTimeAction(UserCache, &node, startPos, stopPos) //学完之后保存学习点 + if err != nil { + lg.Print(lg.INFO, "[", lg.Green, UserCache.Account, lg.Default, "] ", "【"+node.VideoName+"】", lg.BoldRed, "保存学习点异常:", err.Error()) + } + modelLog.ModelPrint(setting.BasicSetting.LogModel == 0, lg.INFO, "[", lg.Green, UserCache.Account, lg.Default, "] ", lg.Yellow, "视屏:", lg.Default, "【"+node.VideoName+"】 ", lg.Green, "学习完毕") +}