init code
This commit is contained in:
commit
28d0a19069
|
@ -0,0 +1,51 @@
|
|||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
BINARY_PREFIX: "study_xxqg_"
|
||||
BINARY_SUFFIX: ""
|
||||
PR_PROMPT: "::warning:: Build artifact will not be uploaded due to the workflow is trigged by pull request."
|
||||
LD_FLAGS: "-w -s"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build binary CI
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
# build and publish in parallel: linux/386, linux/amd64, windows/386, windows/amd64, darwin/amd64, darwin/arm64
|
||||
goos: [linux, windows]
|
||||
goarch: [amd64]
|
||||
exclude:
|
||||
- goos: darwin
|
||||
goarch: arm
|
||||
- goos: darwin
|
||||
goarch: "386"
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
fail-fast: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Go environment
|
||||
uses: actions/setup-go@v2.1.3
|
||||
with:
|
||||
go-version: 1.17
|
||||
- name: Build binary file
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
IS_PR: ${{ !!github.head_ref }}
|
||||
run: |
|
||||
if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi
|
||||
if $IS_PR ; then echo $PR_PROMPT; fi
|
||||
export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX"
|
||||
export CGO_ENABLED=0
|
||||
go build -o "output/$BINARY_NAME" -ldflags "-w -s -X main.VERSION=action"
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
if: ${{ !github.head_ref }}
|
||||
with:
|
||||
name: ${{ matrix.goos }}_${{ matrix.goarch }}
|
||||
path: output/
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2.3.4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17.2'
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
env:
|
||||
# main: ./example/main.go
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
#- name: Checkout Dist
|
||||
# uses: actions/checkout@v2
|
||||
# with:
|
||||
# repository: 'gocq/dist'
|
||||
# ref: master
|
||||
# ssh-key: ${{ secrets.SSH_KEY }}
|
||||
# path: upstream/dist
|
||||
|
||||
#- name: Update Dist
|
||||
# run: |
|
||||
# chmod +x scripts/upload_dist.sh
|
||||
# ./scripts/upload_dist.sh
|
|
@ -0,0 +1,94 @@
|
|||
linters-settings:
|
||||
errcheck:
|
||||
ignore: fmt:.*,io/ioutil:^Read.*
|
||||
ignoretests: true
|
||||
|
||||
goimports:
|
||||
local-prefixes: github.com/huoxue1/study_xxqg
|
||||
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- exitAfterDefer
|
||||
|
||||
forbidigo:
|
||||
# Forbid the following identifiers
|
||||
forbid:
|
||||
- ^fmt\.Errorf$ # consider errors.Errorf in github.com/pkg/errors
|
||||
|
||||
linters:
|
||||
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
fast: true
|
||||
enable:
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- depguard
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- exportloopref
|
||||
- exhaustive
|
||||
#- funlen
|
||||
#- goconst
|
||||
- gocritic
|
||||
#- gocyclo
|
||||
- gofmt
|
||||
- goimports
|
||||
- goprintffuncname
|
||||
#- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- nolintlint
|
||||
- rowserrcheck
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
- whitespace
|
||||
- prealloc
|
||||
- predeclared
|
||||
- asciicheck
|
||||
- forbidigo
|
||||
- makezero
|
||||
- revive
|
||||
#- interfacer
|
||||
|
||||
# don't enable:
|
||||
# - scopelint
|
||||
# - gochecknoglobals
|
||||
# - gocognit
|
||||
# - godot
|
||||
# - godox
|
||||
# - goerr113
|
||||
# - interfacer
|
||||
# - maligned
|
||||
# - nestif
|
||||
# - testpackage
|
||||
# - wsl
|
||||
|
||||
run:
|
||||
# default concurrency is a available CPU number.
|
||||
# concurrency: 4 # explicitly omit this value to fully utilize available resources.
|
||||
deadline: 5m
|
||||
issues-exit-code: 1
|
||||
tests: false
|
||||
|
||||
# output configuration options
|
||||
output:
|
||||
format: "colored-line-number"
|
||||
print-issued-lines: true
|
||||
print-linter-name: true
|
||||
uniq-by-line: true
|
||||
|
||||
issues:
|
||||
# Fix found issues (if it's supported by the linter)
|
||||
fix: true
|
||||
exclude-use-default: false
|
||||
exclude:
|
||||
- "Error return value of .((os.)?std(out|err)..*|.*Close|.*Flush|os.Remove(All)?|.*print(f|ln)?|os.(Un)?Setenv). is not check"
|
|
@ -0,0 +1,91 @@
|
|||
env:
|
||||
- GO111MODULE=on
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
builds:
|
||||
|
||||
- id: nowin
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
- GO111MODULE=on
|
||||
goos:
|
||||
- linux
|
||||
# - darwin
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
# - arm
|
||||
# - arm64
|
||||
# goarm:
|
||||
# - 7
|
||||
# ignore:
|
||||
# - goos: darwin
|
||||
# goarch: arm
|
||||
# - goos: darwin
|
||||
# goarch: 386
|
||||
mod_timestamp: "{{ .CommitTimestamp }}"
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -s -w -X main.VERSION=v{{.Version}}
|
||||
- id: win
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
- GO111MODULE=on
|
||||
goos:
|
||||
- windows
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
# - arm
|
||||
goarm:
|
||||
- 7
|
||||
mod_timestamp: "{{ .CommitTimestamp }}"
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -s -w -X main.VERSION=v{{.Version}}
|
||||
|
||||
checksum:
|
||||
name_template: "{{ .ProjectName }}_checksums.txt"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
- fix typo
|
||||
- Merge pull request
|
||||
- Merge branch
|
||||
- Merge remote-tracking
|
||||
- go mod tidy
|
||||
|
||||
archives:
|
||||
- id: binary
|
||||
builds:
|
||||
- win
|
||||
- nowin
|
||||
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: binary
|
||||
- goos: linux
|
||||
format: binary
|
||||
- id: nowin
|
||||
builds:
|
||||
- nowin
|
||||
- win
|
||||
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
|
||||
nfpms:
|
||||
- license: AGPL 3.0
|
||||
homepage: https://github.com/huoxue1/study_xxqg
|
||||
file_name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
maintainer: HuoXue1
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
|
@ -0,0 +1 @@
|
|||
study_xxqg
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/study_xxqg.iml" filepath="$PROJECT_DIR$/.idea/study_xxqg.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,16 @@
|
|||
### 学习强国自动化学习
|
||||
|
||||
|
||||
|
||||
## 使用
|
||||
|
||||
+ 从release下载对应版本压缩包
|
||||
+ 首次打开会在 ```config\config.yml```生成默认配置文件
|
||||
+ 再次打开即可运行
|
||||
|
||||
|
||||
## 申明,该项目仅用于学习。
|
||||
|
||||
## 鸣谢
|
||||
|
||||
+ ### [imkenf/XueQG](https://github.com/imkenf/XueQG)
|
|
@ -0,0 +1,5 @@
|
|||
# 刷课模式,默认为1,
|
||||
# 1:只刷文章何视频
|
||||
# 2:只刷文章和视频和每日答题
|
||||
# 3:刷文章和视频和每日答题每周答题和专项答题
|
||||
model: 1
|
|
@ -0,0 +1 @@
|
|||
[{"cookies":[{"name":"_uab_collina","value":"163662103329486079242507","domain":"pc.xuexi.cn","path":"/points","expires":1951981033,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"__UID__","value":"5cdc19a0-42cd-11ec-b6bc-e3c5195d165e","domain":".xuexi.cn","path":"/","expires":1668157033,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"tmzw","value":"1636621034119","domain":".xuexi.cn","path":"/","expires":1636707434,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"zwfigprt","value":"297bce38be89bc8a076e6e29b6282c1c","domain":".xuexi.cn","path":"/","expires":1636707434,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"003c420ac17482ba6ad5550439dfb427add3b6076673bc476f0beeb76d7abdf6","domain":"pc-api.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10416366210318943764e7c9b024dcd55ba787fb0c5064287171f5d3d","domain":"pc-api.xuexi.cn","path":"/","expires":1636622834,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"171ba83785f1d8fb9d76af9bbb376840828ef4710300b5854145bf5e7fec3c1f","domain":"login.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10416366210325768127e7c9adce9f228d7e2f62ece3cd09618ee90d6","domain":"login.xuexi.cn","path":"/","expires":1636622835,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"nhkb8v0kuyzpFzw6Xptyftdj3b03","domain":"login.xuexi.cn","path":"/","expires":1652173035,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"bhkFmvUOuw7p1swt3pe4kCdf22g3","domain":"www.xuexi.cn","path":"/","expires":1652173036,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"94k6yvb2u6apejwFCpekkm5u6e79","domain":"pc.xuexi.cn","path":"/","expires":1652173036,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"token","value":"143ed9a00afe4c1fbcf1eae8acfdeca3","domain":".xuexi.cn","path":"/","expires":1636642691,"httpOnly":false,"secure":false,"same_site":"None"}],"nick":"苟江山","uid":"151142372517"}]
|
|
@ -0,0 +1,41 @@
|
|||
module github.com/huoxue1/study_xxqg
|
||||
|
||||
go 1.17
|
||||
|
||||
replace github.com/willf/bitset v1.2.1 => github.com/bits-and-blooms/bitset v1.2.1
|
||||
|
||||
require (
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
|
||||
github.com/guonaihong/gout v0.2.9
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||
github.com/mxschmitt/playwright-go v0.1100.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816
|
||||
github.com/tidwall/gjson v1.11.0
|
||||
github.com/tuotoo/qrcode v0.0.0-20190222102259-ac9c44189bf2
|
||||
gopkg.in/yaml.v2 v2.2.8
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
|
||||
github.com/go-playground/locales v0.13.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.17.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.4.1 // indirect
|
||||
github.com/google/uuid v1.1.1 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/leodido/go-urn v1.2.0 // indirect
|
||||
github.com/lestrrat-go/strftime v1.0.5 // indirect
|
||||
github.com/maruel/rs v0.0.0-20150922171536-2c81c4312fe4 // indirect
|
||||
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/willf/bitset v1.2.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa // indirect
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
)
|
|
@ -0,0 +1,123 @@
|
|||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f h1:2dk3eOnYllh+wUOuDhOoC2vUVoJF/5z478ryJ+wzEII=
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/go.mod h1:4a58ifQTEe2uwwsaqbh3i2un5/CBPg+At/qHpt18Tmk=
|
||||
github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY=
|
||||
github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ=
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU=
|
||||
github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/guonaihong/gout v0.2.9 h1:8nU5hrtwP1qDwiadFvU+D+z3ud9WEk8iPSfxQDiebng=
|
||||
github.com/guonaihong/gout v0.2.9/go.mod h1:H1JqEuZmK4h/urWUq/LnIOEzS1kxl5rK3NkFqZ6Rn48=
|
||||
github.com/h2non/filetype v1.1.0/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
|
||||
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
|
||||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
|
||||
github.com/lestrrat-go/strftime v1.0.5 h1:A7H3tT8DhTz8u65w+JRpiBxM4dINQhUXAZnhBa2xeOE=
|
||||
github.com/lestrrat-go/strftime v1.0.5/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR76fd03sz+Qz4g=
|
||||
github.com/maruel/rs v0.0.0-20150922171536-2c81c4312fe4 h1:u9jwvcKbQpghIXgNl/EOL8hzhAFXh4ePrEP493W3tNA=
|
||||
github.com/maruel/rs v0.0.0-20150922171536-2c81c4312fe4/go.mod h1:kcRFpEzolcEklV6rD7W95mG49/sbdX/PlFmd7ni3RvA=
|
||||
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mxschmitt/playwright-go v0.1100.0 h1:GkI1TuXU50GlA988VqqdoTObLzi2bbeT8RmLtcxKQrc=
|
||||
github.com/mxschmitt/playwright-go v0.1100.0/go.mod h1:a3SD3v+56XMA0sDDxXJXy+QGnCfXrNZ/+4gwR5ioSgU=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 h1:J6v8awz+me+xeb/cUTotKgceAYouhIB3pjzgRd6IlGk=
|
||||
github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816/go.mod h1:tzym/CEb5jnFI+Q0k4Qq3+LvRF4gO3E2pxS8fHP8jcA=
|
||||
github.com/tidwall/gjson v1.11.0 h1:C16pk7tQNiH6VlCrtIXL1w8GaOsi1X3W8KDkE1BuYd4=
|
||||
github.com/tidwall/gjson v1.11.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tuotoo/qrcode v0.0.0-20190222102259-ac9c44189bf2 h1:BWVtt2VBY+lmVDu9MGKqLGKl04B+iRHcrW1Ptyi/8tg=
|
||||
github.com/tuotoo/qrcode v0.0.0-20190222102259-ac9c44189bf2/go.mod h1:lPnW9HVS0vJdeYyQtOvIvlXgZPNhUAhwz+z5r8AJk0Y=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
@ -0,0 +1,44 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Model int `json:"model" yaml:"model"`
|
||||
LogLevel string `json:"log_level" yaml:"log_level"`
|
||||
ShowBrowser bool `json:"show_browser" yaml:"show_browser"`
|
||||
}
|
||||
|
||||
var (
|
||||
config = Config{
|
||||
Model: 1,
|
||||
}
|
||||
)
|
||||
|
||||
//go:embed config_default.yml
|
||||
var defaultConfig []byte
|
||||
|
||||
func GetConfig() Config {
|
||||
file, err := os.ReadFile("./config/config.yml")
|
||||
if err != nil {
|
||||
log.Warningln("检测到配置文件可能不存在")
|
||||
err := os.WriteFile("./config/config.yml", defaultConfig, 0666)
|
||||
if err != nil {
|
||||
log.Errorln("写入到配置文件出现错误")
|
||||
return Config{}
|
||||
}
|
||||
log.Infoln("成功写入到配置文件,请重启应用")
|
||||
os.Exit(3)
|
||||
}
|
||||
err = yaml.Unmarshal(file, &config)
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
return Config{}
|
||||
}
|
||||
return config
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
# 刷课模式,默认为1,
|
||||
# 1:只刷文章何视频
|
||||
# 2:只刷文章和视频和每日答题
|
||||
# 3:刷文章和视频和每日答题每周答题和专项答题
|
||||
model: 1
|
||||
|
||||
# 日志等级
|
||||
# panic
|
||||
# fatal
|
||||
# error
|
||||
# warn, warning
|
||||
# info
|
||||
# debug
|
||||
# trace
|
||||
log_level: "info"
|
||||
|
||||
# 是否显示浏览器
|
||||
show_browser: true
|
|
@ -0,0 +1,227 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go"
|
||||
"github.com/guonaihong/gout"
|
||||
"github.com/mxschmitt/playwright-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/tuotoo/qrcode"
|
||||
)
|
||||
|
||||
type Core struct {
|
||||
pw *playwright.Playwright
|
||||
browser playwright.Browser
|
||||
context playwright.BrowserContext
|
||||
}
|
||||
|
||||
type cookie struct {
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Value string `json:"value" yaml:"value"`
|
||||
Domain string `json:"domain" yaml:"domain"`
|
||||
Path string `json:"path" yaml:"path"`
|
||||
Expires int `json:"expires" yaml:"expires"`
|
||||
HTTPOnly bool `json:"httpOnly" yaml:"http_only"`
|
||||
Secure bool `json:"secure" yaml:"secure"`
|
||||
SameSite string `json:"same_site" yaml:"same_site"`
|
||||
}
|
||||
|
||||
func (c *Core) Init() {
|
||||
pwt, err := playwright.Run()
|
||||
if err != nil {
|
||||
log.Errorln("[core]", "初始化playwright失败")
|
||||
log.Errorln("[core] ", err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
c.pw = pwt
|
||||
browser, err := pwt.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
|
||||
Args: []string{
|
||||
"--disable-extensions",
|
||||
"--disable-gpu",
|
||||
"--no-sandbox",
|
||||
"--window-size=540,400",
|
||||
"--start-maximized",
|
||||
"--mute-audio",
|
||||
"--window-position=0,0",
|
||||
"--ignore-certificate-errors",
|
||||
"--ignore-ssl-errors",
|
||||
"--disable-features=RendererCodeIntegrity",
|
||||
"--disable-blink-features",
|
||||
"--disable-blink-features=AutomationControlled",
|
||||
},
|
||||
Channel: nil,
|
||||
ChromiumSandbox: nil,
|
||||
Devtools: nil,
|
||||
DownloadsPath: nil,
|
||||
ExecutablePath: nil,
|
||||
HandleSIGHUP: nil,
|
||||
HandleSIGINT: nil,
|
||||
HandleSIGTERM: nil,
|
||||
Headless: playwright.Bool(false),
|
||||
Proxy: nil,
|
||||
SlowMo: nil,
|
||||
Timeout: nil,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln("[core] ", "初始化chrome失败")
|
||||
log.Errorln("[core] ", err.Error())
|
||||
return
|
||||
}
|
||||
c.browser = browser
|
||||
context, err := c.browser.NewContext()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.context = context
|
||||
}
|
||||
|
||||
func (c *Core) Quit() {
|
||||
err := c.context.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = c.browser.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = c.pw.Stop()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Core) Login() ([]cookie, error) {
|
||||
page, err := c.context.NewPage()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = page.Goto("https://pc.xuexi.cn/points/login.html", playwright.PageGotoOptions{
|
||||
Referer: nil,
|
||||
Timeout: playwright.Float(30000),
|
||||
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln("[core] ", "打开登录页面失败")
|
||||
log.Errorln("[core] ", err.Error())
|
||||
|
||||
return nil, err
|
||||
}
|
||||
log.Infoln("[core] ", "正在等待二维码扫描")
|
||||
|
||||
_, _ = page.WaitForSelector(`#app > div > div.login_content > div > div.login_qrcode `)
|
||||
|
||||
_, err = page.Evaluate(`let h = document.body.scrollWidth/2;document.documentElement.scrollTop=h;`)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infoln("[core] ", "加载验证码中,请耐心等待")
|
||||
|
||||
frame := page.Frame(playwright.PageFrameOptions{
|
||||
Name: playwright.String(`ddlogin-iframe`),
|
||||
URL: nil,
|
||||
})
|
||||
if frame == nil {
|
||||
log.Errorln("获取frame失败")
|
||||
}
|
||||
|
||||
selector, err := frame.QuerySelector(`img`)
|
||||
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
img, err := selector.GetAttribute(`src`)
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
|
||||
return nil, err
|
||||
}
|
||||
img = strings.ReplaceAll(img, "data:image/png;base64,", "")
|
||||
go sendToQQ(img)
|
||||
data, err := base64.StdEncoding.DecodeString(img)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
os.WriteFile("qrcode.png", data, 0666)
|
||||
matrix, err := qrcode.Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
qrcodeTerminal.New().Get(matrix.Content).Print()
|
||||
|
||||
_, err = page.WaitForNavigation(playwright.PageWaitForNavigationOptions{
|
||||
Timeout: playwright.Float(30 * 1000 * 5),
|
||||
URL: nil,
|
||||
WaitUntil: nil,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
|
||||
return nil, err
|
||||
}
|
||||
cookies, err := c.context.Cookies() //nolint:wsl
|
||||
if err != nil {
|
||||
log.Errorln("[core] ", "获取cookie失败")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
cos []cookie
|
||||
)
|
||||
|
||||
for _, c := range cookies {
|
||||
co := cookie{}
|
||||
co.Name = c.Name
|
||||
co.Path = c.Path
|
||||
co.Value = c.Value
|
||||
co.Domain = c.Domain
|
||||
co.Expires = c.Expires
|
||||
co.HTTPOnly = c.HttpOnly
|
||||
co.SameSite = c.SameSite
|
||||
co.Secure = c.Secure
|
||||
cos = append(cos, co)
|
||||
}
|
||||
info, nick, err := GetUserInfo(cos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = SaveUser(User{
|
||||
Cookies: cos,
|
||||
Nick: nick,
|
||||
Uid: info,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cos, err
|
||||
}
|
||||
|
||||
func sendToQQ(img string) {
|
||||
err := gout.POST("http://127.0.0.1:5700/send_private_msg").SetJSON(map[string]interface{}{
|
||||
"user_id": 3343780376,
|
||||
"message": map[string]interface{}{
|
||||
"type": "image",
|
||||
"data": map[string]interface{}{
|
||||
"file": "base64://" + img,
|
||||
},
|
||||
},
|
||||
}).Do()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestName(t *testing.T) {
|
||||
core := Core{}
|
||||
core.Init()
|
||||
cookies, err := core.Login()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
score, err := GetUserScore(cookies)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(score)
|
||||
}
|
|
@ -0,0 +1,489 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
rand2 "math/rand"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mxschmitt/playwright-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
MyPointsUri = "https://pc.xuexi.cn/points/my-points.html"
|
||||
|
||||
DailyBUTTON = `#app > div > div.layout-body > div >
|
||||
div.my-points-section > div.my-points-content > div:nth-child(5) > div.my-points-card-footer > div.buttonbox > div`
|
||||
WEEKEND = `#app > div > div.layout-body >
|
||||
div > div.my-points-section > div.my-points-content > div:nth-child(6) > div.my-points-card-footer > div.buttonbox > div`
|
||||
SPECIALBUTTON = `#app > div > div.layout-body >
|
||||
div > div.my-points-section > div.my-points-content > div:nth-child(7) > div.my-points-card-footer > div.buttonbox > div`
|
||||
)
|
||||
|
||||
func (c *Core) RespondDaily(cookies []cookie, model string) {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
log.Errorln("答题模块异常结束")
|
||||
}
|
||||
}()
|
||||
|
||||
// 获取用户成绩
|
||||
score, err := GetUserScore(cookies)
|
||||
if err != nil {
|
||||
log.Errorln("获取分数失败,停止每日答题", err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
page, err := c.context.NewPage()
|
||||
if err != nil {
|
||||
log.Errorln("创建页面失败" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
err = c.context.AddCookies(cookieToParam(cookies)...)
|
||||
if err != nil {
|
||||
log.Errorln("添加cookie信息失败,已退出答题")
|
||||
|
||||
return
|
||||
}
|
||||
log.Infoln("已加载每日答题模块")
|
||||
|
||||
_, err = page.Goto(MyPointsUri, playwright.PageGotoOptions{
|
||||
Referer: playwright.String(MyPointsUri),
|
||||
Timeout: playwright.Float(1000),
|
||||
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln("跳转页面失败")
|
||||
|
||||
return
|
||||
}
|
||||
switch model {
|
||||
case "daily":
|
||||
{
|
||||
// 检测是否已经完成
|
||||
if score.Content["daily"].CurrentScore >= score.Content["daily"].MaxScore {
|
||||
log.Infoln("检测到每日答题已经完成,即将退出答题")
|
||||
|
||||
return
|
||||
}
|
||||
err = page.Click(DailyBUTTON)
|
||||
if err != nil {
|
||||
log.Errorln("跳转到积分页面错误")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
case "weekly":
|
||||
{
|
||||
// 检测是否已经完成
|
||||
if score.Content["weekly"].CurrentScore >= score.Content["weekly"].MaxScore {
|
||||
log.Infoln("检测到每周答题已经完成,即将退出答题")
|
||||
|
||||
return
|
||||
}
|
||||
err = page.Click(WEEKEND)
|
||||
if err != nil {
|
||||
log.Errorln("跳转到积分页面错误")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
case "special":
|
||||
{
|
||||
// 检测是否已经完成
|
||||
if score.Content["special"].CurrentScore >= score.Content["special"].MaxScore {
|
||||
log.Infoln("检测到特殊答题已经完成,即将退出答题")
|
||||
|
||||
return
|
||||
}
|
||||
err = page.Click(SPECIALBUTTON)
|
||||
if err != nil {
|
||||
log.Errorln("跳转到积分页面错误")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
getAnswerPage(page, model)
|
||||
|
||||
for true {
|
||||
// 查看是否存在答题按钮,若按钮可用则重新提交答题
|
||||
btn, err := page.QuerySelector(`#app > div > div.layout-body > div > div.detail-body > div.action-row > button`)
|
||||
if err != nil {
|
||||
log.Infoln("获取提交按钮失败,本次答题结束" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
enabled, err := btn.IsEnabled()
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
continue
|
||||
}
|
||||
if enabled {
|
||||
log.Infoln("检测到有答案未提交,将重新提交")
|
||||
err := btn.Click()
|
||||
if err != nil {
|
||||
log.Errorln("提交答案失败")
|
||||
}
|
||||
}
|
||||
switch model {
|
||||
case "daily":
|
||||
{
|
||||
// 检测是否已经完成
|
||||
if score.Content["daily"].CurrentScore >= score.Content["daily"].MaxScore {
|
||||
log.Infoln("检测到每日答题已经完成,即将退出答题")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
case "weekly":
|
||||
{
|
||||
// 检测是否已经完成
|
||||
if score.Content["weekly"].CurrentScore >= score.Content["weekly"].MaxScore {
|
||||
log.Infoln("检测到每周答题已经完成,即将退出答题")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
case "special":
|
||||
{
|
||||
// 检测是否已经完成
|
||||
if score.Content["special"].CurrentScore >= score.Content["special"].MaxScore {
|
||||
log.Infoln("检测到特殊答题已经完成,即将退出答题")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取题目类型
|
||||
category, err := page.QuerySelector(
|
||||
`#app > div > div.layout-body > div > div.detail-body > div.question > div.q-header`)
|
||||
if err != nil {
|
||||
log.Errorln("没有找到题目元素" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// 获取题目
|
||||
question, err := page.QuerySelector(
|
||||
`#app > div > div.layout-body > div > div.detail-body > div.question > div.q-body > div`)
|
||||
if err != nil {
|
||||
log.Errorln("未找到题目问题元素")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
categoryText, err := category.TextContent()
|
||||
if err != nil {
|
||||
log.Errorln("获取题目元素失败" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
log.Infoln("## 题目类型:" + categoryText)
|
||||
|
||||
questionText, err := question.TextContent()
|
||||
if err != nil {
|
||||
log.Errorln("获取题目问题失败" + err.Error())
|
||||
return
|
||||
}
|
||||
log.Infoln("## 题目:" + questionText)
|
||||
|
||||
// 获取答题帮助
|
||||
openTips, err := page.QuerySelector(
|
||||
`#app > div > div.layout-body > div > div.detail-body > div.question > div.q-footer > span`)
|
||||
if err != nil {
|
||||
log.Errorln("为获取到题目提示信息" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
err = openTips.Click()
|
||||
if err != nil {
|
||||
log.Errorln("点击打开提示信息按钮失败" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
content, err := page.Content()
|
||||
if err != nil {
|
||||
log.Errorln("获取网页全体内容失败" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
err = openTips.Click()
|
||||
if err != nil {
|
||||
log.Errorln("点击打开提示信息按钮失败" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
tips := getTips(content)
|
||||
log.Infoln("[提示信息]:", tips)
|
||||
// 填空题
|
||||
switch {
|
||||
case strings.Contains(categoryText, "填空题"):
|
||||
err := FillBlank(page, tips)
|
||||
if err != nil {
|
||||
log.Errorln("填空题答题失败" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
case strings.Contains(categoryText, "多选题"):
|
||||
log.Infoln("读取到多选题")
|
||||
options, err := getOptions(page)
|
||||
if err != nil {
|
||||
log.Errorln("获取选项失败" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
log.Infoln("获取到选项答案:", options)
|
||||
log.Infoln("[多选题选项]:", options)
|
||||
var answer []string
|
||||
for _, option := range options {
|
||||
for _, tip := range tips {
|
||||
if strings.Contains(option, tip) {
|
||||
answer = append(answer, option)
|
||||
}
|
||||
}
|
||||
}
|
||||
err = radioCheck(page, answer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case strings.Contains(categoryText, "单选题"):
|
||||
log.Infoln("读取到单选题")
|
||||
options, err := getOptions(page)
|
||||
if err != nil {
|
||||
log.Errorln("获取选项失败" + err.Error())
|
||||
return
|
||||
}
|
||||
log.Infoln("获取到选项答案:", options)
|
||||
log.Infoln("[多选题选项]:", options)
|
||||
var answer []string
|
||||
for _, option := range options {
|
||||
for _, tip := range tips {
|
||||
if strings.Contains(option, tip) {
|
||||
answer = append(answer, option)
|
||||
}
|
||||
}
|
||||
}
|
||||
err = radioCheck(page, answer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
score, _ = GetUserScore(cookies)
|
||||
}
|
||||
}
|
||||
|
||||
func getAnswerPage(page playwright.Page, model string) {
|
||||
selectPages, err := page.QuerySelectorAll(`#app .ant-pagination .ant-pagination-item`)
|
||||
if err != nil {
|
||||
log.Errorln("获取到页码失败")
|
||||
|
||||
return
|
||||
}
|
||||
log.Infoln("共获取到", len(selectPages), "页")
|
||||
modelName := ""
|
||||
modelSlector := ""
|
||||
switch model {
|
||||
case "daily":
|
||||
return
|
||||
case "weekly":
|
||||
modelName = "每周答题"
|
||||
modelSlector = "button.ant-btn-primary"
|
||||
case "special":
|
||||
modelName = "专项答题"
|
||||
modelSlector = "#app .items .item button"
|
||||
}
|
||||
for i := 1; i <= len(selectPages); i++ {
|
||||
log.Infoln("获取到"+modelName, "第", i, "页")
|
||||
err1 := selectPages[i-1].Click()
|
||||
if err1 != nil {
|
||||
log.Errorln("点击页码失败")
|
||||
}
|
||||
datas, err := page.QuerySelectorAll(modelSlector)
|
||||
if err != nil {
|
||||
log.Errorln("获取页面内容失败")
|
||||
continue
|
||||
}
|
||||
for _, data := range datas {
|
||||
time.Sleep(3 * time.Second)
|
||||
content, err := data.TextContent()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(content, "重新") || strings.Contains(content, "满分") {
|
||||
continue
|
||||
} else {
|
||||
if strings.Contains(content, "电影试题") {
|
||||
log.Infoln("发现有未答题的电影试题")
|
||||
continue
|
||||
}
|
||||
enabled, err := data.IsEnabled()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if enabled {
|
||||
log.Infoln("按钮可用")
|
||||
}
|
||||
err = data.Click(playwright.ElementHandleClickOptions{
|
||||
Button: nil,
|
||||
ClickCount: playwright.Int(2),
|
||||
Delay: nil,
|
||||
Force: nil,
|
||||
Modifiers: nil,
|
||||
NoWaitAfter: nil,
|
||||
Position: nil,
|
||||
Timeout: playwright.Float(100000),
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln("点击按钮失败" + err.Error())
|
||||
time.Sleep(2 * time.Second)
|
||||
continue
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func radioCheck(page playwright.Page, answer []string) error {
|
||||
radios, err := page.QuerySelectorAll(`.q-answer.choosable`)
|
||||
if err != nil {
|
||||
log.Errorln("获取选项失败")
|
||||
|
||||
return err
|
||||
}
|
||||
log.Debugln("获取到", len(radios), "个按钮")
|
||||
for _, radio := range radios {
|
||||
textContent, err := radio.TextContent()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, s := range answer {
|
||||
if textContent == s {
|
||||
err := radio.Click()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r := rand2.Intn(2)
|
||||
time.Sleep(time.Duration(r) * time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
r := rand2.Intn(5)
|
||||
time.Sleep(time.Duration(r) * time.Second)
|
||||
checkNextBotton(page)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getOptions(page playwright.Page) ([]string, error) {
|
||||
handles, err := page.QuerySelectorAll(`.q-answer.choosable`)
|
||||
if err != nil {
|
||||
log.Errorln("获取选项信息失败")
|
||||
return nil, err
|
||||
}
|
||||
var options []string
|
||||
for _, handle := range handles {
|
||||
content, err := handle.TextContent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
options = append(options, content)
|
||||
}
|
||||
return options, err
|
||||
}
|
||||
|
||||
func getTips(data string) []string {
|
||||
data = strings.ReplaceAll(data, " ", "")
|
||||
data = strings.ReplaceAll(data, "\n", "")
|
||||
compile := regexp.MustCompile(`<fontcolor="red">(.*?)</font>`)
|
||||
match := compile.FindAllStringSubmatch(data, -1)
|
||||
var tips []string
|
||||
for _, i := range match {
|
||||
tips = append(tips, i[1])
|
||||
}
|
||||
return tips
|
||||
}
|
||||
|
||||
func FillBlank(page playwright.Page, tips []string) error {
|
||||
video := false
|
||||
var answer []string
|
||||
for _, tip := range tips {
|
||||
if tip == "请观看视频" {
|
||||
video = true
|
||||
}
|
||||
}
|
||||
if video {
|
||||
answer = append(answer, "不知道")
|
||||
} else {
|
||||
answer = tips
|
||||
}
|
||||
inouts, err := page.QuerySelectorAll(`div.q-body > div > input`)
|
||||
if err != nil {
|
||||
log.Errorln("获取输入框错误" + err.Error())
|
||||
return err
|
||||
}
|
||||
log.Debugln("获取到", len(inouts), "个填空")
|
||||
if len(inouts) == 1 && len(tips) > 1 {
|
||||
temp := ""
|
||||
for _, tip := range tips {
|
||||
temp += tip
|
||||
}
|
||||
answer = strings.Split(temp, ",")
|
||||
log.Infoln("答案已合并处理" + err.Error())
|
||||
}
|
||||
for i := 0; i < len(inouts); i++ {
|
||||
err := inouts[i].Fill(answer[i])
|
||||
if err != nil {
|
||||
log.Errorln("填充答案失败" + err.Error())
|
||||
continue
|
||||
}
|
||||
r := rand2.Intn(5)
|
||||
time.Sleep(time.Duration(r) * time.Second)
|
||||
}
|
||||
r := rand2.Intn(2)
|
||||
time.Sleep(time.Duration(r) * time.Second)
|
||||
checkNextBotton(page)
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkNextBotton(page playwright.Page) {
|
||||
btns, err := page.QuerySelectorAll(`#app .action-row > button`)
|
||||
if err != nil {
|
||||
log.Errorln("未检测到按钮" + err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
if len(btns) <= 1 {
|
||||
err := btns[0].Check()
|
||||
if err != nil {
|
||||
log.Errorln("点击吓一题按钮失败")
|
||||
|
||||
return
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
_, err = btns[0].GetAttribute("disabled")
|
||||
if err != nil {
|
||||
log.Infoln("未检测到禁言属性")
|
||||
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err := btns[1].Click()
|
||||
if err != nil {
|
||||
log.Errorln("提交试卷失败")
|
||||
|
||||
return
|
||||
}
|
||||
log.Infoln("已成功提交试卷")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/guonaihong/gout"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Score struct {
|
||||
TotalScore int
|
||||
TodayScore int
|
||||
Content map[string]Data
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
CurrentScore int
|
||||
MaxScore int
|
||||
}
|
||||
|
||||
func GetUserScore(cookies []cookie) (Score, error) {
|
||||
var score Score
|
||||
var resp []byte
|
||||
// 获取用户总分
|
||||
err := gout.GET(user_totalScore_url).SetCookies(cookieToJar(cookies)...).SetHeader(gout.H{
|
||||
"Cache-Control": "no-cache",
|
||||
}).BindBody(&resp).Do()
|
||||
if err != nil {
|
||||
log.Errorln("获取用户总分错误" + err.Error())
|
||||
|
||||
return Score{}, err
|
||||
}
|
||||
log.Debugln(gjson.GetBytes(resp, "@this|@pretty"))
|
||||
score.TotalScore = int(gjson.GetBytes(resp, "data.score").Int())
|
||||
|
||||
// 获取用户今日得分
|
||||
err = gout.GET(user_todayTotalScore_url).SetCookies(cookieToJar(cookies)...).SetHeader(gout.H{
|
||||
"Cache-Control": "no-cache",
|
||||
}).BindBody(&resp).Do()
|
||||
if err != nil {
|
||||
log.Errorln("获取用户每日总分错误" + err.Error())
|
||||
|
||||
return Score{}, err
|
||||
}
|
||||
log.Debugln(gjson.GetBytes(resp, "@this|@pretty"))
|
||||
score.TodayScore = int(gjson.GetBytes(resp, "data.score").Int())
|
||||
|
||||
err = gout.GET(user_rateScore_url).SetCookies(cookieToJar(cookies)...).SetHeader(gout.H{
|
||||
"Cache-Control": "no-cache",
|
||||
}).BindBody(&resp).Do()
|
||||
if err != nil {
|
||||
log.Errorln("获取用户积分出现错误" + err.Error())
|
||||
return Score{}, err
|
||||
}
|
||||
log.Debugln(gjson.GetBytes(resp, "@this|@pretty"))
|
||||
datas := gjson.GetBytes(resp, "data.taskProgress").Array()
|
||||
m := make(map[string]Data, 7)
|
||||
m["article"] = Data{
|
||||
CurrentScore: int(datas[0].Get("currentScore").Int()),
|
||||
MaxScore: int(datas[0].Get("dayMaxScore").Int()),
|
||||
}
|
||||
m["video"] = Data{
|
||||
CurrentScore: int(datas[1].Get("currentScore").Int()),
|
||||
MaxScore: int(datas[1].Get("dayMaxScore").Int()),
|
||||
}
|
||||
m["weekly"] = Data{
|
||||
CurrentScore: int(datas[2].Get("currentScore").Int()),
|
||||
MaxScore: int(datas[2].Get("dayMaxScore").Int()),
|
||||
}
|
||||
m["video_time"] = Data{
|
||||
CurrentScore: int(datas[3].Get("currentScore").Int()),
|
||||
MaxScore: int(datas[3].Get("dayMaxScore").Int()),
|
||||
}
|
||||
m["login"] = Data{
|
||||
CurrentScore: int(datas[4].Get("currentScore").Int()),
|
||||
MaxScore: int(datas[4].Get("dayMaxScore").Int()),
|
||||
}
|
||||
m["special"] = Data{
|
||||
CurrentScore: int(datas[5].Get("currentScore").Int()),
|
||||
MaxScore: int(datas[5].Get("dayMaxScore").Int()),
|
||||
}
|
||||
m["daily"] = Data{
|
||||
CurrentScore: int(datas[6].Get("currentScore").Int()),
|
||||
MaxScore: int(datas[6].Get("dayMaxScore").Int()),
|
||||
}
|
||||
|
||||
score.Content = m
|
||||
|
||||
return score, err
|
||||
}
|
||||
|
||||
func PrintScore(score Score) {
|
||||
log.Infoln(fmt.Sprintf("当前学习总积分:%d 今日得分:%d", score.TodayScore, score.TodayScore))
|
||||
for s, data := range score.Content {
|
||||
log.Infoln(s, ": ", data.CurrentScore, "/", data.MaxScore)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/guonaihong/gout"
|
||||
"github.com/mxschmitt/playwright-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var (
|
||||
article_url_list = []string{
|
||||
"https://www.xuexi.cn/lgdata/35il6fpn0ohq.json",
|
||||
"https://www.xuexi.cn/lgdata/45a3hac2bf1j.json",
|
||||
"https://www.xuexi.cn/lgdata/1ajhkle8l72.json",
|
||||
"https://www.xuexi.cn/lgdata/1ahjpjgb4n3.json",
|
||||
"https://www.xuexi.cn/lgdata/1je1objnh73.json",
|
||||
"https://www.xuexi.cn/lgdata/1kvrj9vvv73.json",
|
||||
"https://www.xuexi.cn/lgdata/17qonfb74n3.json",
|
||||
"https://www.xuexi.cn/lgdata/1i30sdhg0n3.json"}
|
||||
|
||||
video_url_list = []string{
|
||||
"https://www.xuexi.cn/lgdata/3j2u3cttsii9.json",
|
||||
"https://www.xuexi.cn/lgdata/1novbsbi47k.json",
|
||||
"https://www.xuexi.cn/lgdata/31c9ca1tgfqb.json",
|
||||
"https://www.xuexi.cn/lgdata/1oajo2vt47l.json",
|
||||
"https://www.xuexi.cn/lgdata/18rkaul9h7l.json",
|
||||
"https://www.xuexi.cn/lgdata/2qfjjjrprmdh.json",
|
||||
"https://www.xuexi.cn/lgdata/3o3ufqgl8rsn.json",
|
||||
"https://www.xuexi.cn/lgdata/525pi8vcj24p.json",
|
||||
"https://www.xuexi.cn/lgdata/1742g60067k.json"}
|
||||
)
|
||||
|
||||
type Link struct {
|
||||
Editor string `json:"editor"`
|
||||
PublishTime string `json:"publishTime"`
|
||||
ItemType string `json:"itemType"`
|
||||
Author string `json:"author"`
|
||||
CrossTime int `json:"crossTime"`
|
||||
Source string `json:"source"`
|
||||
NameB string `json:"nameB"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
Url string `json:"url"`
|
||||
ShowSource string `json:"showSource"`
|
||||
ItemId string `json:"itemId"`
|
||||
ThumbImage string `json:"thumbImage"`
|
||||
AuditTime string `json:"auditTime"`
|
||||
ChannelNames []string `json:"channelNames"`
|
||||
Producer string `json:"producer"`
|
||||
ChannelIds []string `json:"channelIds"`
|
||||
DataValid bool `json:"dataValid"`
|
||||
}
|
||||
|
||||
func getLinks(model string) ([]Link, error) {
|
||||
UID := rand.Intn(20000000) + 10000000
|
||||
learnUrl := ""
|
||||
if model == "article" {
|
||||
learnUrl = article_url_list[rand.Intn(7)]
|
||||
} else if model == "video" {
|
||||
learnUrl = video_url_list[rand.Intn(7)]
|
||||
} else {
|
||||
return nil, errors.New("model选择出现错误")
|
||||
}
|
||||
var (
|
||||
resp []byte
|
||||
)
|
||||
|
||||
err := gout.GET(learnUrl + "?_st=" + strconv.Itoa(UID)).BindBody(&resp).Do()
|
||||
if err != nil {
|
||||
log.Errorln("请求连接列表出现错误" + err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var links []Link
|
||||
err = json.Unmarshal(resp, &links)
|
||||
if err != nil {
|
||||
log.Errorln("解析列表出现错误" + err.Error())
|
||||
return nil, err
|
||||
}
|
||||
return links, err
|
||||
}
|
||||
|
||||
func (c *Core) LearnArticle(cookies []cookie) {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
log.Errorln("文章学习模块异常结束")
|
||||
}
|
||||
}()
|
||||
|
||||
score, err := GetUserScore(cookies)
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
return
|
||||
}
|
||||
links, _ := getLinks("article")
|
||||
if score.Content["article"].CurrentScore < score.Content["article"].MaxScore {
|
||||
log.Infoln("开始加载文章学习模块")
|
||||
page, err := c.context.NewPage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = c.context.AddCookies(cookieToParam(cookies)...)
|
||||
if err != nil {
|
||||
log.Errorln("添加cookie失败" + err.Error())
|
||||
return
|
||||
}
|
||||
tryCount := 0
|
||||
|
||||
for {
|
||||
if tryCount < 20 {
|
||||
PrintScore(score)
|
||||
n := rand.Intn(len(links))
|
||||
_, err := page.Goto(links[n].Url, playwright.PageGotoOptions{
|
||||
Referer: playwright.String(links[rand.Intn(len(links))].Url),
|
||||
Timeout: playwright.Float(10000),
|
||||
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln("页面跳转失败")
|
||||
}
|
||||
log.Infoln("正在学习文章:" + links[n].Title)
|
||||
log.Infoln("文章发布时间:" + links[n].PublishTime)
|
||||
log.Infoln("文章学习链接:" + links[n].Url)
|
||||
learnTime := 50 + rand.Intn(5) + 10
|
||||
log.Infoln(fmt.Sprintf("正在进行阅读学习中,剩余%d篇,本篇剩余时间%d秒", score.Content["article"].MaxScore-score.Content["article"].CurrentScore, learnTime))
|
||||
for i := 0; i < learnTime; i++ {
|
||||
if rand.Float32() > 0.5 {
|
||||
go func() {
|
||||
_, err = page.Evaluate(fmt.Sprintf(`let h = document.body.scrollHeight/120*%d;document.documentElement.scrollTop=h;`, i))
|
||||
if err != nil {
|
||||
log.Errorln("文章滑动失败")
|
||||
}
|
||||
}()
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
if score.Content["article"].CurrentScore >= score.Content["article"].MaxScore {
|
||||
log.Infoln("检测到本次阅读学习分数已满,退出学习")
|
||||
break
|
||||
}
|
||||
score, _ = GetUserScore(cookies)
|
||||
tryCount++
|
||||
} else {
|
||||
log.Errorln("阅读学习出现异常,稍后可重新学习")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Infoln("检测到文章学习已经完成")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Core) LearnVideo(cookies []cookie) {
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
log.Errorln("视频学习模块异常结束")
|
||||
}
|
||||
}()
|
||||
score, err := GetUserScore(cookies)
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
return
|
||||
}
|
||||
links, _ := getLinks("video")
|
||||
if score.Content["video"].CurrentScore < score.Content["video"].MaxScore || score.Content["video_time"].CurrentScore < score.Content["video_time"].MaxScore {
|
||||
log.Infoln("开始加载视频学习模块")
|
||||
// core := Core{}
|
||||
//core.Init()
|
||||
|
||||
page, err := c.context.NewPage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var resp string
|
||||
err = gout.GET("http://1.15.144.22/stealth.min.js").BindBody(&resp).Do()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = page.AddInitScript(playwright.PageAddInitScriptOptions{
|
||||
Script: playwright.String(resp),
|
||||
Path: nil,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = c.context.AddCookies(cookieToParam(cookies)...)
|
||||
if err != nil {
|
||||
log.Errorln("添加cookie失败" + err.Error())
|
||||
return
|
||||
}
|
||||
tryCount := 0
|
||||
networkCookies, err := c.context.Cookies()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, networkCookie := range networkCookies {
|
||||
fmt.Println(networkCookie.Name)
|
||||
}
|
||||
|
||||
for {
|
||||
if tryCount < 20 {
|
||||
PrintScore(score)
|
||||
n := rand.Intn(len(links))
|
||||
_, err := page.Goto(links[n].Url, playwright.PageGotoOptions{
|
||||
Referer: playwright.String(links[rand.Intn(len(links))].Url),
|
||||
Timeout: playwright.Float(10000),
|
||||
WaitUntil: playwright.WaitUntilStateDomcontentloaded,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorln("页面跳转失败")
|
||||
}
|
||||
log.Infoln("正在观看视频:" + links[n].Title)
|
||||
log.Infoln("视频发布时间:" + links[n].PublishTime)
|
||||
log.Infoln("视频学习链接:" + links[n].Url)
|
||||
learnTime := 50 + rand.Intn(5) + 10
|
||||
log.Infoln(fmt.Sprintf("正在进行视频学习中,剩余%d个,当前剩余时间%d秒", score.Content["video"].MaxScore-score.Content["video"].CurrentScore, learnTime))
|
||||
for i := 0; i < learnTime; i++ {
|
||||
if rand.Float32() > 0.5 {
|
||||
go func() {
|
||||
_, err := page.Evaluate(fmt.Sprintf(`let h = document.body.scrollHeight/120*%d;document.documentElement.scrollTop=h;`, i))
|
||||
if err != nil {
|
||||
log.Errorln("视频滑动失败")
|
||||
}
|
||||
}()
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
if score.Content["video"].CurrentScore >= score.Content["video"].MaxScore || score.Content["video_time"].CurrentScore >= score.Content["video_time"].MaxScore {
|
||||
log.Infoln("检测到本次视频学习分数已满,退出学习")
|
||||
break
|
||||
}
|
||||
score, _ = GetUserScore(cookies)
|
||||
tryCount++
|
||||
} else {
|
||||
log.Errorln("视频学习出现异常,稍后可重新学习")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Infoln("检测到视频学习已经完成")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestName1(t *testing.T) {
|
||||
CheckUserCookie(User{})
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
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"
|
||||
)
|
|
@ -0,0 +1,117 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/guonaihong/gout"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func init() {
|
||||
_, err := os.Stat(`./config/user.json`)
|
||||
if err != nil {
|
||||
err := os.WriteFile(user_path, []byte("[]"), 0666)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
user_path = "./config/user.json"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Cookies []cookie `json:"cookies"`
|
||||
Nick string `json:"nick"`
|
||||
Uid string `json:"uid"`
|
||||
}
|
||||
|
||||
func GetUsers() ([]User, error) {
|
||||
file, err := os.ReadFile(user_path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var users []User
|
||||
err = json.Unmarshal(file, &users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var newUsers []User
|
||||
for i := 0; i < len(users); i++ {
|
||||
if CheckUserCookie(users[i]) {
|
||||
newUsers = append(newUsers, users[i])
|
||||
continue
|
||||
}
|
||||
log.Infoln("用户" + users[i].Nick + "cookie已失效")
|
||||
}
|
||||
return users, err
|
||||
}
|
||||
|
||||
func SaveUser(user User) error {
|
||||
users, err := GetUsers()
|
||||
if err != nil {
|
||||
log.Errorln("获取用户信息错误")
|
||||
return err
|
||||
}
|
||||
a := false
|
||||
for _, u := range users {
|
||||
if u.Uid == user.Uid {
|
||||
u.Cookies = user.Cookies
|
||||
a = true
|
||||
}
|
||||
}
|
||||
if !a {
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(&users)
|
||||
if err != nil {
|
||||
log.Errorln("序列化用户失败")
|
||||
return err
|
||||
}
|
||||
err = os.WriteFile(user_path, data, 0666)
|
||||
if err != nil {
|
||||
log.Errorln("写入用户信息到文件错误")
|
||||
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func GetUserInfo(cookies []cookie) (string, string, error) {
|
||||
var resp []byte
|
||||
err := gout.GET(user_Info_url).
|
||||
SetCookies(cookieToJar(cookies)...).
|
||||
SetHeader(gout.H{
|
||||
"Cache-Control": "no-cache",
|
||||
}).BindBody(&resp).Do()
|
||||
if err != nil {
|
||||
log.Errorln("获取用户信息失败")
|
||||
|
||||
return "", "", err
|
||||
}
|
||||
log.Debugln("[user] 用户信息:", gjson.GetBytes(resp, "@this|@pretty").String())
|
||||
uid := gjson.GetBytes(resp, "data.uid").String()
|
||||
nick := gjson.GetBytes(resp, "data.nick").String()
|
||||
|
||||
return uid, nick, err
|
||||
}
|
||||
|
||||
func CheckUserCookie(user User) bool {
|
||||
var resp []byte
|
||||
err := gout.GET(`https://pc-api.xuexi.cn/open/api/score/get?_t=1636607911602`).SetCookies(cookieToJar(user.Cookies)...).BindBody(&resp).Do()
|
||||
if err != nil {
|
||||
log.Errorln(err.Error())
|
||||
|
||||
return true
|
||||
}
|
||||
if gjson.GetBytes(resp, "code").Int() == 401 && gjson.GetBytes(resp, "message").String() == "token check failed" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
package lib
|
|
@ -0,0 +1,47 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/mxschmitt/playwright-go"
|
||||
)
|
||||
|
||||
func cookieToJar(cookies []cookie) []*http.Cookie {
|
||||
var (
|
||||
cooks []*http.Cookie
|
||||
)
|
||||
for _, c := range cookies {
|
||||
cooks = append(
|
||||
cooks,
|
||||
&http.Cookie{
|
||||
Name: c.Name,
|
||||
Value: c.Value,
|
||||
Path: c.Path,
|
||||
Domain: c.Domain,
|
||||
Secure: c.Secure,
|
||||
HttpOnly: c.HTTPOnly,
|
||||
},
|
||||
)
|
||||
}
|
||||
return cooks
|
||||
}
|
||||
|
||||
func cookieToParam(cookies []cookie) []playwright.SetNetworkCookieParam {
|
||||
var (
|
||||
cooks []playwright.SetNetworkCookieParam
|
||||
)
|
||||
for _, c := range cookies {
|
||||
cooks = append(cooks, playwright.SetNetworkCookieParam{
|
||||
Name: c.Name,
|
||||
Value: c.Value,
|
||||
URL: playwright.String(""),
|
||||
Domain: playwright.String(c.Domain),
|
||||
Path: playwright.String(c.Path),
|
||||
Expires: playwright.Int(c.Expires),
|
||||
HttpOnly: playwright.Bool(c.HTTPOnly),
|
||||
Secure: playwright.Bool(c.Secure),
|
||||
SameSite: playwright.String(c.SameSite),
|
||||
})
|
||||
}
|
||||
return cooks
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
rotates "github.com/lestrrat-go/file-rotatelogs"
|
||||
log "github.com/sirupsen/logrus"
|
||||
easy "github.com/t-tomalak/logrus-easy-formatter"
|
||||
|
||||
"github.com/huoxue1/study_xxqg/lib"
|
||||
)
|
||||
|
||||
func init() {
|
||||
config = lib.GetConfig()
|
||||
logFormatter := &easy.Formatter{
|
||||
TimestampFormat: "2006-01-02 15:04:05",
|
||||
LogFormat: "[%time%] [%lvl%]: %msg% \n",
|
||||
}
|
||||
w, err := rotates.New(path.Join("logs", "%Y-%m-%d.log"), rotates.WithRotationTime(time.Hour*24))
|
||||
if err != nil {
|
||||
log.Errorf("rotates init err: %v", err)
|
||||
panic(err)
|
||||
}
|
||||
log.SetOutput(w)
|
||||
log.SetFormatter(logFormatter)
|
||||
level, err := log.ParseLevel(config.LogLevel)
|
||||
|
||||
log.SetLevel(level)
|
||||
}
|
||||
|
||||
var (
|
||||
config lib.Config
|
||||
)
|
||||
|
||||
func init() {
|
||||
_, err := os.Stat(`./config/`)
|
||||
if err != nil {
|
||||
os.Mkdir("./config/", 0666)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
log.Infoln(`// 刷课模式,默认为1,
|
||||
1:只刷文章何视频
|
||||
2:只刷文章和视频和每日答题
|
||||
3:刷文章和视频和每日答题每周答题和专项答题`)
|
||||
log.Infoln("检测到模式", config.Model)
|
||||
core := lib.Core{}
|
||||
defer core.Quit()
|
||||
core.Init()
|
||||
login, err := core.Login()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
core.LearnArticle(login)
|
||||
core.LearnVideo(login)
|
||||
if config.Model == 2 {
|
||||
core.RespondDaily(login, "daily")
|
||||
} else if config.Model == 3 {
|
||||
core.RespondDaily(login, "daily")
|
||||
core.RespondDaily(login, "weekly")
|
||||
core.RespondDaily(login, "special")
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
|
@ -0,0 +1 @@
|
|||
[{"cookies":[{"name":"_uab_collina","value":"163661069885993287694617","domain":"pc.xuexi.cn","path":"/points","expires":1951970698,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"__UID__","value":"4d0dda30-42b5-11ec-8eab-7b360a497c38","domain":".xuexi.cn","path":"/","expires":1668146699,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"tmzw","value":"1636610699718","domain":".xuexi.cn","path":"/","expires":1636697099,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"zwfigprt","value":"326756256aef95deeac0da98de19540a","domain":".xuexi.cn","path":"/","expires":1636697099,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"3212c84c4db8248eb50cafb336966f583ec86bde33da115a4561f52089443041","domain":"pc-api.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10a16366106974298596e40c8422b249f6358963e35bdec6a06e7fffc","domain":"pc-api.xuexi.cn","path":"/","expires":1636612500,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"e1ca5c9dbc630cf0cd3a4479a7cb7827b29e00e66d27bc969d7ede5f659a28ac","domain":"login.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10a16366106983052977e40cad89c774137b66301bdc7f0766c8365f7","domain":"login.xuexi.cn","path":"/","expires":1636612501,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"q2kIFvUvu68jwgrLg7LXxzt6sp2n","domain":"login.xuexi.cn","path":"/","expires":1652162702,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"qnkIdvOnu16j6LrUR7d9xjnosUR9","domain":"pc.xuexi.cn","path":"/","expires":1652162702,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"y5kOpvmgu6zjFnrqU8Is8atmzI1e","domain":"www.xuexi.cn","path":"/","expires":1652162702,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"token","value":"393807e803174851ac408d5a97ae0d97","domain":".xuexi.cn","path":"/","expires":1636632336,"httpOnly":false,"secure":false,"same_site":"None"}],"nick":"gjs","uid":"151172176463"},{"cookies":[{"name":"_uab_collina","value":"163661377781318630961955","domain":"pc.xuexi.cn","path":"/points","expires":1951973777,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"__UID__","value":"78569db0-42bc-11ec-9199-7dc30372e140","domain":".xuexi.cn","path":"/","expires":1668149778,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"tmzw","value":"1636613778733","domain":".xuexi.cn","path":"/","expires":1636700178,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"zwfigprt","value":"d90dcffd85a58b9228f41a3564b585f9","domain":".xuexi.cn","path":"/","expires":1636700178,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"e73d7582129f14b8e44805900fe16c6b3d1cb98cfbf3e92e2daaf5de778a0041","domain":"pc-api.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10a16366137763874277e40f11af2eb6b2a22101afc55394b828f1b9e","domain":"pc-api.xuexi.cn","path":"/","expires":1636615579,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"aliyungf_tc","value":"edf43c7511240e88c17b406bf729a9ee5fa1c286aab41995912ee012e478d4d6","domain":"login.xuexi.cn","path":"/","expires":-1,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"acw_tc","value":"2f6fc10a16366137768314189e40f324b65cd4dd52322d849bd68424a12439","domain":"login.xuexi.cn","path":"/","expires":1636615579,"httpOnly":true,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"tqkLUvkhuFalRsl0d7n7pqw2X2nb","domain":"www.xuexi.cn","path":"/","expires":1652165781,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"U6kIsvCyud8lhglmb8ev1pk5pnak","domain":"login.xuexi.cn","path":"/","expires":1652165781,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"_bl_uid","value":"ItkwCv85uFqlyLl038zb1v6nzy2b","domain":"pc.xuexi.cn","path":"/","expires":1652165781,"httpOnly":false,"secure":false,"same_site":"None"},{"name":"token","value":"c18d4e0283514eeda1a4fe6cf63e3ac6","domain":".xuexi.cn","path":"/","expires":1636635418,"httpOnly":false,"secure":false,"same_site":"None"}],"nick":"苟江山","uid":"151142372517"}]
|
Loading…
Reference in New Issue