mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 22:00:11 +08:00
Compare commits
239 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62a57fa61d | ||
|
|
0142050d6a | ||
|
|
9cfad308b0 | ||
|
|
28a8ee945c | ||
|
|
2154faec2c | ||
|
|
577b3f3f30 | ||
|
|
99c9cc3de6 | ||
|
|
216d99c05d | ||
|
|
8101c02ca8 | ||
|
|
da81875f8b | ||
|
|
dd1a0ae478 | ||
|
|
aafac8d6fa | ||
|
|
a74bcb869a | ||
|
|
584882282f | ||
|
|
05345e4c13 | ||
|
|
b8a57b80f2 | ||
|
|
177fdbae68 | ||
|
|
fef48e405a | ||
|
|
2d1603d65a | ||
|
|
73c7bbda1a | ||
|
|
558c3ee482 | ||
|
|
bc20d95bd1 | ||
|
|
883adc621c | ||
|
|
7be1f2342b | ||
|
|
4481ea4861 | ||
|
|
4aace203cf | ||
|
|
324a0022a7 | ||
|
|
8825514fb2 | ||
|
|
d2e6c9780f | ||
|
|
06b8b518f8 | ||
|
|
aa67d09ee1 | ||
|
|
724e48f3e8 | ||
|
|
57c95178d8 | ||
|
|
1e2d425cf4 | ||
|
|
c22e4b543c | ||
|
|
4434a617ed | ||
|
|
d6eb3ba28c | ||
|
|
d0f4d296d9 | ||
|
|
13aaaba8f3 | ||
|
|
3302d8d295 | ||
|
|
dd328afae8 | ||
|
|
d304cda7f0 | ||
|
|
109395a6af | ||
|
|
f7c0f4df98 | ||
|
|
43cc90b724 | ||
|
|
7bd1653cb5 | ||
|
|
6c4c6a3b8b | ||
|
|
72e0e796c4 | ||
|
|
3c41c18d27 | ||
|
|
7640f0cfac | ||
|
|
73eef961b5 | ||
|
|
8e87be262c | ||
|
|
8811df5968 | ||
|
|
f09f15937c | ||
|
|
49983ab451 | ||
|
|
4dd5189a3c | ||
|
|
b9250ab82d | ||
|
|
641495b579 | ||
|
|
e6a4dfcdf2 | ||
|
|
6b505d050a | ||
|
|
fc9a21d2d1 | ||
|
|
e84e44476a | ||
|
|
b012df4c23 | ||
|
|
08e02ab730 | ||
|
|
fb090839d6 | ||
|
|
ac2d53352c | ||
|
|
35292a69fc | ||
|
|
cd16a755d7 | ||
|
|
1e7b2d3335 | ||
|
|
20d49ccf15 | ||
|
|
1f66f47ce6 | ||
|
|
34f3b9ba2a | ||
|
|
2fa7868838 | ||
|
|
b6ddda1d51 | ||
|
|
a1621f34a0 | ||
|
|
21aa3bc49f | ||
|
|
617d4f50a4 | ||
|
|
cb0ffa0c17 | ||
|
|
0615993297 | ||
|
|
1c0d91424a | ||
|
|
c94ee365ce | ||
|
|
19e5e6636f | ||
|
|
cac3a4be81 | ||
|
|
beada7f4da | ||
|
|
43b45ce6c5 | ||
|
|
95dd5e6b94 | ||
|
|
566f6ecfd5 | ||
|
|
5b28ad75b7 | ||
|
|
997857a558 | ||
|
|
4269057283 | ||
|
|
f70cab80c2 | ||
|
|
609d819610 | ||
|
|
961fbb098e | ||
|
|
42fe124b09 | ||
|
|
076b113455 | ||
|
|
c888936489 | ||
|
|
e1d2dee881 | ||
|
|
39e1f56955 | ||
|
|
4151464bdc | ||
|
|
0b89312d9d | ||
|
|
2c607dedee | ||
|
|
30e9d04f74 | ||
|
|
4b90a0659b | ||
|
|
109b7661b7 | ||
|
|
8da52a2772 | ||
|
|
7515983b55 | ||
|
|
7519ea548d | ||
|
|
6a55d9b279 | ||
|
|
d5227f1159 | ||
|
|
62e9fe69ed | ||
|
|
2df52161e5 | ||
|
|
a29f4cb1f9 | ||
|
|
6a747d2f9d | ||
|
|
164c71a3a3 | ||
|
|
3f1b0ad67b | ||
|
|
6c6699a5d6 | ||
|
|
e292b69ee5 | ||
|
|
e6e6dd4565 | ||
|
|
28bfc3e71d | ||
|
|
d3975cf461 | ||
|
|
7430c41c1e | ||
|
|
dd1064db26 | ||
|
|
1167866b16 | ||
|
|
caed8eab0c | ||
|
|
8d85334049 | ||
|
|
da89fb29ca | ||
|
|
e005621fbb | ||
|
|
511f04c6f9 | ||
|
|
fb29619b9e | ||
|
|
325adf8911 | ||
|
|
b494390373 | ||
|
|
085e95cd48 | ||
|
|
659f4e07c2 | ||
|
|
3abf6317de | ||
|
|
e8305c5886 | ||
|
|
71d029f7a0 | ||
|
|
dc899f55fe | ||
|
|
8c11f48502 | ||
|
|
e12ec697e6 | ||
|
|
b01d3a4f14 | ||
|
|
552c1a9a35 | ||
|
|
aacf720b88 | ||
|
|
832addc55e | ||
|
|
f7c5584016 | ||
|
|
df5ceb930f | ||
|
|
d4071f54f9 | ||
|
|
ae859a1ece | ||
|
|
112328a7f2 | ||
|
|
512561d8fd | ||
|
|
f73bf5a270 | ||
|
|
3c7034e46c | ||
|
|
2a848366f3 | ||
|
|
549a8ce30b | ||
|
|
d00c4aec47 | ||
|
|
4ef5b854bc | ||
|
|
41f02f34c2 | ||
|
|
b9cf52404d | ||
|
|
350e2e3907 | ||
|
|
a8b2587cee | ||
|
|
735c3cdde1 | ||
|
|
24955dc4a7 | ||
|
|
b4eb61e36a | ||
|
|
70ebb03434 | ||
|
|
2c5596cd96 | ||
|
|
d6c13337d1 | ||
|
|
eb2daf1827 | ||
|
|
c4d4bd9f40 | ||
|
|
fd1c8bf9b9 | ||
|
|
7fef4b08c0 | ||
|
|
b04c244cab | ||
|
|
cfb98ca241 | ||
|
|
885544077b | ||
|
|
fcb01c2c18 | ||
|
|
41d28b71bf | ||
|
|
8fa91a13c3 | ||
|
|
696a0ac99c | ||
|
|
37818acee1 | ||
|
|
38eae9375d | ||
|
|
c35fc543d3 | ||
|
|
2c8726dda3 | ||
|
|
83037f621c | ||
|
|
6a2c7e8740 | ||
|
|
9e8ae43b15 | ||
|
|
4ba0b36be1 | ||
|
|
9470977092 | ||
|
|
08d33fd74f | ||
|
|
66a8ec91bc | ||
|
|
b4edabb91d | ||
|
|
83ca8c344b | ||
|
|
f5e1c197dd | ||
|
|
7c5a17761e | ||
|
|
3c7289997a | ||
|
|
eb065e1984 | ||
|
|
814fa0ce33 | ||
|
|
4b0a2a12a8 | ||
|
|
321c941ce5 | ||
|
|
e653475e08 | ||
|
|
23c0949388 | ||
|
|
6349f38d57 | ||
|
|
105553c386 | ||
|
|
48a2703b99 | ||
|
|
ba3df3d9a0 | ||
|
|
b448e972e1 | ||
|
|
0537fcbd6e | ||
|
|
6c79b3385f | ||
|
|
42b63d836d | ||
|
|
b9bea7dff7 | ||
|
|
78d156395b | ||
|
|
8bcab9bf43 | ||
|
|
ef3fa92de3 | ||
|
|
50be1bbe68 | ||
|
|
4cf296c839 | ||
|
|
26d2074db6 | ||
|
|
419f67f1c7 | ||
|
|
066ee59741 | ||
|
|
001fdcceae | ||
|
|
baf1a80dc2 | ||
|
|
6a038643d6 | ||
|
|
339b9db271 | ||
|
|
6a0d8fbaa4 | ||
|
|
24b438741b | ||
|
|
25ce35fd63 | ||
|
|
8b302d715f | ||
|
|
077da3746c | ||
|
|
831fe5482a | ||
|
|
edf186f5b8 | ||
|
|
db50375141 | ||
|
|
8e6eb618dd | ||
|
|
3102577a16 | ||
|
|
24ce891c4d | ||
|
|
112da0f37d | ||
|
|
a8cb6f2061 | ||
|
|
74edd1c375 | ||
|
|
defcdf34bb | ||
|
|
f13342350d | ||
|
|
b777b34126 | ||
|
|
410dd05600 | ||
|
|
147ebb001c | ||
|
|
096bd4c99a |
4
.github/workflows/gomod2nix.yml
vendored
4
.github/workflows/gomod2nix.yml
vendored
@ -18,10 +18,12 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@master
|
uses: actions/setup-go@master
|
||||||
with:
|
with:
|
||||||
go-version: "1.20"
|
go-version: "1.25"
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: gomod2nix update
|
- name: gomod2nix update
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
42
.github/workflows/nightly-docker.yml
vendored
42
.github/workflows/nightly-docker.yml
vendored
@ -1,42 +0,0 @@
|
|||||||
name: 打包最新版为 Docker Image
|
|
||||||
|
|
||||||
on: [push]
|
|
||||||
jobs:
|
|
||||||
docker-builder:
|
|
||||||
name: build docker
|
|
||||||
runs-on: ubuntu-23.04
|
|
||||||
steps:
|
|
||||||
- name: Check out code into the Go module directory
|
|
||||||
uses: actions/checkout@master
|
|
||||||
- run: sudo apt-get install -y qemu-user-static
|
|
||||||
|
|
||||||
- name: Set up nix
|
|
||||||
uses: cachix/install-nix-action@v27
|
|
||||||
with:
|
|
||||||
nix_path: nixpkgs=channel:nixos-unstable
|
|
||||||
extra_nix_config: |
|
|
||||||
sandbox = true
|
|
||||||
|
|
||||||
- name: Speed Up nix
|
|
||||||
uses: DeterminateSystems/magic-nix-cache-action@main
|
|
||||||
|
|
||||||
- name: build docker
|
|
||||||
run: |
|
|
||||||
mkdir output/
|
|
||||||
|
|
||||||
# https://discourse.nixos.org/t/nix-github-actions-aarch64/11034
|
|
||||||
nix build .#packages.aarch64-linux.docker_builder -o aarch64-linux.docker --print-out-paths --option system aarch64-linux --extra-platforms aarch64-linux
|
|
||||||
cp $(readlink aarch64-linux.docker) ./output/aarch64-linux.docker.tar.gz
|
|
||||||
|
|
||||||
nix build .#packages.x86_64-linux.docker_builder -o x86_64-linux.docker --print-out-paths --option system x86_64-linux --extra-platforms x86_64-linux
|
|
||||||
cp $(readlink x86_64-linux.docker) ./output/x86_64-linux.docker.tar.gz
|
|
||||||
|
|
||||||
# gomod2nix did not provide this
|
|
||||||
# nix build .#packages.i686-linux.docker_builder -o i686-linux.docker --print-out-paths --option system i686-linux --extra-platforms i686-linux
|
|
||||||
# cp $(readlink i686-linux.docker) ./output/i686-linux.docker.tar.gz
|
|
||||||
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-artifact@master
|
|
||||||
if: ${{ !github.head_ref }}
|
|
||||||
with:
|
|
||||||
path: output/
|
|
||||||
5
.github/workflows/nightly.yml
vendored
5
.github/workflows/nightly.yml
vendored
@ -27,10 +27,12 @@ jobs:
|
|||||||
fail-fast: true
|
fail-fast: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
- name: Setup Go environment
|
- name: Setup Go environment
|
||||||
uses: actions/setup-go@master
|
uses: actions/setup-go@master
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.25'
|
||||||
- name: Cache downloaded module
|
- name: Cache downloaded module
|
||||||
uses: actions/cache@master
|
uses: actions/cache@master
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@ -45,6 +47,7 @@ jobs:
|
|||||||
GOARCH: ${{ matrix.goarch }}
|
GOARCH: ${{ matrix.goarch }}
|
||||||
IS_PR: ${{ !!github.head_ref }}
|
IS_PR: ${{ !!github.head_ref }}
|
||||||
run: |
|
run: |
|
||||||
|
GOOS= GOARCH= go generate ./...
|
||||||
if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi
|
if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi
|
||||||
if $IS_PR ; then echo $PR_PROMPT; fi
|
if $IS_PR ; then echo $PR_PROMPT; fi
|
||||||
export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX"
|
export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX"
|
||||||
|
|||||||
7
.github/workflows/pull.yml
vendored
7
.github/workflows/pull.yml
vendored
@ -26,15 +26,18 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@master
|
uses: actions/setup-go@master
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.24'
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Tidy Modules
|
- name: Tidy Modules
|
||||||
run: go mod tidy
|
run: |
|
||||||
|
go mod tidy
|
||||||
|
go generate main.go
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@master
|
uses: golangci/golangci-lint-action@master
|
||||||
|
|||||||
8
.github/workflows/push.yml
vendored
8
.github/workflows/push.yml
vendored
@ -8,13 +8,17 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@master
|
uses: actions/setup-go@master
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.24'
|
||||||
|
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Tidy Modules
|
- name: Tidy Modules
|
||||||
run: go mod tidy
|
run: |
|
||||||
|
go mod tidy
|
||||||
|
go generate main.go
|
||||||
|
|
||||||
- name: Run Lint
|
- name: Run Lint
|
||||||
uses: golangci/golangci-lint-action@master
|
uses: golangci/golangci-lint-action@master
|
||||||
|
|||||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -16,12 +16,12 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@master
|
uses: actions/setup-go@master
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.25'
|
||||||
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@master
|
uses: goreleaser/goreleaser-action@master
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: "~> v2"
|
||||||
args: release --clean
|
args: release --clean
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ linters:
|
|||||||
#- depguard
|
#- depguard
|
||||||
- dogsled
|
- dogsled
|
||||||
- errcheck
|
- errcheck
|
||||||
- exportloopref
|
#- exportloopref
|
||||||
- exhaustive
|
- exhaustive
|
||||||
#- funlen
|
#- funlen
|
||||||
#- goconst
|
#- goconst
|
||||||
@ -56,7 +56,7 @@ run:
|
|||||||
deadline: 5m
|
deadline: 5m
|
||||||
issues-exit-code: 1
|
issues-exit-code: 1
|
||||||
tests: false
|
tests: false
|
||||||
go: '1.20'
|
go: '1.24'
|
||||||
|
|
||||||
# output configuration options
|
# output configuration options
|
||||||
output:
|
output:
|
||||||
@ -64,12 +64,12 @@ output:
|
|||||||
- format: "colored-line-number"
|
- format: "colored-line-number"
|
||||||
print-issued-lines: true
|
print-issued-lines: true
|
||||||
print-linter-name: true
|
print-linter-name: true
|
||||||
uniq-by-line: true
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
# Fix found issues (if it's supported by the linter)
|
# Fix found issues (if it's supported by the linter)
|
||||||
fix: true
|
fix: true
|
||||||
exclude-use-default: false
|
exclude-use-default: false
|
||||||
|
uniq-by-line: true
|
||||||
exclude:
|
exclude:
|
||||||
- "Error return value of .((os.)?std(out|err)..*|.*Close|.*Seek|.*Flush|os.Remove(All)?|.*print(f|ln)?|os.(Un)?Setenv). is not check"
|
- "Error return value of .((os.)?std(out|err)..*|.*Close|.*Seek|.*Flush|os.Remove(All)?|.*print(f|ln)?|os.(Un)?Setenv). is not check"
|
||||||
- 'identifier ".*" contain non-ASCII character: U\+.*'
|
- 'identifier ".*" contain non-ASCII character: U\+.*'
|
||||||
|
|||||||
@ -4,6 +4,7 @@ env:
|
|||||||
before:
|
before:
|
||||||
hooks:
|
hooks:
|
||||||
- go mod tidy
|
- go mod tidy
|
||||||
|
- go generate ./...
|
||||||
- go install github.com/tc-hib/go-winres@latest
|
- go install github.com/tc-hib/go-winres@latest
|
||||||
- go-winres make
|
- go-winres make
|
||||||
builds:
|
builds:
|
||||||
@ -62,7 +63,7 @@ archives:
|
|||||||
name_template: "zbp_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
|
name_template: "zbp_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
|
||||||
format_overrides:
|
format_overrides:
|
||||||
- goos: windows
|
- goos: windows
|
||||||
format: zip
|
formats: zip
|
||||||
|
|
||||||
nfpms:
|
nfpms:
|
||||||
- license: AGPL 3.0
|
- license: AGPL 3.0
|
||||||
|
|||||||
228
README.md
228
README.md
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
[](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin)
|
[](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin)
|
||||||
[](https://t.me/zerobotplugin)
|
[](https://t.me/zerobotplugin)
|
||||||
[](https://github.com/wdvxdr1123/ZeroBot)
|
[](https://github.com/wdvxdr1123/ZeroBot)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -192,6 +192,18 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
|
|||||||
|
|
||||||
- [x] 早安 | 晚安
|
- [x] 早安 | 晚安
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>违禁词检测</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/antiabuse"
|
||||||
|
`
|
||||||
|
- [x] 添加违禁词
|
||||||
|
|
||||||
|
- [x] 删除违禁词
|
||||||
|
|
||||||
|
- [x] 查看违禁词
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>ATRI</summary>
|
<summary>ATRI</summary>
|
||||||
@ -256,6 +268,8 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
|
|||||||
|
|
||||||
- [x] 赞我
|
- [x] 赞我
|
||||||
|
|
||||||
|
- [x] 群签到
|
||||||
|
|
||||||
- [x] [开启 | 关闭]入群验证
|
- [x] [开启 | 关闭]入群验证
|
||||||
|
|
||||||
- [x] [开启 | 关闭]gist加群自动审批
|
- [x] [开启 | 关闭]gist加群自动审批
|
||||||
@ -276,6 +290,20 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
|
|||||||
|
|
||||||
- 设置欢迎语可选添加参数说明:{at}可在发送时艾特被欢迎者 {nickname}是被欢迎者名字 {avatar}是被欢迎者头像 {uid}是被欢迎者QQ号 {gid}是当前群群号 {groupname} 是当前群群名
|
- 设置欢迎语可选添加参数说明:{at}可在发送时艾特被欢迎者 {nickname}是被欢迎者名字 {avatar}是被欢迎者头像 {uid}是被欢迎者QQ号 {gid}是当前群群号 {groupname} 是当前群群名
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>群应用:AI声聊</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/airecord"`
|
||||||
|
|
||||||
|
- [x] 设置AI语音群号1048452984(tips:机器人任意所在群聊即可)
|
||||||
|
|
||||||
|
- [x] 设置AI语音模型
|
||||||
|
|
||||||
|
- [x] 查看AI语音配置
|
||||||
|
|
||||||
|
- [x] 发送AI语音xxx
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>定时指令触发器</summary>
|
<summary>定时指令触发器</summary>
|
||||||
@ -384,6 +412,18 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] 设置默认限速为每 m [分钟 | 秒] n 次触发
|
- [x] 设置默认限速为每 m [分钟 | 秒] n 次触发
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>aiimage</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiimage"`
|
||||||
|
|
||||||
|
- [x] 设置AI画图密钥xxx
|
||||||
|
- [x] 设置AI画图接口地址https://api.siliconflow.cn/v1/images/generations
|
||||||
|
- [x] 设置AI画图模型名Kwai-Kolors/Kolors
|
||||||
|
- [x] 查看AI画图配置
|
||||||
|
- [x] AI画图 [描述]
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>AIWife</summary>
|
<summary>AIWife</summary>
|
||||||
@ -400,6 +440,18 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] 支付宝到账 1
|
- [x] 支付宝到账 1
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>AnimeTrace 动画/Galgame识别</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/animetrace"`
|
||||||
|
|
||||||
|
基于[AnimeTrace](https://ai.animedb.cn/)API 的识图搜索插件
|
||||||
|
|
||||||
|
- [x] Gal识图 | Gal识图 [模型名]
|
||||||
|
|
||||||
|
- [x] 动漫识图 | 动漫识图 2 | 动漫识图 [模型名]
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>触发者撤回时也自动撤回</summary>
|
<summary>触发者撤回时也自动撤回</summary>
|
||||||
@ -519,7 +571,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
<details>
|
<details>
|
||||||
<summary>b站动态、专栏、视频、直播解析</summary>
|
<summary>b站动态、专栏、视频、直播解析</summary>
|
||||||
|
|
||||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"`
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibiliparse"`
|
||||||
|
|
||||||
- [x] t.bilibili.com/642277677329285174 | bilibili.com/read/cv17134450 | bilibili.com/video/BV13B4y1x7pS | live.bilibili.com/22603245
|
- [x] t.bilibili.com/642277677329285174 | bilibili.com/read/cv17134450 | bilibili.com/video/BV13B4y1x7pS | live.bilibili.com/22603245
|
||||||
|
|
||||||
@ -527,7 +579,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
<details>
|
<details>
|
||||||
<summary>b站动态、直播推送,需要配合job一起使用</summary>
|
<summary>b站动态、直播推送,需要配合job一起使用</summary>
|
||||||
|
|
||||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"`
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibilipush"`
|
||||||
|
|
||||||
- [x] 添加b站订阅[uid|name]
|
- [x] 添加b站订阅[uid|name]
|
||||||
|
|
||||||
@ -593,6 +645,17 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] 磕cp大老师 雪乃
|
- [x] 磕cp大老师 雪乃
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>奇怪语言加解密</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/crypter"`
|
||||||
|
|
||||||
|
- [x] 齁语加密 [文本] 或 h加密 [文本]
|
||||||
|
- [x] 齁语解密 [密文] 或 h解密 [密文]
|
||||||
|
- [x] fumo加密 [文本]
|
||||||
|
- [x] fumo解密 [文本]
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>今日早报</summary>
|
<summary>今日早报</summary>
|
||||||
@ -667,6 +730,16 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] [emoji][emoji]
|
- [x] [emoji][emoji]
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>颜文字抽象转写</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/emozi"`
|
||||||
|
|
||||||
|
- [x] 抽象转写[文段]
|
||||||
|
- [x] 抽象还原[文段]
|
||||||
|
- [x] 抽象登录[用户名]
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>好友申请及群聊邀请事件处理</summary>
|
<summary>好友申请及群聊邀请事件处理</summary>
|
||||||
@ -941,12 +1014,26 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>日韩 VITS 模型拟声</summary>
|
<summary>Minecraft服务器监控&订阅</summary>
|
||||||
|
|
||||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/moegoe"`
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/minecraftobserver"`
|
||||||
|
|
||||||
- [x] 让[派蒙|空|荧|阿贝多|枫原万叶|温迪|八重神子|纳西妲|钟离|诺艾尔|凝光|托马|北斗|莫娜|荒泷一斗|提纳里|芭芭拉|艾尔海森|雷电将军|赛诺|琴|班尼特|五郎|神里绫华|迪希雅|夜兰|辛焱|安柏|宵宫|云堇|妮露|烟绯|鹿野院平藏|凯亚|达达利亚|迪卢克|可莉|早柚|香菱|重云|刻晴|久岐忍|珊瑚宫心海|迪奥娜|戴因斯雷布|魈|神里绫人|丽莎|优菈|凯瑟琳|雷泽|菲谢尔|九条裟罗|甘雨|行秋|胡桃|迪娜泽黛|柯莱|申鹤|砂糖|萍姥姥|奥兹|罗莎莉亚|式大将|哲平|坎蒂丝|托克|留云借风真君|昆钧|塞琉斯|多莉|大肉丸|莱依拉|散兵|拉赫曼|杜拉夫|阿守|玛乔丽|纳比尔|海芭夏|九条镰治|阿娜耶|阿晃|阿扎尔|七七|博士|白术|埃洛伊|大慈树王|女士|丽塔|失落迷迭|缭乱星棘|伊甸|伏特加女孩|狂热蓝调|莉莉娅|萝莎莉娅|八重樱|八重霞|卡莲|第六夜想曲|卡萝尔|姬子|极地战刃|布洛妮娅|次生银翼|理之律者|迷城骇兔|希儿|魇夜星渊|黑希儿|帕朵菲莉丝|天元骑英|幽兰黛尔|德丽莎|月下初拥|朔夜观星|暮光骑士|明日香|李素裳|格蕾修|梅比乌斯|渡鸦|人之律者|爱莉希雅|爱衣|天穹游侠|琪亚娜|空之律者|薪炎之律者|云墨丹心|符华|识之律者|维尔薇|芽衣|雷之律者|阿波尼亚]说(中文)
|
- [x] mc服务器状态 [服务器IP/URI]
|
||||||
|
- [x] mc服务器添加订阅 [服务器IP/URI]
|
||||||
|
- [x] mc服务器取消订阅 [服务器IP/URI]
|
||||||
|
- [x] mc服务器订阅拉取 (需要插件定时任务配合使用,全局只需要设置一个)
|
||||||
|
- 使用job插件设置定时, 对话例子如下::
|
||||||
|
- 记录在"@every 1m"触发的指令
|
||||||
|
- (机器人回答:您的下一条指令将被记录,在@@every 1m时触发)
|
||||||
|
- mc服务器订阅拉取
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>Movies猫眼电影查询</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/movies"`
|
||||||
|
|
||||||
|
- [x] 今日电影
|
||||||
|
- [x] 预售电影
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>摸鱼</summary>
|
<summary>摸鱼</summary>
|
||||||
@ -991,6 +1078,10 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] 酷狗点歌[xxx]
|
- [x] 酷狗点歌[xxx]
|
||||||
|
|
||||||
|
- [x] qq点歌[xxx]
|
||||||
|
|
||||||
|
- [x] 咪咕点歌[xxx]
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>本地涩图</summary>
|
<summary>本地涩图</summary>
|
||||||
@ -1043,6 +1134,10 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] 赎牛牛
|
- [x] 赎牛牛
|
||||||
|
|
||||||
|
- [x] 牛牛拍卖行
|
||||||
|
|
||||||
|
- [x] 出售牛牛
|
||||||
|
|
||||||
- [x] 牛牛商店
|
- [x] 牛牛商店
|
||||||
|
|
||||||
- [x] 牛牛背包
|
- [x] 牛牛背包
|
||||||
@ -1189,6 +1284,17 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] 打劫[对方Q号|@对方QQ]
|
- [x] 打劫[对方Q号|@对方QQ]
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>RSSHub</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/rsshub"`
|
||||||
|
|
||||||
|
- [x] 添加rsshub订阅-/bookfere/weekly
|
||||||
|
- [x] 删除rsshub订阅-/bookfere/weekly
|
||||||
|
- [x] 查看rsshub订阅列表
|
||||||
|
- [x] rsshub同步 (使用job执行定时任务------记录在"@every 10m"触发的指令)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>在线代码运行</summary>
|
<summary>在线代码运行</summary>
|
||||||
@ -1309,14 +1415,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] >TL 你好
|
- [x] >TL 你好
|
||||||
|
|
||||||
</details>
|
|
||||||
<details>
|
|
||||||
<summary>vits猫雷</summary>
|
|
||||||
|
|
||||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru"`
|
|
||||||
|
|
||||||
- [x] 让猫雷说[xxxx]
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>vtb语录</summary>
|
<summary>vtb语录</summary>
|
||||||
@ -1375,50 +1473,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
- [x] 每日特惠
|
- [x] 每日特惠
|
||||||
</details>
|
</details>
|
||||||
<details>
|
|
||||||
<summary>百度文心AI</summary>
|
|
||||||
|
|
||||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinAI"`
|
|
||||||
|
|
||||||
基于百度文心API的一些功能
|
|
||||||
|
|
||||||
key申请链接:https://wenxin.baidu.com/moduleApi/key
|
|
||||||
|
|
||||||
- [x] 为[自己/本群/QQ号/群+群号]设置文心key [API Key] [Secret Key]
|
|
||||||
|
|
||||||
- [x] 为[自己/本群/QQ号/群+群号]设置画图key [API Key] [Secret Key]
|
|
||||||
|
|
||||||
例:“为10086设置画图key 123 456”;“为群10010设置画图key 789 101”
|
|
||||||
|
|
||||||
文心key和画图key的API key 可以是相同的,只是文心key日限为200,画图日限为50,以此作区别。
|
|
||||||
|
|
||||||
- [x] 文心作文 (x字的)[作文题目]
|
|
||||||
|
|
||||||
- [x] 文心提案 (x字的)[文案标题]
|
|
||||||
|
|
||||||
- [x] 文心摘要 (x字的)[文章内容]
|
|
||||||
|
|
||||||
- [x] 文心小说 (x字的)[小说上文]
|
|
||||||
|
|
||||||
- [x] 文心对联 [上联]
|
|
||||||
|
|
||||||
- [x] 文心问答 [问题]
|
|
||||||
|
|
||||||
- [x] 文心补全 [带“_”的填空题]
|
|
||||||
|
|
||||||
- [x] 文心自定义 [prompt]
|
|
||||||
|
|
||||||
- [x] [bot名称]画几张[图片描述]的[图片类型][图片尺寸]
|
|
||||||
|
|
||||||
指令示例:
|
|
||||||
|
|
||||||
- 文心作文 我的椛椛机器人
|
|
||||||
|
|
||||||
- 文心作文 300字的我的椛椛机器人
|
|
||||||
|
|
||||||
- 椛椛帮我画几张金凤凰,背景绚烂,高饱和,古风,仙境,高清,4K,古风的油画方图
|
|
||||||
|
|
||||||
</details>
|
|
||||||
<details>
|
<details>
|
||||||
<summary>抽老婆</summary>
|
<summary>抽老婆</summary>
|
||||||
|
|
||||||
@ -1432,7 +1486,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count"`
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count"`
|
||||||
|
|
||||||
- [x] 热词 [群号] [消息数目]|热词 123456 1000
|
- [x] 热词 [消息数目]|热词 1000
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
@ -1462,21 +1516,21 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>一些游戏王插件</summary>
|
<summary>游戏王白鸽API卡查</summary>
|
||||||
|
|
||||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygo"`
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygocdb"`
|
||||||
|
|
||||||
##### 白鸽API卡查
|
|
||||||
|
|
||||||
###### `"github.com/FloatTech/ZeroBot-Plugin/plugin/ygo/ygocdb.go"`
|
|
||||||
- [x] /ydp [xxx]
|
- [x] /ydp [xxx]
|
||||||
- [x] /yds [xxx]
|
- [x] /yds [xxx]
|
||||||
- [x] /ydb [xxx]
|
- [x] /ydb [xxx]
|
||||||
- 注:[xxx]为搜索内容;p:返回一张图片;s:返回一张效果描述;b:高级搜索
|
- 注:[xxx]为搜索内容;p:返回一张图片;s:返回一张效果描述;b:高级搜索
|
||||||
|
|
||||||
##### 集换社卡价查询
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>游戏王集换社卡价查询</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygotrade"`
|
||||||
|
|
||||||
###### `"github.com/FloatTech/ZeroBot-Plugin/plugin/ygo/ygotrade.go"`
|
|
||||||
- [x] 查卡价 [卡名]
|
- [x] 查卡价 [卡名]
|
||||||
- [x] 查卡价 [卡名] -r [稀有度 稀有度 ...]
|
- [x] 查卡价 [卡名] -r [稀有度 稀有度 ...]
|
||||||
- [x] 查卡店 [卡名]
|
- [x] 查卡店 [卡名]
|
||||||
@ -1539,6 +1593,33 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
### *低优先级*
|
### *低优先级*
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>OpenAI聊天</summary>
|
||||||
|
|
||||||
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aichat"`
|
||||||
|
|
||||||
|
- [x] 设置AI聊天触发概率10
|
||||||
|
- [x] 设置AI聊天温度80
|
||||||
|
- [x] 设置AI聊天(识图|Agent)接口类型[OpenAI|OLLaMA|GenAI]
|
||||||
|
- [x] 设置AI聊天(不)使用Agent模式
|
||||||
|
- [x] 设置AI聊天(不)支持系统提示词
|
||||||
|
- [x] 设置AI聊天(识图|Agent)接口地址https://api.siliconflow.cn/v1/chat/completions
|
||||||
|
- [x] 设置AI聊天(识图|Agent)密钥xxx
|
||||||
|
- [x] 设置AI聊天(识图|Agent)模型名Qwen/Qwen3-8B
|
||||||
|
- [x] 查看AI聊天系统提示词
|
||||||
|
- [x] 重置AI聊天系统提示词
|
||||||
|
- [x] 设置AI聊天系统提示词xxx
|
||||||
|
- [x] 设置AI聊天分隔符`</think>`(留空则清除)
|
||||||
|
- [x] 设置AI聊天(不)响应AT
|
||||||
|
- [x] 设置AI聊天最大长度4096
|
||||||
|
- [x] 设置AI聊天TopP 0.9
|
||||||
|
- [x] 设置AI聊天(不)以AI语音输出
|
||||||
|
- [x] 查看AI聊天配置
|
||||||
|
- [x] 重置AI聊天
|
||||||
|
- [x] 群聊总结 [消息数目]|群聊总结 1000
|
||||||
|
- [x] /gpt [内容](使用大模型聊天)
|
||||||
|
|
||||||
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>骂人</summary>
|
<summary>骂人</summary>
|
||||||
|
|
||||||
@ -1550,19 +1631,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>人工智能回复</summary>
|
<summary>词典匹配回复, 仅@触发</summary>
|
||||||
|
|
||||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aireply"`
|
|
||||||
|
|
||||||
- [x] @Bot 任意文本(任意一句话回复)
|
|
||||||
|
|
||||||
- [x] 设置文字回复模式[婧枫|沫沫|青云客|小爱|ChatGPT]
|
|
||||||
|
|
||||||
- [x] 设置 ChatGPT api key xxx
|
|
||||||
|
|
||||||
</details>
|
|
||||||
<details>
|
|
||||||
<summary>词典匹配回复</summary>
|
|
||||||
|
|
||||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus"`
|
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus"`
|
||||||
|
|
||||||
@ -1616,6 +1685,7 @@ go version
|
|||||||
go env -w GOPROXY=https://goproxy.cn,direct
|
go env -w GOPROXY=https://goproxy.cn,direct
|
||||||
go env -w GO111MODULE=auto
|
go env -w GO111MODULE=auto
|
||||||
go mod tidy
|
go mod tidy
|
||||||
|
go generate main.go
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 编辑 main.go 文件,内容按需修改
|
3. 编辑 main.go 文件,内容按需修改
|
||||||
|
|||||||
164
abineundo/main.go
Normal file
164
abineundo/main.go
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// Package abineundo provides an explicit "from the beginning" (Latin: "ab ineundō")
|
||||||
|
// initialization anchor.
|
||||||
|
//
|
||||||
|
// Name origin:
|
||||||
|
//
|
||||||
|
// Latin phrase "ab ineundō" meaning "from which is to be begun".
|
||||||
|
//
|
||||||
|
// Purpose:
|
||||||
|
//
|
||||||
|
// Place this package at the very top of top-level main.go so its init (present
|
||||||
|
// or future) executes before other plugin packages, filling in a predictable
|
||||||
|
// plugin priority.
|
||||||
|
//
|
||||||
|
// Typical usage:
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// _ "github.com/your/module/abineundo" // priority anchor
|
||||||
|
// // ... other imports ...
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// A blank identifier import preserves ordering side-effects without expanding the
|
||||||
|
// exported API surface.
|
||||||
|
//
|
||||||
|
// (No further code is required here; the package's presence alone defines ordering semantics.)
|
||||||
|
package abineundo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
_ "embed"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/FloatTech/zbputils/control"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed ref/main/main.go
|
||||||
|
var maincode string
|
||||||
|
|
||||||
|
//go:embed ref/custom/register.go
|
||||||
|
var customcode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
statusnone = iota
|
||||||
|
statushigh
|
||||||
|
statushighend
|
||||||
|
statusmid
|
||||||
|
statusmidend
|
||||||
|
statuslow
|
||||||
|
statuslowend
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
priore = regexp.MustCompile(`^\t// -{28}(高|中|低)优先级区-{28} //$`)
|
||||||
|
mainpluginre = regexp.MustCompile(`^\t_ "github\.com/FloatTech/ZeroBot-Plugin/plugin/(\w+)"\s+// `)
|
||||||
|
custpluginre = regexp.MustCompile(`^\t_ "github\.com/FloatTech/ZeroBot-Plugin/custom/plugin/(\w+)"\s+// `)
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
highprios := make([]string, 0, 64)
|
||||||
|
midprios := make([]string, 0, 64)
|
||||||
|
lowprios := make([]string, 0, 64)
|
||||||
|
|
||||||
|
status := statusnone
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(maincode))
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
|
prioword := ""
|
||||||
|
match := priore.FindStringSubmatch(line)
|
||||||
|
if len(match) > 1 {
|
||||||
|
prioword = match[1]
|
||||||
|
}
|
||||||
|
switch prioword {
|
||||||
|
case "高":
|
||||||
|
switch status {
|
||||||
|
case statusnone:
|
||||||
|
status = statushigh
|
||||||
|
case statushigh:
|
||||||
|
status = statushighend
|
||||||
|
default:
|
||||||
|
panic("unexpected")
|
||||||
|
}
|
||||||
|
case "中":
|
||||||
|
switch status {
|
||||||
|
case statushighend:
|
||||||
|
status = statusmid
|
||||||
|
case statusmid:
|
||||||
|
status = statusmidend
|
||||||
|
default:
|
||||||
|
panic("unexpected")
|
||||||
|
}
|
||||||
|
case "低":
|
||||||
|
switch status {
|
||||||
|
case statusmidend:
|
||||||
|
status = statuslow
|
||||||
|
case statuslow:
|
||||||
|
status = statuslowend
|
||||||
|
default:
|
||||||
|
panic("unexpected")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
switch status {
|
||||||
|
case statusnone: // 还未开始匹配
|
||||||
|
continue
|
||||||
|
case statuslowend: // 匹配已结束
|
||||||
|
break
|
||||||
|
default: // 继续匹配插件
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在对应优先级区域内匹配插件
|
||||||
|
if matches := mainpluginre.FindStringSubmatch(line); len(matches) > 1 {
|
||||||
|
name := matches[1]
|
||||||
|
switch status {
|
||||||
|
case statushigh:
|
||||||
|
highprios = append(highprios, name)
|
||||||
|
case statusmid:
|
||||||
|
midprios = append(midprios, name)
|
||||||
|
case statuslow:
|
||||||
|
lowprios = append(lowprios, name)
|
||||||
|
default: // 在不该匹配到插件的区域匹配到
|
||||||
|
panic("unexpected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
custprios := make([]string, 0, 64)
|
||||||
|
|
||||||
|
scanner = bufio.NewScanner(strings.NewReader(customcode))
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
|
if matches := custpluginre.FindStringSubmatch(line); len(matches) > 1 {
|
||||||
|
custprios = append(custprios, matches[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成最终插件优先级表
|
||||||
|
m := make(map[string]uint64, 4*(len(highprios)+len(midprios)+len(lowprios)+len(custprios)))
|
||||||
|
i := 0
|
||||||
|
for _, name := range highprios {
|
||||||
|
m[name] = (uint64(i) + 1) * 10
|
||||||
|
logrus.Debugln("[ab] set high plugin", name, "prio to", m[name])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for _, name := range custprios {
|
||||||
|
m[name] = (uint64(i) + 1) * 10
|
||||||
|
logrus.Debugln("[ab] set cust plugin", name, "prio to", m[name])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for _, name := range midprios {
|
||||||
|
m[name] = (uint64(i) + 1) * 10
|
||||||
|
logrus.Debugln("[ab] set mid plugin", name, "prio to", m[name])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for _, name := range lowprios {
|
||||||
|
m[name] = (uint64(i) + 1) * 10
|
||||||
|
logrus.Debugln("[ab] set low plugin", name, "prio to", m[name])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
control.LoadCustomPriority(m)
|
||||||
|
}
|
||||||
2
abineundo/ref/custom/.gitignore
vendored
Normal file
2
abineundo/ref/custom/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
!.gitignore
|
||||||
|
*
|
||||||
54
abineundo/ref/main.go
Normal file
54
abineundo/ref/main.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Package main generate necessary files that needed for compiling
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
root := flag.String("r", "", "project root dir")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
fi, err := os.Open(path.Join(*root, "main.go"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fo, err := os.Create(path.Join(*root, "abineundo/ref/main/main.go"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(fo, fi)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fi.Close()
|
||||||
|
fo.Close()
|
||||||
|
|
||||||
|
regf := path.Join(*root, "custom/register.go")
|
||||||
|
tgtf := path.Join(*root, "abineundo/ref/custom/register.go")
|
||||||
|
if _, err := os.Stat(regf); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
_ = os.WriteFile(tgtf, []byte("// Package custom ...\npackage custom\n"), 0644)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err = os.Open(regf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fo, err = os.Create(tgtf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(fo, fi)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fi.Close()
|
||||||
|
fo.Close()
|
||||||
|
}
|
||||||
2
abineundo/ref/main/.gitignore
vendored
Normal file
2
abineundo/ref/main/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
!.gitignore
|
||||||
|
*
|
||||||
@ -38,12 +38,18 @@ func setConsoleTitle(title string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
debugMode := os.Getenv("DEBUG_MODE") == "1"
|
||||||
stdin := windows.Handle(os.Stdin.Fd())
|
stdin := windows.Handle(os.Stdin.Fd())
|
||||||
|
|
||||||
var mode uint32
|
var mode uint32
|
||||||
err := windows.GetConsoleMode(stdin, &mode)
|
err := windows.GetConsoleMode(stdin, &mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
if debugMode {
|
||||||
|
logrus.Warnf("调试模式下忽略控制台模式获取失败: %v", err)
|
||||||
|
return // 调试模式下直接返回,跳过后续配置
|
||||||
|
} else {
|
||||||
|
panic(err) // 非调试模式下 panic
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mode &^= windows.ENABLE_QUICK_EDIT_MODE // 禁用快速编辑模式
|
mode &^= windows.ENABLE_QUICK_EDIT_MODE // 禁用快速编辑模式
|
||||||
|
|||||||
4
custom/.gitignore
vendored
Normal file
4
custom/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
!.gitignore
|
||||||
|
!doc.go
|
||||||
|
!plugin
|
||||||
|
*
|
||||||
2
custom/doc.go
Normal file
2
custom/doc.go
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// Package custom 注册用户自定义插件于此
|
||||||
|
package custom
|
||||||
2
custom/plugin/.gitignore
vendored
Normal file
2
custom/plugin/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
!.gitignore
|
||||||
|
*
|
||||||
2
data
2
data
@ -1 +1 @@
|
|||||||
Subproject commit f1f8cd107cacaf8d8e358d7468f7c9b25adf637a
|
Subproject commit 1b0abcd3fe4943fa3298885cf0311e8d94a02c0b
|
||||||
@ -11,6 +11,7 @@
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
buildGoApplication ? pkgs.buildGoApplication,
|
buildGoApplication ? pkgs.buildGoApplication,
|
||||||
|
...
|
||||||
}:
|
}:
|
||||||
buildGoApplication {
|
buildGoApplication {
|
||||||
pname = "ZeroBot-Plugin";
|
pname = "ZeroBot-Plugin";
|
||||||
|
|||||||
37
flake.lock
37
flake.lock
@ -5,11 +5,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1705309234,
|
"lastModified": 1731533236,
|
||||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -28,11 +28,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1705314449,
|
"lastModified": 1742209644,
|
||||||
"narHash": "sha256-yfQQ67dLejP0FLK76LKHbkzcQqNIrux6MFe32MMFGNQ=",
|
"narHash": "sha256-jMy1XqXqD0/tJprEbUmKilTkvbDY/C0ZGSsJJH4TNCE=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "gomod2nix",
|
"repo": "gomod2nix",
|
||||||
"rev": "30e3c3a9ec4ac8453282ca7f67fca9e1da12c3e6",
|
"rev": "8f3534eb8f6c5c3fce799376dc3b91bae6b11884",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -43,11 +43,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1705856552,
|
"lastModified": 1745391562,
|
||||||
"narHash": "sha256-JXfnuEf5Yd6bhMs/uvM67/joxYKoysyE3M2k6T3eWbg=",
|
"narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "612f97239e2cc474c13c9dafa0df378058c5ad8d",
|
"rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -57,11 +57,28 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs-with-go_1_20": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710843028,
|
||||||
|
"narHash": "sha256-CMbK45c4nSkGvayiEHFkGFH+doGPbgo3AWfecd2t1Fk=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "33c51330782cb486764eb598d5907b43dc87b4c2",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "33c51330782cb486764eb598d5907b43dc87b4c2",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"gomod2nix": "gomod2nix",
|
"gomod2nix": "gomod2nix",
|
||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs",
|
||||||
|
"nixpkgs-with-go_1_20": "nixpkgs-with-go_1_20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
|
|||||||
24
flake.nix
24
flake.nix
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
description = "基于 ZeroBot 的 OneBot 插件";
|
description = "基于 ZeroBot 的 OneBot 插件";
|
||||||
|
|
||||||
|
inputs.nixpkgs-with-go_1_20.url = "github:NixOS/nixpkgs/33c51330782cb486764eb598d5907b43dc87b4c2";
|
||||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||||
inputs.gomod2nix.url = "github:nix-community/gomod2nix";
|
inputs.gomod2nix.url = "github:nix-community/gomod2nix";
|
||||||
@ -10,14 +11,25 @@
|
|||||||
outputs = {
|
outputs = {
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
|
nixpkgs-with-go_1_20,
|
||||||
flake-utils,
|
flake-utils,
|
||||||
gomod2nix,
|
gomod2nix,
|
||||||
}: let
|
...
|
||||||
|
} @ inputs: let
|
||||||
allSystems = flake-utils.lib.allSystems;
|
allSystems = flake-utils.lib.allSystems;
|
||||||
in (
|
in (
|
||||||
flake-utils.lib.eachSystem allSystems
|
flake-utils.lib.eachSystem allSystems
|
||||||
(system: let
|
(system: let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
old-nixpkgs = nixpkgs-with-go_1_20.legacyPackages.${system};
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
|
||||||
|
overlays = [
|
||||||
|
(_: _: {
|
||||||
|
go_1_20 = old-nixpkgs.go_1_20;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
# The current default sdk for macOS fails to compile go projects, so we use a newer one for now.
|
# The current default sdk for macOS fails to compile go projects, so we use a newer one for now.
|
||||||
# This has no effect on other platforms.
|
# This has no effect on other platforms.
|
||||||
@ -25,11 +37,10 @@
|
|||||||
in {
|
in {
|
||||||
# doCheck will fail at write files
|
# doCheck will fail at write files
|
||||||
packages = rec {
|
packages = rec {
|
||||||
|
ZeroBot-Plugin = (callPackage ./. (inputs
|
||||||
ZeroBot-Plugin =
|
// {
|
||||||
(callPackage ./. {
|
|
||||||
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
|
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
|
||||||
})
|
}))
|
||||||
.overrideAttrs (_: {doCheck = false;});
|
.overrideAttrs (_: {doCheck = false;});
|
||||||
|
|
||||||
default = ZeroBot-Plugin;
|
default = ZeroBot-Plugin;
|
||||||
@ -42,7 +53,6 @@
|
|||||||
pkgs.cacert
|
pkgs.cacert
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
devShells.default = callPackage ./shell.nix {
|
devShells.default = callPackage ./shell.nix {
|
||||||
inherit (gomod2nix.legacyPackages.${system}) mkGoEnv gomod2nix;
|
inherit (gomod2nix.legacyPackages.${system}) mkGoEnv gomod2nix;
|
||||||
|
|||||||
110
go.mod
110
go.mod
@ -1,99 +1,105 @@
|
|||||||
module github.com/FloatTech/ZeroBot-Plugin
|
module github.com/FloatTech/ZeroBot-Plugin
|
||||||
|
|
||||||
go 1.20
|
go 1.24.2
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Baidu-AIP/golang-sdk v1.1.1
|
github.com/Baidu-AIP/golang-sdk v1.1.1
|
||||||
github.com/FloatTech/AnimeAPI v1.7.1-0.20240826120833-9bf54389aadb
|
github.com/FloatTech/AnimeAPI v1.7.1-0.20251028071248-0c948e3db65c
|
||||||
github.com/FloatTech/floatbox v0.0.0-20240505082030-226ec6713e14
|
github.com/FloatTech/floatbox v0.0.0-20251002074805-f95cbc7edb31
|
||||||
github.com/FloatTech/gg v1.1.3
|
github.com/FloatTech/gg v1.1.3
|
||||||
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef
|
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef
|
||||||
github.com/FloatTech/rendercard v0.1.1
|
github.com/FloatTech/rendercard v0.2.0
|
||||||
github.com/FloatTech/sqlite v1.6.3
|
github.com/FloatTech/sqlite v1.7.2
|
||||||
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562
|
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d
|
||||||
github.com/FloatTech/zbpctrl v1.6.2-0.20240904160347-1317e11a15bb
|
github.com/FloatTech/zbpctrl v1.7.0
|
||||||
github.com/FloatTech/zbputils v1.7.2-0.20240822065525-5ea6811ed91c
|
github.com/FloatTech/zbputils v1.7.2-0.20251002080916-b554b7039913
|
||||||
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7
|
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7
|
||||||
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5
|
github.com/RomiChan/websocket v1.4.3-0.20251002072000-d3eb41798438
|
||||||
github.com/antchfx/htmlquery v1.3.1
|
github.com/Tnze/go-mc v1.20.2
|
||||||
|
github.com/antchfx/htmlquery v1.3.4
|
||||||
github.com/corona10/goimagehash v1.1.0
|
github.com/corona10/goimagehash v1.1.0
|
||||||
github.com/davidscholberg/go-durationfmt v0.0.0-20170122144659-64843a2083d3
|
github.com/davidscholberg/go-durationfmt v0.0.0-20170122144659-64843a2083d3
|
||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/fumiama/ahsai v0.1.0
|
github.com/fumiama/ahsai v0.1.1
|
||||||
github.com/fumiama/cron v1.3.0
|
github.com/fumiama/cron v1.3.0
|
||||||
|
github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa
|
||||||
github.com/fumiama/go-base16384 v1.7.0
|
github.com/fumiama/go-base16384 v1.7.0
|
||||||
|
github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8
|
||||||
github.com/fumiama/go-registry v0.2.7
|
github.com/fumiama/go-registry v0.2.7
|
||||||
github.com/fumiama/gotracemoe v0.0.3
|
github.com/fumiama/gotracemoe v0.0.3
|
||||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565
|
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565
|
||||||
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4
|
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4
|
||||||
github.com/fumiama/terasu v0.0.0-20240507144117-547a591149c0
|
github.com/fumiama/terasu v1.0.1
|
||||||
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6
|
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
github.com/jinzhu/gorm v1.9.16
|
github.com/jinzhu/gorm v1.9.16
|
||||||
github.com/jozsefsallai/gophersauce v1.0.1
|
github.com/jozsefsallai/gophersauce v1.0.1
|
||||||
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5
|
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5
|
||||||
github.com/lithammer/fuzzysearch v1.1.8
|
github.com/lithammer/fuzzysearch v1.1.8
|
||||||
github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5
|
github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5
|
||||||
|
github.com/mmcdole/gofeed v1.3.0
|
||||||
github.com/mroth/weightedrand v1.0.0
|
github.com/mroth/weightedrand v1.0.0
|
||||||
github.com/notnil/chess v1.9.0
|
github.com/notnil/chess v1.10.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/shirou/gopsutil/v3 v3.24.4
|
github.com/shirou/gopsutil/v4 v4.25.11
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/tidwall/gjson v1.17.3
|
github.com/tidwall/gjson v1.18.0
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.1
|
github.com/wcharczuk/go-chart/v2 v2.1.2
|
||||||
github.com/wdvxdr1123/ZeroBot v1.7.5-0.20240829093431-bea5257d1a2b
|
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20251002074418-56567b7fc282
|
||||||
gitlab.com/gomidi/midi/v2 v2.1.7
|
gitlab.com/gomidi/midi/v2 v2.3.16
|
||||||
golang.org/x/image v0.16.0
|
golang.org/x/image v0.32.0
|
||||||
golang.org/x/sys v0.20.0
|
golang.org/x/sys v0.38.0
|
||||||
golang.org/x/text v0.15.0
|
golang.org/x/text v0.30.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/PuerkitoBio/goquery v1.10.3 // indirect
|
||||||
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
|
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
|
||||||
github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca // indirect
|
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect
|
||||||
github.com/antchfx/xpath v1.3.0 // indirect
|
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||||
github.com/blend/go-sdk v1.20220411.3 // indirect
|
github.com/antchfx/xpath v1.3.5 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
github.com/ebitengine/oto/v3 v3.4.0 // indirect
|
||||||
|
github.com/ebitengine/purego v0.9.1 // indirect
|
||||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 // indirect
|
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 // indirect
|
||||||
github.com/faiface/beep v1.1.0 // indirect
|
|
||||||
github.com/fumiama/go-simple-protobuf v0.2.0 // indirect
|
github.com/fumiama/go-simple-protobuf v0.2.0 // indirect
|
||||||
github.com/fumiama/gofastTEA v0.0.10 // indirect
|
github.com/fumiama/gofastTEA v0.1.3 // indirect
|
||||||
github.com/fumiama/imgsz v0.0.4 // indirect
|
github.com/fumiama/imgsz v0.0.4 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.0.4 // indirect
|
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5 // indirect
|
||||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||||
github.com/hajimehoshi/oto v0.7.1 // indirect
|
github.com/gopxl/beep/v2 v2.1.1 // indirect
|
||||||
github.com/jfreymuth/oggvorbis v1.0.1 // indirect
|
github.com/jfreymuth/oggvorbis v1.0.5 // indirect
|
||||||
github.com/jfreymuth/vorbis v1.0.0 // indirect
|
github.com/jfreymuth/vorbis v1.0.2 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
|
github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
|
||||||
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d // indirect
|
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d // indirect
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/mmcdole/goxpp v1.1.1 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||||
github.com/pkumza/numcn v1.0.0 // indirect
|
github.com/pkumza/numcn v1.0.0 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
github.com/tidwall/match v1.2.0 // indirect
|
||||||
github.com/tetratelabs/wazero v1.5.0 // indirect
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tklauser/go-sysconf v0.3.16 // indirect
|
||||||
github.com/tidwall/pretty v1.2.0 // indirect
|
github.com/tklauser/numcpus v0.11.0 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 // indirect
|
golang.org/x/net v0.46.0 // indirect
|
||||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
golang.org/x/net v0.24.0 // indirect
|
modernc.org/libc v1.66.10 // indirect
|
||||||
modernc.org/libc v1.49.3 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/mathutil v1.6.0 // indirect
|
modernc.org/memory v1.11.0 // indirect
|
||||||
modernc.org/memory v1.8.0 // indirect
|
modernc.org/sqlite v1.39.1 // indirect
|
||||||
modernc.org/sqlite v1.20.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
||||||
replace modernc.org/sqlite => github.com/fumiama/sqlite3 v1.29.10-simp
|
replace modernc.org/sqlite => github.com/fumiama/sqlite3 v1.29.10-simp
|
||||||
|
|||||||
315
go.sum
315
go.sum
@ -1,44 +1,50 @@
|
|||||||
github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhvrx4cw=
|
github.com/Baidu-AIP/golang-sdk v1.1.1 h1:RQsAmgDSAkiq22I6n7XJ2t3afgzFeqjY46FGhvrx4cw=
|
||||||
github.com/Baidu-AIP/golang-sdk v1.1.1/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y=
|
github.com/Baidu-AIP/golang-sdk v1.1.1/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/FloatTech/AnimeAPI v1.7.1-0.20240826120833-9bf54389aadb h1:j7m84zwcDWLoMLjgG4MDnvanGQoDNnG8A7/aNCnYMIk=
|
github.com/FloatTech/AnimeAPI v1.7.1-0.20251028071248-0c948e3db65c h1:fmvlRUzwoK6KdoRSW+XeTQ9myKHimd0pV6GbmRJLNRo=
|
||||||
github.com/FloatTech/AnimeAPI v1.7.1-0.20240826120833-9bf54389aadb/go.mod h1:Ru6q5pZUnfMg1iu0M1Hp73q9N3LNIbDr16kjkzyG6Xk=
|
github.com/FloatTech/AnimeAPI v1.7.1-0.20251028071248-0c948e3db65c/go.mod h1:cuDd67B23xmICSmFBhWzXN51blod2BlM1liN9Ux0pSc=
|
||||||
github.com/FloatTech/floatbox v0.0.0-20240505082030-226ec6713e14 h1:8O0Iq9MnKsKowltY9txhOqcJdmGTjxHPQ4gEYzbJc9A=
|
github.com/FloatTech/floatbox v0.0.0-20251002074805-f95cbc7edb31 h1:2K+/M64ixD1Pg5hr00Nbxr7GoWQOgahvpmp1pAMnrYc=
|
||||||
github.com/FloatTech/floatbox v0.0.0-20240505082030-226ec6713e14/go.mod h1:OzGLhvmtz1TKIdGaJDd8pQumvD36UqK+dWsiCISmzQQ=
|
github.com/FloatTech/floatbox v0.0.0-20251002074805-f95cbc7edb31/go.mod h1:kf+Ywc2lk8PLdg3RX0vrUmFLPO6k+23MFmt4GviV8C0=
|
||||||
github.com/FloatTech/gg v1.1.3 h1:+GlL02lTKsxJQr4WCuNwVxC1/eBZrCvypCIBtxuOFb4=
|
github.com/FloatTech/gg v1.1.3 h1:+GlL02lTKsxJQr4WCuNwVxC1/eBZrCvypCIBtxuOFb4=
|
||||||
github.com/FloatTech/gg v1.1.3/go.mod h1:/9oLP54CMfq4r+71XL26uaFTJ1uL1boAyX67680/1HE=
|
github.com/FloatTech/gg v1.1.3/go.mod h1:/9oLP54CMfq4r+71XL26uaFTJ1uL1boAyX67680/1HE=
|
||||||
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef h1:CJbK/2FRwPuZpeb6M4sWK2d7oXDnBEGhpkQuQrgc91A=
|
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef h1:CJbK/2FRwPuZpeb6M4sWK2d7oXDnBEGhpkQuQrgc91A=
|
||||||
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef/go.mod h1:el5hGpj1C1bDRxcTXYRwEivDCr40zZeJpcrLrB1fajs=
|
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef/go.mod h1:el5hGpj1C1bDRxcTXYRwEivDCr40zZeJpcrLrB1fajs=
|
||||||
github.com/FloatTech/rendercard v0.1.1 h1:vXz3x92bLavmNexTywdUvhft2/ipUSuo8aPRkqVdGQ8=
|
github.com/FloatTech/rendercard v0.2.0 h1:PBTZ2gCEy/dAEGSfWecrGTrWDYpiBJD1dVzNDDaOxh4=
|
||||||
github.com/FloatTech/rendercard v0.1.1/go.mod h1:Sbojcy1t3NfFz7/WicZRmR/uKFxNMYkKF8qHx69dxY0=
|
github.com/FloatTech/rendercard v0.2.0/go.mod h1:Sbojcy1t3NfFz7/WicZRmR/uKFxNMYkKF8qHx69dxY0=
|
||||||
github.com/FloatTech/sqlite v1.6.3 h1:MQkqBNlkPuCoKQQgoNLuTL/2Ci3tBTFAnVYBdD0Wy4M=
|
github.com/FloatTech/sqlite v1.7.2 h1:b8COegNLSzofzOyARsVwSbz9OOzWEa8IElsTlx1TBLw=
|
||||||
github.com/FloatTech/sqlite v1.6.3/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
|
github.com/FloatTech/sqlite v1.7.2/go.mod h1:/4tzfCGhrZnnjC1U8vcfwGQeF6eR649fhOsS3+Le0+s=
|
||||||
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562 h1:snfw7FNFym1eNnLrQ/VCf80LiQo9C7jHgrunZDwiRcY=
|
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d h1:mUQ/c3wXKsUGa4Sg9DBy01APXKB68PmobhxOyaJI7lY=
|
||||||
github.com/FloatTech/ttl v0.0.0-20240716161252-965925764562/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||||
github.com/FloatTech/zbpctrl v1.6.2-0.20240904160347-1317e11a15bb h1:sGqwCiMDyUD/znWEVVRVxbd6Kg1KLgGnnIuq5bCUWaQ=
|
github.com/FloatTech/zbpctrl v1.7.0 h1:Hxo6EIhJo+pHjcQP9QgIJgluaT1pHH99zkk3njqTNMo=
|
||||||
github.com/FloatTech/zbpctrl v1.6.2-0.20240904160347-1317e11a15bb/go.mod h1:I+MetM++1sJhNPg3zww1aw04BicYsNohvHC4Jh52XSo=
|
github.com/FloatTech/zbpctrl v1.7.0/go.mod h1:xmM4dSwHA02Gei3ogCRiG+RTrw/7Z69PfrN5NYf8BPE=
|
||||||
github.com/FloatTech/zbputils v1.7.2-0.20240822065525-5ea6811ed91c h1:hFiqx4uk6+lc2zHAaQ3JkkI2KH59c6O4yHKWKXFzxLs=
|
github.com/FloatTech/zbputils v1.7.2-0.20251002080916-b554b7039913 h1:uGexKAPL26sAWGemyHbfkjYyzFItMsbI8EREBLSZ/sU=
|
||||||
github.com/FloatTech/zbputils v1.7.2-0.20240822065525-5ea6811ed91c/go.mod h1:MwTFLPhlP0qMMLcq4x90oiu1IVE1T5dN0ZsxyTGSf6k=
|
github.com/FloatTech/zbputils v1.7.2-0.20251002080916-b554b7039913/go.mod h1:mNvv0+wCou042n/3QkK23WmbayNctT5wgkKC3A6nbmM=
|
||||||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||||
|
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
||||||
|
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
||||||
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 h1:S/ferNiehVjNaBMNNBxUjLtVmP/YWD6Yh79RfPv4ehU=
|
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 h1:S/ferNiehVjNaBMNNBxUjLtVmP/YWD6Yh79RfPv4ehU=
|
||||||
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
|
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
|
||||||
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5 h1:bBmmB7he0iVN4m5mcehfheeRUEer/Avo4ujnxI3uCqs=
|
github.com/RomiChan/websocket v1.4.3-0.20251002072000-d3eb41798438 h1:I0bdwHZ+2DY45b39xPoTD2u+Z8zhvBuu9aZfjMZeiZM=
|
||||||
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5/go.mod h1:0UcFaCkhp6vZw6l5Dpq0Dp673CoF9GdvA8lTfst0GiU=
|
github.com/RomiChan/websocket v1.4.3-0.20251002072000-d3eb41798438/go.mod h1:GO+9i5UYB4BuZEel6BfGx7O1u3ggwgZWUnGxPATUoTE=
|
||||||
|
github.com/Tnze/go-mc v1.20.2 h1:arHCE/WxLCxY73C/4ZNLdOymRYtdwoXE05ohB7HVN6Q=
|
||||||
|
github.com/Tnze/go-mc v1.20.2/go.mod h1:geoRj2HsXSkB3FJBuhr7wCzXegRlzWsVXd7h7jiJ6aQ=
|
||||||
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:ir/IFJU5xbja5UaBEQLjcvn7aAU01nqU/NUyOBEU+ew=
|
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:ir/IFJU5xbja5UaBEQLjcvn7aAU01nqU/NUyOBEU+ew=
|
||||||
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:PRWNwWq0yifz6XDPZu48aSld8BWwBfr2JKB2bGWiEd4=
|
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:PRWNwWq0yifz6XDPZu48aSld8BWwBfr2JKB2bGWiEd4=
|
||||||
github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca h1:kWzLcty5V2rzOqJM7Tp/MfSX0RMSI1x4IOLApEefYxA=
|
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
|
||||||
|
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
|
||||||
github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||||
|
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
|
||||||
|
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
|
||||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||||
github.com/antchfx/htmlquery v1.3.1 h1:wm0LxjLMsZhRHfQKKZscDf2COyH4vDYA3wyH+qZ+Ylc=
|
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||||
github.com/antchfx/htmlquery v1.3.1/go.mod h1:PTj+f1V2zksPlwNt7uVvZPsxpKNa7mlVliCRxLX6Nx8=
|
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||||
github.com/antchfx/xpath v1.3.0 h1:nTMlzGAK3IJ0bPpME2urTuFL76o4A96iYvoKFHRXJgc=
|
github.com/antchfx/htmlquery v1.3.4 h1:Isd0srPkni2iNTWCwVj/72t7uCphFeor5Q8nCzj1jdQ=
|
||||||
github.com/antchfx/xpath v1.3.0/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
github.com/antchfx/htmlquery v1.3.4/go.mod h1:K9os0BwIEmLAvTqaNSua8tXLWRWZpocZIH73OzWQbwM=
|
||||||
github.com/blend/go-sdk v1.20220411.3 h1:GFV4/FQX5UzXLPwWV03gP811pj7B8J2sbuq+GJQofXc=
|
github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||||
github.com/blend/go-sdk v1.20220411.3/go.mod h1:7lnH8fTi6U4i1fArEXRyOIY2E1X4MALg09qsQqY1+ak=
|
github.com/antchfx/xpath v1.3.5 h1:PqbXLC3TkfeZyakF5eeh3NTWEbYl4VHNVeufANzDbKQ=
|
||||||
|
github.com/antchfx/xpath v1.3.5/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||||
github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI=
|
github.com/corona10/goimagehash v1.1.0 h1:teNMX/1e+Wn/AYSbLHX8mj+mF9r60R1kBeqE9MkoYwI=
|
||||||
github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI=
|
github.com/corona10/goimagehash v1.1.0/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -50,24 +56,30 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1
|
|||||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
|
github.com/ebitengine/oto/v3 v3.4.0 h1:br0PgASsEWaoWn38b2Goe7m1GKFYfNgnsjSd5Gg+/bQ=
|
||||||
|
github.com/ebitengine/oto/v3 v3.4.0/go.mod h1:IOleLVD0m+CMak3mRVwsYY8vTctQgOM0iiL6S7Ar7eI=
|
||||||
|
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||||
|
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+JlV/f7JstZ4pitd4tHhpN+w+6I+LyOS7B4fyU=
|
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4 h1:BBade+JlV/f7JstZ4pitd4tHhpN+w+6I+LyOS7B4fyU=
|
||||||
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4/go.mod h1:H7chHJglrhPPzetLdzBleF8d22WYOv7UM/lEKYiwlKM=
|
github.com/ericpauley/go-quantize v0.0.0-20200331213906-ae555eb2afa4/go.mod h1:H7chHJglrhPPzetLdzBleF8d22WYOv7UM/lEKYiwlKM=
|
||||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||||
github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c=
|
github.com/fumiama/ahsai v0.1.1 h1:/t5tdKRim0TK6YwgNFQfqtDOW7Y2tFBsmdUWt3JK+C0=
|
||||||
github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4=
|
github.com/fumiama/ahsai v0.1.1/go.mod h1:rBhHLgN2bygcqLpBi+XQa8B8Afn4UkPHQ5vvQibdbDQ=
|
||||||
github.com/fumiama/ahsai v0.1.0 h1:LXD61Kaj6kJHa3AEGsLIfKNzcgaVxg7JB72OR4yNNZ4=
|
|
||||||
github.com/fumiama/ahsai v0.1.0/go.mod h1:fFeNnqgo44i8FIaguK659aQryuZeFy+4klYLQu/rfdk=
|
|
||||||
github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo=
|
github.com/fumiama/cron v1.3.0 h1:ZWlwuexF+HQHl3cYytEE5HNwD99q+3vNZF1GrEiXCFo=
|
||||||
github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY=
|
github.com/fumiama/cron v1.3.0/go.mod h1:bz5Izvgi/xEUI8tlBN8BI2jr9Moo8N4or0KV8xXuPDY=
|
||||||
|
github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa h1:UMMNejpPp8dn92GPaVSZ2XKNSgp7+CVneOkZfExUilk=
|
||||||
|
github.com/fumiama/deepinfra v0.0.0-20250924162107-cf156d49a0fa/go.mod h1:uqsWK/GM9OvKV0pXZOQB63rWugBbiXInY8E1JoRKhkg=
|
||||||
github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA=
|
github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA=
|
||||||
github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||||
|
github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8 h1:aXk5IVXvPy2IfajL6gH+V/6ZOVV1BBVKjnFISLvyw60=
|
||||||
|
github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8/go.mod h1:oH8DGDpRPjUAu8Fd/K+RxsB+z0Yis+BHeJAh+ZkO5EM=
|
||||||
github.com/fumiama/go-registry v0.2.7 h1:tLEqgEpsiybQMqBv0dLHm5leia/z1DhajMupwnOHeNs=
|
github.com/fumiama/go-registry v0.2.7 h1:tLEqgEpsiybQMqBv0dLHm5leia/z1DhajMupwnOHeNs=
|
||||||
github.com/fumiama/go-registry v0.2.7/go.mod h1:m+wp5fF8dYgVoFkBPZl+vlK90loymaJE0JCtocVQLEs=
|
github.com/fumiama/go-registry v0.2.7/go.mod h1:m+wp5fF8dYgVoFkBPZl+vlK90loymaJE0JCtocVQLEs=
|
||||||
github.com/fumiama/go-simple-protobuf v0.2.0 h1:ACyN1MAlu7pDR3EszWgzUeNP+IRsSHwH6V9JCJA5R5o=
|
github.com/fumiama/go-simple-protobuf v0.2.0 h1:ACyN1MAlu7pDR3EszWgzUeNP+IRsSHwH6V9JCJA5R5o=
|
||||||
github.com/fumiama/go-simple-protobuf v0.2.0/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4=
|
github.com/fumiama/go-simple-protobuf v0.2.0/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4=
|
||||||
github.com/fumiama/gofastTEA v0.0.10 h1:JJJ+brWD4kie+mmK2TkspDXKzqq0IjXm89aGYfoGhhQ=
|
github.com/fumiama/gofastTEA v0.1.3 h1:fxOi2D66knV6QN170hb59YiqxPhjlgizvBw+o0OjxUA=
|
||||||
github.com/fumiama/gofastTEA v0.0.10/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
|
github.com/fumiama/gofastTEA v0.1.3/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
|
||||||
github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc=
|
github.com/fumiama/gotracemoe v0.0.3 h1:iI5EbE9A3UUbfukG6+/soYPjp1S31eCNYf4tw7s6/Jc=
|
||||||
github.com/fumiama/gotracemoe v0.0.3/go.mod h1:tyqahdUzHf0bQIAVY/GYmDWvYYe5ik1ZbhnGYh+zl40=
|
github.com/fumiama/gotracemoe v0.0.3/go.mod h1:tyqahdUzHf0bQIAVY/GYmDWvYYe5ik1ZbhnGYh+zl40=
|
||||||
github.com/fumiama/imgsz v0.0.4 h1:Lsasu2hdSSFS+vnD+nvR1UkiRMK7hcpyYCC0FzgSMFI=
|
github.com/fumiama/imgsz v0.0.4 h1:Lsasu2hdSSFS+vnD+nvR1UkiRMK7hcpyYCC0FzgSMFI=
|
||||||
@ -76,48 +88,45 @@ github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 h1:sQuR2+N5HurnvsZhi
|
|||||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565/go.mod h1:UUEvyLTJ7yoOA/viKG4wEis4ERydM7+Ny6gZUWgkS80=
|
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565/go.mod h1:UUEvyLTJ7yoOA/viKG4wEis4ERydM7+Ny6gZUWgkS80=
|
||||||
github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5 h1:jDxsIupsT84A6WHcs6kWbst+KqrRQ8/o0VyoFMnbBOA=
|
github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5 h1:jDxsIupsT84A6WHcs6kWbst+KqrRQ8/o0VyoFMnbBOA=
|
||||||
github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5/go.mod h1:15P6ublJ9FJR8YQCGy8DeQ2Uwur7iW9Hserr/T3OFZE=
|
github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5/go.mod h1:15P6ublJ9FJR8YQCGy8DeQ2Uwur7iW9Hserr/T3OFZE=
|
||||||
|
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5 h1:j9o0XVvdAeLwrBYMnh0SerrMc9CgNU6AGszbsvFzoc0=
|
||||||
|
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5/go.mod h1:FOjdw7KdCbK2eH3gRPhwFNCoXKpu9sN5vPH4El/8e0c=
|
||||||
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4 h1:zN9e09TYKXI1mNkuS6YbH+Sn+4k5tBir+ovhZZcRYAs=
|
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4 h1:zN9e09TYKXI1mNkuS6YbH+Sn+4k5tBir+ovhZZcRYAs=
|
||||||
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4/go.mod h1:iZf1H/Jcw5gjOOFb4C5nlweJtViWc7uwUxRCe14pbYk=
|
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4/go.mod h1:iZf1H/Jcw5gjOOFb4C5nlweJtViWc7uwUxRCe14pbYk=
|
||||||
github.com/fumiama/sqlite3 v1.29.10-simp h1:c5y3uKyU0q9t0/SyfynzYyuslQ5zP+5CD8e0yYY554A=
|
github.com/fumiama/sqlite3 v1.29.10-simp h1:c5y3uKyU0q9t0/SyfynzYyuslQ5zP+5CD8e0yYY554A=
|
||||||
github.com/fumiama/sqlite3 v1.29.10-simp/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA=
|
github.com/fumiama/sqlite3 v1.29.10-simp/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA=
|
||||||
github.com/fumiama/terasu v0.0.0-20240507144117-547a591149c0 h1:So/3Bg/m2ZcUvqCzzEjjkjHBjcvnV3AN5tCxwsdMwYU=
|
github.com/fumiama/terasu v1.0.1 h1:WdP12r8xhRTyeCGWBtZx0QP0Eg5S3obJyS5MQVbBilE=
|
||||||
github.com/fumiama/terasu v0.0.0-20240507144117-547a591149c0/go.mod h1:UVx8YP1jKKL1Cj+uy+OnQRM2Ih6U36Mqy9GSf7jabsI=
|
github.com/fumiama/terasu v1.0.1/go.mod h1:ksDiLG3X7RM+B9XW2qvP+v8PU8hv+xhN5vdJdLoBWX4=
|
||||||
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6 h1:LtDgr628eji8jRpjPCxsk7ibjcfi97QieZVCTjxLCBw=
|
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6 h1:LtDgr628eji8jRpjPCxsk7ibjcfi97QieZVCTjxLCBw=
|
||||||
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6/go.mod h1:lEaZsT4FRSqcjnQ5q8y+mkenkzR/r1D3BJmfdp0vqDg=
|
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6/go.mod h1:lEaZsT4FRSqcjnQ5q8y+mkenkzR/r1D3BJmfdp0vqDg=
|
||||||
github.com/gabriel-vasile/mimetype v1.0.4 h1:uBejfH8l3/2f+5vjl1e4xIaSyNEhRBZ5N/ij7ohpNd8=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.0.4/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
|
github.com/gabriel-vasile/mimetype v1.0.4/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
|
||||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||||
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
|
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
|
|
||||||
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
|
|
||||||
github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE=
|
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
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/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/gopxl/beep/v2 v2.1.1 h1:6FYIYMm2qPAdWkjX+7xwKrViS1x0Po5kDMdRkq8NVbU=
|
||||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
github.com/gopxl/beep/v2 v2.1.1/go.mod h1:ZAm9TGQ9lvpoiFLd4zf5B1IuyxZhgRACMId1XJbaW0E=
|
||||||
github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk=
|
github.com/jfreymuth/oggvorbis v1.0.5 h1:u+Ck+R0eLSRhgq8WTmffYnrVtSztJcYrl588DM4e3kQ=
|
||||||
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos=
|
github.com/jfreymuth/oggvorbis v1.0.5/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
||||||
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
|
github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE=
|
||||||
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
|
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
|
||||||
github.com/jfreymuth/oggvorbis v1.0.1 h1:NT0eXBgE2WHzu6RT/6zcb2H10Kxj6Fm3PccT0LE6bqw=
|
|
||||||
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
|
|
||||||
github.com/jfreymuth/vorbis v1.0.0 h1:SmDf783s82lIjGZi8EGUUaS7YxPHgRj4ZXW/h7rUi7U=
|
|
||||||
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
|
|
||||||
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
@ -126,11 +135,11 @@ github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
|
|||||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/jozsefsallai/gophersauce v1.0.1 h1:BA3ovtQRrAb1qYU9JoRLbDHpxnDunlNcEkEfhCvDDCM=
|
github.com/jozsefsallai/gophersauce v1.0.1 h1:BA3ovtQRrAb1qYU9JoRLbDHpxnDunlNcEkEfhCvDDCM=
|
||||||
github.com/jozsefsallai/gophersauce v1.0.1/go.mod h1:YVEI7djliMTmZ1Vh01YPF8bUHi+oKhe3yXgKf1T49vg=
|
github.com/jozsefsallai/gophersauce v1.0.1/go.mod h1:YVEI7djliMTmZ1Vh01YPF8bUHi+oKhe3yXgKf1T49vg=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5 h1:BXnB1Gz4y/zwQh+ZFNy7rgd+ZfMOrwRr4uZSHEI+ieY=
|
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5 h1:BXnB1Gz4y/zwQh+ZFNy7rgd+ZfMOrwRr4uZSHEI+ieY=
|
||||||
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5/go.mod h1:c9+VS9GaommgIOzNWb5ze4lYwfT8BZ2UDyGiuQTT7yc=
|
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5/go.mod h1:c9+VS9GaommgIOzNWb5ze4lYwfT8BZ2UDyGiuQTT7yc=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
||||||
@ -141,163 +150,205 @@ github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d h1:hTRDIpJ1FjS9ULJuEzu69n
|
|||||||
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d/go.mod h1:7xD3p0XnHvJFQ3t/stEJd877CSIMkH/fACVWen5pYnc=
|
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d/go.mod h1:7xD3p0XnHvJFQ3t/stEJd877CSIMkH/fACVWen5pYnc=
|
||||||
github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5 h1:wnbHIeP1UX8ClYEWKGnw66PfYvReCHu9G5lXSte3Sqc=
|
github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5 h1:wnbHIeP1UX8ClYEWKGnw66PfYvReCHu9G5lXSte3Sqc=
|
||||||
github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5/go.mod h1:7KaV9YIR92M1FpbczAcfYQ3UZ5ayT27pNtunDmXvLBo=
|
github.com/liuzl/gocc v0.0.0-20231231122217-0372e1059ca5/go.mod h1:7KaV9YIR92M1FpbczAcfYQ3UZ5ayT27pNtunDmXvLBo=
|
||||||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||||
github.com/mewkiz/flac v1.0.7/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU=
|
github.com/mmcdole/gofeed v1.3.0 h1:5yn+HeqlcvjMeAI4gu6T+crm7d0anY85+M+v6fIFNG4=
|
||||||
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
|
github.com/mmcdole/gofeed v1.3.0/go.mod h1:9TGv2LcJhdXePDzxiuMnukhV2/zb6VtnZt1mS+SjkLE=
|
||||||
|
github.com/mmcdole/goxpp v1.1.1 h1:RGIX+D6iQRIunGHrKqnA2+700XMCnNv0bAOOv5MUhx8=
|
||||||
|
github.com/mmcdole/goxpp v1.1.1/go.mod h1:v+25+lT2ViuQ7mVxcncQ8ch1URund48oH+jhjiwEgS8=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8L3E=
|
github.com/mroth/weightedrand v1.0.0 h1:V8JeHChvl2MP1sAoXq4brElOcza+jxLkRuwvtQu8L3E=
|
||||||
github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE=
|
github.com/mroth/weightedrand v1.0.0/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
github.com/notnil/chess v1.9.0 h1:YMxR5kUVjtwcuFptGU0/3q7eG3MSHQNbg0VUekvRKV0=
|
github.com/notnil/chess v1.10.0 h1:RR3MgS9G6zZmJ+VPTJolyxdaIgxoUPyUUY+2iaw35G0=
|
||||||
github.com/notnil/chess v1.9.0/go.mod h1:cRuJUIBFq9Xki05TWHJxHYkC+fFpq45IWwk94DdlCrA=
|
github.com/notnil/chess v1.10.0/go.mod h1:cRuJUIBFq9Xki05TWHJxHYkC+fFpq45IWwk94DdlCrA=
|
||||||
|
github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e h1:s2RNOM/IGdY0Y6qfTeUKhDawdHDpK9RGBdx80qN4Ttw=
|
||||||
|
github.com/orcaman/writerseeker v0.0.0-20200621085525-1d3f536ff85e/go.mod h1:nBdnFKj15wFbf94Rwfq4m30eAcyY9V/IyKAGQFtqkW0=
|
||||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||||
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 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkumza/numcn v1.0.0 h1:ZT5cf9IJkUZgRgEtCiNNykk0RwsrKXSTsvDHOwUTzgE=
|
github.com/pkumza/numcn v1.0.0 h1:ZT5cf9IJkUZgRgEtCiNNykk0RwsrKXSTsvDHOwUTzgE=
|
||||||
github.com/pkumza/numcn v1.0.0/go.mod h1:QSeH+al9dWCd8di5HZM/ZqHqhZmUKfph572e9Ev/ETc=
|
github.com/pkumza/numcn v1.0.0/go.mod h1:QSeH+al9dWCd8di5HZM/ZqHqhZmUKfph572e9Ev/ETc=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
|
||||||
github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
|
|
||||||
github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
|
|
||||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
|
||||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
|
||||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
|
||||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||||
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0=
|
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||||
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94=
|
|
||||||
github.com/tidwall/gjson v1.17.3/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/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM=
|
||||||
|
github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
|
||||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.1 h1:2u7na789qiD5WzccZsFz4MJWOJP72G+2kUuJoSNqWnE=
|
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
|
||||||
github.com/wcharczuk/go-chart/v2 v2.1.1/go.mod h1:CyCAUt2oqvfhCl6Q5ZvAZwItgpQKZOkCJGb+VGv6l14=
|
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
|
||||||
github.com/wdvxdr1123/ZeroBot v1.7.5-0.20240829093431-bea5257d1a2b h1:DGVFcw0yQxLXmqWmVCqt5AfJd3V1Sea6af7hB0ynCfg=
|
github.com/wcharczuk/go-chart/v2 v2.1.2 h1:Y17/oYNuXwZg6TFag06qe8sBajwwsuvPiJJXcUcLL6E=
|
||||||
github.com/wdvxdr1123/ZeroBot v1.7.5-0.20240829093431-bea5257d1a2b/go.mod h1:C86nQ0gIdAri4K2vg8IIQIslt08zzrKMcqYt8zhkx1M=
|
github.com/wcharczuk/go-chart/v2 v2.1.2/go.mod h1:Zi4hbaqlWpYajnXB2K22IUYVXRXaLfSGNNR7P4ukyyQ=
|
||||||
|
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20251002074418-56567b7fc282 h1:YctW/t88sQ0H8cJ69PWULU6xWfh8kNsX/XgCpW2OPHw=
|
||||||
|
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20251002074418-56567b7fc282/go.mod h1:trueIIVRywKJa3ov4QphzVvzYzgCNrlXdf9JvPJOFW8=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
gitlab.com/gomidi/midi/v2 v2.1.7 h1:lIjVXH+bnGG04j/kUVOFILt0BQvBeGz8Kyz0l6aM830=
|
gitlab.com/gomidi/midi/v2 v2.3.16 h1:yufWSENyjnJ4LFQa9BerzUm4E4aLfTyzw5nmnCteO0c=
|
||||||
gitlab.com/gomidi/midi/v2 v2.1.7/go.mod h1:Cj6K9VH5GhYvPgL2JddxHBmZiP3nxKxB5XyTxiXvL9U=
|
gitlab.com/gomidi/midi/v2 v2.3.16/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 h1:idBdZTd9UioThJp8KpM/rTSinK/ChZFBE43/WtIy8zg=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||||
|
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
|
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||||
golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw=
|
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
|
||||||
golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs=
|
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
|
||||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6 h1:vyLBGJPIl9ZYbcQFM2USFmJBK6KI+t+z6jL0lbwjrnc=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
|
||||||
|
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
|
||||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
|
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||||
|
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
|
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||||
|
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
|
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||||
|
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
|
||||||
|
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
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/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
|
||||||
modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk=
|
modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk=
|
||||||
|
modernc.org/cc/v4 v4.21.2/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||||
modernc.org/ccgo/v4 v4.17.8 h1:yyWBf2ipA0Y9GGz/MmCmi3EFpKgeS7ICrAFes+suEbs=
|
modernc.org/ccgo/v4 v4.17.8 h1:yyWBf2ipA0Y9GGz/MmCmi3EFpKgeS7ICrAFes+suEbs=
|
||||||
|
modernc.org/ccgo/v4 v4.17.8/go.mod h1:buJnJ6Fn0tyAdP/dqePbrrvLyr6qslFfTbFrCuaYvtA=
|
||||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||||
|
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||||
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||||
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||||
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||||
|
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||||
|
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
||||||
|
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
|
||||||
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||||
|
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
|||||||
223
gomod2nix.toml
223
gomod2nix.toml
@ -5,11 +5,11 @@ schema = 3
|
|||||||
version = "v1.1.1"
|
version = "v1.1.1"
|
||||||
hash = "sha256-hKshA0K92bKuK92mmtM0osVmqLJcSbeobeWSDpQoRCo="
|
hash = "sha256-hKshA0K92bKuK92mmtM0osVmqLJcSbeobeWSDpQoRCo="
|
||||||
[mod."github.com/FloatTech/AnimeAPI"]
|
[mod."github.com/FloatTech/AnimeAPI"]
|
||||||
version = "v1.7.1-0.20240530072450-71c23d2f01f8"
|
version = "v1.7.1-0.20250926171956-ba37dfebfc4a"
|
||||||
hash = "sha256-NUYNGhjVW5bdpWIeKjBhnVTsjf6OXNqCcqzrRd3c+gE="
|
hash = "sha256-wtr9hgHSPsD5NqSmI3Lo8RVWE+cNMIUGo2bcsKTN8Gg="
|
||||||
[mod."github.com/FloatTech/floatbox"]
|
[mod."github.com/FloatTech/floatbox"]
|
||||||
version = "v0.0.0-20240505082030-226ec6713e14"
|
version = "v0.0.0-20251002074805-f95cbc7edb31"
|
||||||
hash = "sha256-v296D9T1QzFmcHQJNxJvx7sMtK+Jd1TUHXWqZtIvvf4="
|
hash = "sha256-c50unGhF0JVPHN8geZM/YYQKgGqJgCtVksh4Ij1Pg+4="
|
||||||
[mod."github.com/FloatTech/gg"]
|
[mod."github.com/FloatTech/gg"]
|
||||||
version = "v1.1.3"
|
version = "v1.1.3"
|
||||||
hash = "sha256-7K/R2mKjUHVnoJ3b1wDObJ5Un2Htj59Y97G1Ja1tuPo="
|
hash = "sha256-7K/R2mKjUHVnoJ3b1wDObJ5Un2Htj59Y97G1Ja1tuPo="
|
||||||
@ -17,41 +17,47 @@ schema = 3
|
|||||||
version = "v0.2.2-0.20230413152719-e101cc3606ef"
|
version = "v0.2.2-0.20230413152719-e101cc3606ef"
|
||||||
hash = "sha256-2okFyPQSYIxrc8hxICsbjEM9xq25a3I2A4wmDIYFCg8="
|
hash = "sha256-2okFyPQSYIxrc8hxICsbjEM9xq25a3I2A4wmDIYFCg8="
|
||||||
[mod."github.com/FloatTech/rendercard"]
|
[mod."github.com/FloatTech/rendercard"]
|
||||||
version = "v0.1.1"
|
version = "v0.2.0"
|
||||||
hash = "sha256-w5GcscWQzgdcfC0Vw4u+7/NipP3PTB2UrVcxki88IPo="
|
hash = "sha256-fgntEYGh2mEl618hM13kb0GGeQEXdP+lochYX8F2OXs="
|
||||||
[mod."github.com/FloatTech/sqlite"]
|
[mod."github.com/FloatTech/sqlite"]
|
||||||
version = "v1.6.3"
|
version = "v1.7.2"
|
||||||
hash = "sha256-zWPByEMi89ms67ubPg0fAPIRxfpBC2IRKc0iNVLqkPU="
|
hash = "sha256-R9QaP5FQwtWpHdbCoNX/rYOS/CgkIeRdFB9cwJ4n/JM="
|
||||||
[mod."github.com/FloatTech/ttl"]
|
[mod."github.com/FloatTech/ttl"]
|
||||||
version = "v0.0.0-20240716161252-965925764562"
|
version = "v0.0.0-20250224045156-012b1463287d"
|
||||||
hash = "sha256-/XjfdVXEzYgeM+OYuyy76tf13lO91vCcwpjWgkRGteU="
|
hash = "sha256-C5xBt0roPgahradCOTgkhL+j5bvoSXmGwdqcu0aSczc="
|
||||||
[mod."github.com/FloatTech/zbpctrl"]
|
[mod."github.com/FloatTech/zbpctrl"]
|
||||||
version = "v1.6.2-0.20240904160347-1317e11a15bb"
|
version = "v1.7.0"
|
||||||
hash = "sha256-x0ZR2bnkboEIjjRFMtMAN0T34BP9BPs7r3AwT3BCyzo="
|
hash = "sha256-HDDnE0oktWJH1tkxuQwUUbeJhmVwY5fyc/vR72D2mkU="
|
||||||
[mod."github.com/FloatTech/zbputils"]
|
[mod."github.com/FloatTech/zbputils"]
|
||||||
version = "v1.7.2-0.20240822065525-5ea6811ed91c"
|
version = "v1.7.2-0.20251002080916-b554b7039913"
|
||||||
hash = "sha256-ouAExps1iPCcD1AmOxyhRXMBGHBDXvUGkplcnQCf3Bg="
|
hash = "sha256-9z7c79uuFl2LKaCgW1gQN5lmMjgKIcKrakcBlb3zJ90="
|
||||||
|
[mod."github.com/PuerkitoBio/goquery"]
|
||||||
|
version = "v1.10.3"
|
||||||
|
hash = "sha256-Mth7nYm/MtcOhPMbHj7gXF+Mot7eDUBVN570RitGR/c="
|
||||||
[mod."github.com/RomiChan/syncx"]
|
[mod."github.com/RomiChan/syncx"]
|
||||||
version = "v0.0.0-20240418144900-b7402ffdebc7"
|
version = "v0.0.0-20240418144900-b7402ffdebc7"
|
||||||
hash = "sha256-L1j1vgiwqXpF9pjMoRRlrQUHzoULisw/01plaEAwxs4="
|
hash = "sha256-L1j1vgiwqXpF9pjMoRRlrQUHzoULisw/01plaEAwxs4="
|
||||||
[mod."github.com/RomiChan/websocket"]
|
[mod."github.com/RomiChan/websocket"]
|
||||||
version = "v1.4.3-0.20220227141055-9b2c6168c9c5"
|
version = "v1.4.3-0.20251002072000-d3eb41798438"
|
||||||
hash = "sha256-Adx+gvqB+CCoUXx7ebIaBDjVkav+wS5qZPmaqcApBWA="
|
hash = "sha256-vLu9Va+9AbOIdh1LEetz5JlJK0P2IXKsYRvCdAO8tYw="
|
||||||
|
[mod."github.com/Tnze/go-mc"]
|
||||||
|
version = "v1.20.2"
|
||||||
|
hash = "sha256-Nu4PXNxeARH0itm6yIIplFaywL2yQnPJFksmmuyIptI="
|
||||||
[mod."github.com/adamzy/cedar-go"]
|
[mod."github.com/adamzy/cedar-go"]
|
||||||
version = "v0.0.0-20170805034717-80a9c64b256d"
|
version = "v0.0.0-20170805034717-80a9c64b256d"
|
||||||
hash = "sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0="
|
hash = "sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0="
|
||||||
[mod."github.com/ajstarks/svgo"]
|
[mod."github.com/ajstarks/svgo"]
|
||||||
version = "v0.0.0-20200320125537-f189e35d30ca"
|
version = "v0.0.0-20211024235047-1546f124cd8b"
|
||||||
hash = "sha256-ALeRuEJN9jHjGb4wNKJcxC59vVx8Tj7hHikEGkaZZ0s="
|
hash = "sha256-sPwt5sImKFk949TzUeYEF2UiJDqHxXFJKRL2Y7JWJ6Y="
|
||||||
|
[mod."github.com/andybalholm/cascadia"]
|
||||||
|
version = "v1.3.3"
|
||||||
|
hash = "sha256-jv7ZshpSd7FZzKKN6hqlUgiR8C3y85zNIS/hq7g76Ho="
|
||||||
[mod."github.com/antchfx/htmlquery"]
|
[mod."github.com/antchfx/htmlquery"]
|
||||||
version = "v1.3.1"
|
version = "v1.3.4"
|
||||||
hash = "sha256-4ZzKk7Z+vH8ytisdtcZz/Y0MbnVVhruiO/7gtUy3ouQ="
|
hash = "sha256-nrtIgRgdOvo0iIQyrhHOFKOmoT8e2gduUsct3f5zDNA="
|
||||||
[mod."github.com/antchfx/xpath"]
|
[mod."github.com/antchfx/xpath"]
|
||||||
version = "v1.3.0"
|
version = "v1.3.5"
|
||||||
hash = "sha256-SU+Tnf5c9vsDCrY1BVKjqYLhB91xt9oHBS5bicbs2cA="
|
hash = "sha256-AVM0rR81hgVAI0QVzlz4WijFUjByf6Zew3ZwuikKw2Q="
|
||||||
[mod."github.com/blend/go-sdk"]
|
|
||||||
version = "v1.20220411.3"
|
|
||||||
hash = "sha256-yxrf24hru8NeTPUmoaJG1PcmHE5pn/U36Sj9Qg+JVqg="
|
|
||||||
[mod."github.com/corona10/goimagehash"]
|
[mod."github.com/corona10/goimagehash"]
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
hash = "sha256-HyS8nc7kUNnDaVBDzJ9Ym4pRs83YB4M2vHSRwfm6mr4="
|
hash = "sha256-HyS8nc7kUNnDaVBDzJ9Ym4pRs83YB4M2vHSRwfm6mr4="
|
||||||
@ -64,21 +70,30 @@ schema = 3
|
|||||||
[mod."github.com/dustin/go-humanize"]
|
[mod."github.com/dustin/go-humanize"]
|
||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
hash = "sha256-yuvxYYngpfVkUg9yAmG99IUVmADTQA0tMbBXe0Fq0Mc="
|
hash = "sha256-yuvxYYngpfVkUg9yAmG99IUVmADTQA0tMbBXe0Fq0Mc="
|
||||||
|
[mod."github.com/ebitengine/oto/v3"]
|
||||||
|
version = "v3.4.0"
|
||||||
|
hash = "sha256-8JU4iu+2pUKWVWMpEe8EAZ8FVo3MZdILu82vVVmDSVY="
|
||||||
|
[mod."github.com/ebitengine/purego"]
|
||||||
|
version = "v0.9.0"
|
||||||
|
hash = "sha256-jSlhGjhuYf15zHy7shSKR1rQN1sRyH5zXAzWqy+huHY="
|
||||||
[mod."github.com/ericpauley/go-quantize"]
|
[mod."github.com/ericpauley/go-quantize"]
|
||||||
version = "v0.0.0-20200331213906-ae555eb2afa4"
|
version = "v0.0.0-20200331213906-ae555eb2afa4"
|
||||||
hash = "sha256-sMN6D7IlDpDqUWM8ppoE5Sdb7DvLAJaN6qAucBWJ3rs="
|
hash = "sha256-sMN6D7IlDpDqUWM8ppoE5Sdb7DvLAJaN6qAucBWJ3rs="
|
||||||
[mod."github.com/faiface/beep"]
|
|
||||||
version = "v1.1.0"
|
|
||||||
hash = "sha256-66qAbnJjUjhXofxlGCa6G1+vjQcSTyN/POCZvYzHaQo="
|
|
||||||
[mod."github.com/fumiama/ahsai"]
|
[mod."github.com/fumiama/ahsai"]
|
||||||
version = "v0.1.0"
|
version = "v0.1.1"
|
||||||
hash = "sha256-lSoos+SFjALcL0ZYPsbOb8wntwn2fcubvSsz0YKgL9c="
|
hash = "sha256-knYw0R5fhjE/asc/TwlGJDzVr+Oaj8sH7kr7x6Mqs3E="
|
||||||
[mod."github.com/fumiama/cron"]
|
[mod."github.com/fumiama/cron"]
|
||||||
version = "v1.3.0"
|
version = "v1.3.0"
|
||||||
hash = "sha256-/sN7X8dKXQgv8J+EDzVUB+o+AY9gBC8e1C6sYhaTy1k="
|
hash = "sha256-/sN7X8dKXQgv8J+EDzVUB+o+AY9gBC8e1C6sYhaTy1k="
|
||||||
|
[mod."github.com/fumiama/deepinfra"]
|
||||||
|
version = "v0.0.0-20250924162107-cf156d49a0fa"
|
||||||
|
hash = "sha256-D0lgA7jBDLE8v9ePDiWwH439eB5+cDlj2fKRAc0wUms="
|
||||||
[mod."github.com/fumiama/go-base16384"]
|
[mod."github.com/fumiama/go-base16384"]
|
||||||
version = "v1.7.0"
|
version = "v1.7.0"
|
||||||
hash = "sha256-vTAsBBYe2ISzb2Nba5E96unodZSkhMcqo6hbwR01nz8="
|
hash = "sha256-vTAsBBYe2ISzb2Nba5E96unodZSkhMcqo6hbwR01nz8="
|
||||||
|
[mod."github.com/fumiama/go-onebot-agent"]
|
||||||
|
version = "v0.0.0-20250926145606-37ebfa6131c8"
|
||||||
|
hash = "sha256-oq1SSyddsXhsFvSHFhqSEAF9SH03b2jI0KvGbsFPXYQ="
|
||||||
[mod."github.com/fumiama/go-registry"]
|
[mod."github.com/fumiama/go-registry"]
|
||||||
version = "v0.2.7"
|
version = "v0.2.7"
|
||||||
hash = "sha256-Rjl+z0Hlp2LMi8+pnFe5HrxctyHMi7UPiK33g/OgLdA="
|
hash = "sha256-Rjl+z0Hlp2LMi8+pnFe5HrxctyHMi7UPiK33g/OgLdA="
|
||||||
@ -86,8 +101,8 @@ schema = 3
|
|||||||
version = "v0.2.0"
|
version = "v0.2.0"
|
||||||
hash = "sha256-2kULBi1sXsFDX2g/KRFmCGkwF60o/UXacNUbIYa/cvw="
|
hash = "sha256-2kULBi1sXsFDX2g/KRFmCGkwF60o/UXacNUbIYa/cvw="
|
||||||
[mod."github.com/fumiama/gofastTEA"]
|
[mod."github.com/fumiama/gofastTEA"]
|
||||||
version = "v0.0.10"
|
version = "v0.1.3"
|
||||||
hash = "sha256-FOCbkXoS8s/K54yZbhX5pmaN/ouELnCHZoNS8a90VAg="
|
hash = "sha256-/Qu57mkkFt7aFufhlkMYPgrWj5XCGbuM28EHDD8w4XY="
|
||||||
[mod."github.com/fumiama/gotracemoe"]
|
[mod."github.com/fumiama/gotracemoe"]
|
||||||
version = "v0.0.3"
|
version = "v0.0.3"
|
||||||
hash = "sha256-O3cDkVXu5NG1ZtzubxhH+S91zfgu4uH1L+OiSGYSNXQ="
|
hash = "sha256-O3cDkVXu5NG1ZtzubxhH+S91zfgu4uH1L+OiSGYSNXQ="
|
||||||
@ -97,39 +112,42 @@ schema = 3
|
|||||||
[mod."github.com/fumiama/jieba"]
|
[mod."github.com/fumiama/jieba"]
|
||||||
version = "v0.0.0-20221203025406-36c17a10b565"
|
version = "v0.0.0-20221203025406-36c17a10b565"
|
||||||
hash = "sha256-DvDx1pdldkdaSszrbadM/VwqT9TTSmWl6G6a+ysXYEM="
|
hash = "sha256-DvDx1pdldkdaSszrbadM/VwqT9TTSmWl6G6a+ysXYEM="
|
||||||
|
[mod."github.com/fumiama/orbyte"]
|
||||||
|
version = "v0.0.0-20251002065953-3bb358367eb5"
|
||||||
|
hash = "sha256-mRQwhR0v922UXlJ7lXo/osv21K8kZDaHx3DsBCjmzoo="
|
||||||
[mod."github.com/fumiama/slowdo"]
|
[mod."github.com/fumiama/slowdo"]
|
||||||
version = "v0.0.0-20241001074058-27c4fe5259a4"
|
version = "v0.0.0-20241001074058-27c4fe5259a4"
|
||||||
hash = "sha256-rsV3MKRCSOBMIgJXFCGbCHRY2aBAb32ftU49hT3GjqY="
|
hash = "sha256-rsV3MKRCSOBMIgJXFCGbCHRY2aBAb32ftU49hT3GjqY="
|
||||||
[mod."github.com/fumiama/terasu"]
|
[mod."github.com/fumiama/terasu"]
|
||||||
version = "v0.0.0-20240507144117-547a591149c0"
|
version = "v1.0.1"
|
||||||
hash = "sha256-ZZG5/Ckq4R0eojmiuli5ZRToDNQt4VeRwdy0jjVCvbg="
|
hash = "sha256-7pe0ByxkmqWeYsxWNwa8urfv6lK1cEPrW1b5l86eM1Y="
|
||||||
[mod."github.com/fumiama/unibase2n"]
|
[mod."github.com/fumiama/unibase2n"]
|
||||||
version = "v0.0.0-20240530074540-ec743fd5a6d6"
|
version = "v0.0.0-20240530074540-ec743fd5a6d6"
|
||||||
hash = "sha256-I3xNzjrj5y0fy0dfa75V57GanfmHIHmubEn9/y0BBHw="
|
hash = "sha256-I3xNzjrj5y0fy0dfa75V57GanfmHIHmubEn9/y0BBHw="
|
||||||
[mod."github.com/gabriel-vasile/mimetype"]
|
[mod."github.com/gabriel-vasile/mimetype"]
|
||||||
version = "v1.0.4"
|
version = "v1.4.10"
|
||||||
hash = "sha256-5hl9zBo3nkPt8dZfcLoOix8lAKLm3qIkWhopoS4V34E="
|
hash = "sha256-ha8NJOAWcmEfQaybfNxyUupt0+zlWxoAKLjCacew43s="
|
||||||
[mod."github.com/go-ole/go-ole"]
|
[mod."github.com/go-ole/go-ole"]
|
||||||
version = "v1.2.6"
|
version = "v1.3.0"
|
||||||
hash = "sha256-+oxitLeJxYF19Z6g+6CgmCHJ1Y5D8raMi2Cb3M6nXCs="
|
hash = "sha256-tF8t3VcV71jQ4jbPL91BwR59AKDpUAFV1waIKzkXJu8="
|
||||||
[mod."github.com/golang/freetype"]
|
[mod."github.com/golang/freetype"]
|
||||||
version = "v0.0.0-20170609003504-e2365dfdc4a0"
|
version = "v0.0.0-20170609003504-e2365dfdc4a0"
|
||||||
hash = "sha256-AHAFBd20/tqxohkWyQkui2bUef9i1HWYgk9LOIFErvA="
|
hash = "sha256-AHAFBd20/tqxohkWyQkui2bUef9i1HWYgk9LOIFErvA="
|
||||||
[mod."github.com/golang/groupcache"]
|
[mod."github.com/golang/groupcache"]
|
||||||
version = "v0.0.0-20210331224755-41bb18bfe9da"
|
version = "v0.0.0-20241129210726-2c02b8208cf8"
|
||||||
hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0="
|
hash = "sha256-AdLZ3dJLe/yduoNvZiXugZxNfmwJjNQyQGsIdzYzH74="
|
||||||
[mod."github.com/google/uuid"]
|
[mod."github.com/google/uuid"]
|
||||||
version = "v1.6.0"
|
version = "v1.6.0"
|
||||||
hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw="
|
hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw="
|
||||||
[mod."github.com/hajimehoshi/oto"]
|
[mod."github.com/gopxl/beep/v2"]
|
||||||
version = "v0.7.1"
|
version = "v2.1.1"
|
||||||
hash = "sha256-eRgbEbsziY5F0oI7wAe29FepZG7uGmq2M4deouDHcXI="
|
hash = "sha256-JLCUJCG+VvNlVF296JWIOUvvUFHlqEAJvZfw853qwwU="
|
||||||
[mod."github.com/jfreymuth/oggvorbis"]
|
[mod."github.com/jfreymuth/oggvorbis"]
|
||||||
version = "v1.0.1"
|
version = "v1.0.5"
|
||||||
hash = "sha256-DpkiTLxAA/iCoiylpNRvMzvaDWtK+U4UMJYNnnCmJMU="
|
hash = "sha256-jphTCaPr34ZT9Id4ZZ6zU9Vnxzy6cTjCwjpQ819eGV0="
|
||||||
[mod."github.com/jfreymuth/vorbis"]
|
[mod."github.com/jfreymuth/vorbis"]
|
||||||
version = "v1.0.0"
|
version = "v1.0.2"
|
||||||
hash = "sha256-6kTol+g3NnZ3MazD786fvraw7ydUf0RWNBzHpzgN9Jk="
|
hash = "sha256-gVS+/PZ5pDnswpTQNZILcrx5ZNq9ShXd6vXn7Jabes4="
|
||||||
[mod."github.com/jinzhu/gorm"]
|
[mod."github.com/jinzhu/gorm"]
|
||||||
version = "v1.9.16"
|
version = "v1.9.16"
|
||||||
hash = "sha256-qKEwgNE8NxcX1uzT20LwC1TKVmve/nIy+oxdAKlxAuc="
|
hash = "sha256-qKEwgNE8NxcX1uzT20LwC1TKVmve/nIy+oxdAKlxAuc="
|
||||||
@ -139,12 +157,12 @@ schema = 3
|
|||||||
[mod."github.com/jozsefsallai/gophersauce"]
|
[mod."github.com/jozsefsallai/gophersauce"]
|
||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
hash = "sha256-29DsfnGmK51DPunR/leRBKCcokN/yLoB7S2HxCsqtgY="
|
hash = "sha256-29DsfnGmK51DPunR/leRBKCcokN/yLoB7S2HxCsqtgY="
|
||||||
|
[mod."github.com/json-iterator/go"]
|
||||||
|
version = "v1.1.12"
|
||||||
|
hash = "sha256-To8A0h+lbfZ/6zM+2PpRpY3+L6725OPC66lffq6fUoM="
|
||||||
[mod."github.com/kanrichan/resvg-go"]
|
[mod."github.com/kanrichan/resvg-go"]
|
||||||
version = "v0.0.2-0.20231001163256-63db194ca9f5"
|
version = "v0.0.2-0.20231001163256-63db194ca9f5"
|
||||||
hash = "sha256-plRZ3yhyCafCXmAD4vnFUoCTRsHmLp7Jn9gFKcEKbds="
|
hash = "sha256-plRZ3yhyCafCXmAD4vnFUoCTRsHmLp7Jn9gFKcEKbds="
|
||||||
[mod."github.com/kr/text"]
|
|
||||||
version = "v0.2.0"
|
|
||||||
hash = "sha256-fadcWxZOORv44oak3jTxm6YcITcFxdGt4bpn869HxUE="
|
|
||||||
[mod."github.com/lithammer/fuzzysearch"]
|
[mod."github.com/lithammer/fuzzysearch"]
|
||||||
version = "v1.1.8"
|
version = "v1.1.8"
|
||||||
hash = "sha256-aMMRcrlUc9CBiiNkcnWWn4hfNMNyVhrAt67kvP4D4Do="
|
hash = "sha256-aMMRcrlUc9CBiiNkcnWWn4hfNMNyVhrAt67kvP4D4Do="
|
||||||
@ -158,23 +176,35 @@ schema = 3
|
|||||||
version = "v0.0.0-20231231122217-0372e1059ca5"
|
version = "v0.0.0-20231231122217-0372e1059ca5"
|
||||||
hash = "sha256-Dr1xDbO+eR4Y/EpPgQ/S6g6C5etRFKWr8de77skcJR8="
|
hash = "sha256-Dr1xDbO+eR4Y/EpPgQ/S6g6C5etRFKWr8de77skcJR8="
|
||||||
[mod."github.com/lufia/plan9stats"]
|
[mod."github.com/lufia/plan9stats"]
|
||||||
version = "v0.0.0-20211012122336-39d0f177ccd0"
|
version = "v0.0.0-20251013123823-9fd1530e3ec3"
|
||||||
hash = "sha256-thb+rkDx5IeWMgw5/5jgu5gZ+6RjJAUXeMgSkJHhRlA="
|
hash = "sha256-N760qPHHaMcxICyA3Ap/b/3exi40AStu7458VPvC9GI="
|
||||||
[mod."github.com/mattn/go-isatty"]
|
[mod."github.com/mattn/go-isatty"]
|
||||||
version = "v0.0.20"
|
version = "v0.0.20"
|
||||||
hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ="
|
hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ="
|
||||||
|
[mod."github.com/mmcdole/gofeed"]
|
||||||
|
version = "v1.3.0"
|
||||||
|
hash = "sha256-GHpqGZvNg+3RSIkVKXrWg6/e8dJD8Y5v2Sx6MzmRlQ0="
|
||||||
|
[mod."github.com/mmcdole/goxpp"]
|
||||||
|
version = "v1.1.1"
|
||||||
|
hash = "sha256-LtZDUtflL06HnDuQiCS6cpoF3VPk+gmABkYXBvdQOz0="
|
||||||
|
[mod."github.com/modern-go/concurrent"]
|
||||||
|
version = "v0.0.0-20180306012644-bacd9c7ef1dd"
|
||||||
|
hash = "sha256-OTySieAgPWR4oJnlohaFTeK1tRaVp/b0d1rYY8xKMzo="
|
||||||
|
[mod."github.com/modern-go/reflect2"]
|
||||||
|
version = "v1.0.2"
|
||||||
|
hash = "sha256-+W9EIW7okXIXjWEgOaMh58eLvBZ7OshW2EhaIpNLSBU="
|
||||||
[mod."github.com/mroth/weightedrand"]
|
[mod."github.com/mroth/weightedrand"]
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
hash = "sha256-bP+yIaBUY5+oI455mNM8zh14z/SNPaQg44L3RJ0/v/c="
|
hash = "sha256-bP+yIaBUY5+oI455mNM8zh14z/SNPaQg44L3RJ0/v/c="
|
||||||
[mod."github.com/ncruces/go-strftime"]
|
[mod."github.com/ncruces/go-strftime"]
|
||||||
version = "v0.1.9"
|
version = "v1.0.0"
|
||||||
hash = "sha256-T0iw+UEckzueWHT88PkTnZZixyKCEa+DTLzIiiohuWY="
|
hash = "sha256-GYIwYDONuv/yTE0AEugCHQbtV3oiBaco93xUNYFcVBQ="
|
||||||
[mod."github.com/nfnt/resize"]
|
[mod."github.com/nfnt/resize"]
|
||||||
version = "v0.0.0-20180221191011-83c6a9932646"
|
version = "v0.0.0-20180221191011-83c6a9932646"
|
||||||
hash = "sha256-yvPV+HlDOyJsiwAcVHQkmtw8DHSXyw+cXHkigXm8rAA="
|
hash = "sha256-yvPV+HlDOyJsiwAcVHQkmtw8DHSXyw+cXHkigXm8rAA="
|
||||||
[mod."github.com/notnil/chess"]
|
[mod."github.com/notnil/chess"]
|
||||||
version = "v1.9.0"
|
version = "v1.10.0"
|
||||||
hash = "sha256-2bHp/H5hBE/hPMT1HLOBqMaCZ/DYWJMDri26O9Yzoms="
|
hash = "sha256-hsUOS4rVuMW+UCPJzhsZh3PHCi1Lol12BwKujcICayo="
|
||||||
[mod."github.com/pbnjay/memory"]
|
[mod."github.com/pbnjay/memory"]
|
||||||
version = "v0.0.0-20210728143218-7b4eea64cf58"
|
version = "v0.0.0-20210728143218-7b4eea64cf58"
|
||||||
hash = "sha256-QI+F1oPLOOtwNp8+m45OOoSfYFs3QVjGzE0rFdpF/IA="
|
hash = "sha256-QI+F1oPLOOtwNp8+m45OOoSfYFs3QVjGzE0rFdpF/IA="
|
||||||
@ -185,71 +215,62 @@ schema = 3
|
|||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
hash = "sha256-cPxqj5tb10+MurN1Lehkk/v8KjaxXpL08+pVgL4x4Hg="
|
hash = "sha256-cPxqj5tb10+MurN1Lehkk/v8KjaxXpL08+pVgL4x4Hg="
|
||||||
[mod."github.com/power-devops/perfstat"]
|
[mod."github.com/power-devops/perfstat"]
|
||||||
version = "v0.0.0-20210106213030-5aafc221ea8c"
|
version = "v0.0.0-20240221224432-82ca36839d55"
|
||||||
hash = "sha256-ywykDYuqcMt0TvZOz1l9Z6Z2JMTYQw8cP2fT8AtpmX4="
|
hash = "sha256-ujzuJ1ttQgjHQJEij4O/2+I8DZaUVZQCQgA4ysfqulI="
|
||||||
[mod."github.com/remyoudompheng/bigfft"]
|
[mod."github.com/remyoudompheng/bigfft"]
|
||||||
version = "v0.0.0-20230129092748-24d4a6f8daec"
|
version = "v0.0.0-20230129092748-24d4a6f8daec"
|
||||||
hash = "sha256-vYmpyCE37eBYP/navhaLV4oX4/nu0Z/StAocLIFqrmM="
|
hash = "sha256-vYmpyCE37eBYP/navhaLV4oX4/nu0Z/StAocLIFqrmM="
|
||||||
[mod."github.com/rogpeppe/go-internal"]
|
|
||||||
version = "v1.12.0"
|
|
||||||
hash = "sha256-qvDNCe3l84/LgrA8X4O15e1FeDcazyX91m9LmXGXX6M="
|
|
||||||
[mod."github.com/shirou/gopsutil/v3"]
|
[mod."github.com/shirou/gopsutil/v3"]
|
||||||
version = "v3.24.4"
|
version = "v3.24.5"
|
||||||
hash = "sha256-ubkBxu9X4LRhI1HqkjsIShR4e8rQsuKQs4VNOIIhZCU="
|
hash = "sha256-tc+t1u7gf5A+Bd956dYeM8pGbxs9ezQHqKAKfLQLpuQ="
|
||||||
[mod."github.com/shoenig/go-m1cpu"]
|
[mod."github.com/shoenig/go-m1cpu"]
|
||||||
version = "v0.1.6"
|
version = "v0.1.7"
|
||||||
hash = "sha256-hT+JP30BBllsXosK/lo89HV/uxxPLsUyO3dRaDiLnCg="
|
hash = "sha256-kIKIE9uxHOniFHGgMgtypYB/OPI8VSQxFUHXehlpuYY="
|
||||||
[mod."github.com/sirupsen/logrus"]
|
[mod."github.com/sirupsen/logrus"]
|
||||||
version = "v1.9.3"
|
version = "v1.9.3"
|
||||||
hash = "sha256-EnxsWdEUPYid+aZ9H4/iMTs1XMvCLbXZRDyvj89Ebms="
|
hash = "sha256-EnxsWdEUPYid+aZ9H4/iMTs1XMvCLbXZRDyvj89Ebms="
|
||||||
[mod."github.com/tetratelabs/wazero"]
|
[mod."github.com/tetratelabs/wazero"]
|
||||||
version = "v1.5.0"
|
version = "v1.9.0"
|
||||||
hash = "sha256-fGdJM4LJrZA9jxHuYVo4EUQ3I1k0IVG3QQCBCgZkeZI="
|
hash = "sha256-b8D0cDMuDgyjvJ6LFY8REdcL95BIjM27SeOEQWfB0+0="
|
||||||
[mod."github.com/tidwall/gjson"]
|
[mod."github.com/tidwall/gjson"]
|
||||||
version = "v1.17.3"
|
version = "v1.18.0"
|
||||||
hash = "sha256-zui8S4qlfFXNLartKynJbYqeM/MW3f3eDbojIvh/KS8="
|
hash = "sha256-CO6hqDu8Y58Po6A01e5iTpwiUBQ5khUZsw7czaJHw0I="
|
||||||
[mod."github.com/tidwall/match"]
|
[mod."github.com/tidwall/match"]
|
||||||
version = "v1.1.1"
|
|
||||||
hash = "sha256-M2klhPId3Q3T3VGkSbOkYl/2nLHnsG+yMbXkPkyrRdg="
|
|
||||||
[mod."github.com/tidwall/pretty"]
|
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
hash = "sha256-esRQGsn2Ee/CiySlwyuOICSLdqUkH4P7u8qXszos8Yc="
|
hash = "sha256-O2wTU0SmNIEEOxfncl2BW2czgWeIW5vqR6+A7dtNtXI="
|
||||||
|
[mod."github.com/tidwall/pretty"]
|
||||||
|
version = "v1.2.1"
|
||||||
|
hash = "sha256-S0uTDDGD8qr415Ut7QinyXljCp0TkL4zOIrlJ+9OMl8="
|
||||||
[mod."github.com/tklauser/go-sysconf"]
|
[mod."github.com/tklauser/go-sysconf"]
|
||||||
version = "v0.3.12"
|
version = "v0.3.15"
|
||||||
hash = "sha256-91VBZNb3L2TZkEETF1AE4wnraLoGxKeofUbC5ZiWVHk="
|
hash = "sha256-Twh9dD/mfNb7Qr5p/KmaK5Xi25VJwj5jESZeJr0qeUc="
|
||||||
[mod."github.com/tklauser/numcpus"]
|
[mod."github.com/tklauser/numcpus"]
|
||||||
version = "v0.6.1"
|
version = "v0.10.0"
|
||||||
hash = "sha256-8eFcw4YI0w6+GPhU5xMMQjiio94q/O5PpNO3QsvXve0="
|
hash = "sha256-NWg68H2Y6MijtlscPaZlLQwgPthEwLV+WpRT01m6kkI="
|
||||||
[mod."github.com/wcharczuk/go-chart/v2"]
|
[mod."github.com/wcharczuk/go-chart/v2"]
|
||||||
version = "v2.1.1"
|
version = "v2.1.2"
|
||||||
hash = "sha256-emvjt/ze8skM+MBflwV0EgS/svpaEGU/mn27Ie4VTXs="
|
hash = "sha256-GXWWea/u6BezTsPPrWhTYiTetPP/YW6P+Sj4YdocPaM="
|
||||||
[mod."github.com/wdvxdr1123/ZeroBot"]
|
[mod."github.com/wdvxdr1123/ZeroBot"]
|
||||||
version = "v1.7.5-0.20240829093431-bea5257d1a2b"
|
version = "v1.8.2-0.20251002074418-56567b7fc282"
|
||||||
hash = "sha256-P8kexm2KOaXIk4Xnex5e02vv1ObTeWKhnWnxnDXrUDE="
|
hash = "sha256-KaoqopWcXqiRhGYNaA3UqYtXf27yMuBEj/bvqOWxaC4="
|
||||||
[mod."github.com/yusufpapurcu/wmi"]
|
[mod."github.com/yusufpapurcu/wmi"]
|
||||||
version = "v1.2.4"
|
version = "v1.2.4"
|
||||||
hash = "sha256-N+YDBjOW59YOsZ2lRBVtFsEEi48KhNQRb63/0ZSU3bA="
|
hash = "sha256-N+YDBjOW59YOsZ2lRBVtFsEEi48KhNQRb63/0ZSU3bA="
|
||||||
[mod."gitlab.com/gomidi/midi/v2"]
|
[mod."gitlab.com/gomidi/midi/v2"]
|
||||||
version = "v2.1.7"
|
version = "v2.3.16"
|
||||||
hash = "sha256-fbgxSMCk7PVII3sNEKuGWbN56fy3eM564Xb+lnYTxRQ="
|
hash = "sha256-o+6UtQH+TRSQlcX8J53esAA/b2c9e7BY7gcO5iSeOy0="
|
||||||
[mod."golang.org/x/exp"]
|
|
||||||
version = "v0.0.0-20190306152737-a1d7652674e8"
|
|
||||||
hash = "sha256-VJ0sxFsqnx2O/NmXamL2F5bQeUw5sizVQ7NLusceK5Q="
|
|
||||||
[mod."golang.org/x/image"]
|
[mod."golang.org/x/image"]
|
||||||
version = "v0.16.0"
|
version = "v0.32.0"
|
||||||
hash = "sha256-+BOLefaFM/c+AV3kmnNvztbhZ+a9GCNwkEya8hZSKYg="
|
hash = "sha256-a5C5nG4IKFkqM/EXjt29wzjrkYEFLKlg5C0aBnXnlZw="
|
||||||
[mod."golang.org/x/mobile"]
|
|
||||||
version = "v0.0.0-20190415191353-3e0bab5405d6"
|
|
||||||
hash = "sha256-Ds7JS9muxzDc7WgCncAd0rMSFeBI88/I0dQsk13/56k="
|
|
||||||
[mod."golang.org/x/net"]
|
[mod."golang.org/x/net"]
|
||||||
version = "v0.24.0"
|
version = "v0.46.0"
|
||||||
hash = "sha256-w1c21ljta5wNIyel9CSIn/crPzwOCRofNKhqmfs4aEQ="
|
hash = "sha256-GkAUXwqEJZF2t5dmxJVEE+t58EDzO24KtihqHqsrZH0="
|
||||||
[mod."golang.org/x/sys"]
|
[mod."golang.org/x/sys"]
|
||||||
version = "v0.20.0"
|
version = "v0.37.0"
|
||||||
hash = "sha256-mowlaoG2k4n1c1rApWef5EMiXd3I77CsUi8jPh6pTYA="
|
hash = "sha256-5aT0xP02sW1o9sfJHtWoGGNVYDdwb9FyiX/n6RAlzPo="
|
||||||
[mod."golang.org/x/text"]
|
[mod."golang.org/x/text"]
|
||||||
version = "v0.15.0"
|
version = "v0.30.0"
|
||||||
hash = "sha256-pBnj0AEkfkvZf+3bN7h6epCD2kurw59clDP7yWvxKlk="
|
hash = "sha256-VPT1Y2zzgdk+Q3Gx8hdwKdxbVh0/Zn/HwDpILCW3ZNA="
|
||||||
[mod."gopkg.in/yaml.v3"]
|
[mod."gopkg.in/yaml.v3"]
|
||||||
version = "v3.0.1"
|
version = "v3.0.1"
|
||||||
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="
|
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="
|
||||||
@ -258,11 +279,11 @@ schema = 3
|
|||||||
hash = "sha256-SJYYRaiDUmIbqy9l/IgiT/4VkFsPYsaslqGEowut34w="
|
hash = "sha256-SJYYRaiDUmIbqy9l/IgiT/4VkFsPYsaslqGEowut34w="
|
||||||
replaced = "github.com/fumiama/libc"
|
replaced = "github.com/fumiama/libc"
|
||||||
[mod."modernc.org/mathutil"]
|
[mod."modernc.org/mathutil"]
|
||||||
version = "v1.6.0"
|
version = "v1.7.1"
|
||||||
hash = "sha256-lfuEiS1odd2TWrTylnaGihSJ9myqKs3FLdpvd7PqTnE="
|
hash = "sha256-COZ5rF2GhQVR1r6a0DanJ8qwQ94JSKdQxTMWrDzE0Cc="
|
||||||
[mod."modernc.org/memory"]
|
[mod."modernc.org/memory"]
|
||||||
version = "v1.8.0"
|
version = "v1.11.0"
|
||||||
hash = "sha256-ucvPr73zg8LjvU+bcoIPKTgwgcon3U9VhKrLEMH81xg="
|
hash = "sha256-MkybF8vvrxXS5j7O8w3skwTo0aMo1yjWS0K440rYcHM="
|
||||||
[mod."modernc.org/sqlite"]
|
[mod."modernc.org/sqlite"]
|
||||||
version = "v1.29.10-simp"
|
version = "v1.29.10-simp"
|
||||||
hash = "sha256-HCUVN6gZDG0g2WIsQ4ksqE1+XR1IjxvnqEBEU2MO1eE="
|
hash = "sha256-HCUVN6gZDG0g2WIsQ4ksqE1+XR1IjxvnqEBEU2MO1eE="
|
||||||
|
|||||||
@ -3,13 +3,13 @@
|
|||||||
package banner
|
package banner
|
||||||
|
|
||||||
// Version ...
|
// Version ...
|
||||||
var Version = "v1.8.4"
|
var Version = "v1.10.0"
|
||||||
|
|
||||||
// Copyright ...
|
// Copyright ...
|
||||||
var Copyright = "© 2020 - 2024 FloatTech"
|
var Copyright = "© 2020 - 2025 FloatTech"
|
||||||
|
|
||||||
// Banner ...
|
// Banner ...
|
||||||
var Banner = "* OneBot + ZeroBot + Golang\n" +
|
var Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||||
"* Version " + Version + " - 2024-10-05 21:11:11 +0900 JST\n" +
|
"* Version " + Version + " - 2025-09-30 23:45:28 +0800 CST\n" +
|
||||||
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
|
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
|
||||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||||
|
|||||||
@ -27,7 +27,7 @@ var Banner = "* OneBot + ZeroBot + Golang\n" +
|
|||||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||||
`
|
`
|
||||||
|
|
||||||
const timeformat = `2006-01-02 15:04:05 +0900 JST`
|
const timeformat = `2006-01-02 15:04:05 +0800 CST`
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
f, err := os.Create("banner/banner.go")
|
f, err := os.Create("banner/banner.go")
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
//go:build go1.21
|
|
||||||
|
|
||||||
package kanban
|
|
||||||
|
|
||||||
const Error int = "请使用小于1.21版本的Go"
|
|
||||||
26
main.go
26
main.go
@ -1,6 +1,8 @@
|
|||||||
// Package main ZeroBot-Plugin main file
|
// Package main ZeroBot-Plugin main file
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
//go:generate go run github.com/FloatTech/ZeroBot-Plugin/abineundo/ref -r .
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
@ -12,8 +14,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/abineundo" // 设置插件优先级
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/console" // 更改控制台属性
|
_ "github.com/FloatTech/ZeroBot-Plugin/console" // 更改控制台属性
|
||||||
|
|
||||||
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 打印 banner
|
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 打印 banner
|
||||||
|
|
||||||
// ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- //
|
// ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- //
|
||||||
@ -38,6 +40,8 @@ import (
|
|||||||
|
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/sleepmanage" // 统计睡眠时间
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/sleepmanage" // 统计睡眠时间
|
||||||
|
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/airecord" // 群应用:AI声聊
|
||||||
|
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/atri" // ATRI词库
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/atri" // ATRI词库
|
||||||
|
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/manager" // 群管
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/manager" // 群管
|
||||||
@ -62,16 +66,21 @@ import (
|
|||||||
// vvvvvvvvvvvvvv //
|
// vvvvvvvvvvvvvv //
|
||||||
// vvvv //
|
// vvvv //
|
||||||
|
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/custom" // 自定义插件合集
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aifalse" // 服务器监控
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aifalse" // 服务器监控
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiimage" // AI画图
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/alipayvoice" // 支付宝到账语音
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/animetrace" // AnimeTrace 动画/Galgame识别
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/autowithdraw" // 触发者撤回时也自动撤回
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/autowithdraw" // 触发者撤回时也自动撤回
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit" // 百度内容审核
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit" // 百度内容审核
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base16384" // base16384加解密
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base16384" // base16384加解密
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibiliparse" // b站相关
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibilipush" // b站相关
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bookreview" // 哀伤雪刃吧推书记录
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bookreview" // 哀伤雪刃吧推书记录
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chess" // 国际象棋
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chess" // 国际象棋
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手
|
||||||
@ -79,6 +88,7 @@ import (
|
|||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chrev" // 英文字符翻转
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chrev" // 英文字符翻转
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/coser" // 三次元小姐姐
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/coser" // 三次元小姐姐
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cpstory" // cp短打
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cpstory" // cp短打
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/crypter" // 奇怪语言加解密
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dailynews" // 今日早报
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dailynews" // 今日早报
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/danbooru" // DeepDanbooru二次元图标签识别
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
|
||||||
@ -86,6 +96,7 @@ import (
|
|||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drawlots" // 多功能抽签
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drawlots" // 多功能抽签
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/driftbottle" // 漂流瓶
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/driftbottle" // 漂流瓶
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/emojimix" // 合成emoji
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/emojimix" // 合成emoji
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/emozi" // 颜文字抽象转写
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/event" // 好友申请群聊邀请事件处理
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/event" // 好友申请群聊邀请事件处理
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/font" // 渲染任意文字到图片
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/font" // 渲染任意文字到图片
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/fortune" // 运势
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/fortune" // 运势
|
||||||
@ -106,7 +117,8 @@ import (
|
|||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/magicprompt" // magicprompt吟唱提示
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/magicprompt" // magicprompt吟唱提示
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/mcfish" // 钓鱼模拟器
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/mcfish" // 钓鱼模拟器
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/midicreate" // 简易midi音乐制作
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/midicreate" // 简易midi音乐制作
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moegoe" // 日韩 VITS 模型拟声
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/minecraftobserver" // Minecraft服务器监控&订阅
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/movies" // 电影插件
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu" // 摸鱼
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyu" // 摸鱼
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyucalendar" // 摸鱼人日历
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/moyucalendar" // 摸鱼人日历
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/music" // 点歌
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/music" // 点歌
|
||||||
@ -124,6 +136,7 @@ import (
|
|||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/robbery" // 打劫群友的ATRI币
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/robbery" // 打劫群友的ATRI币
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/rsshub" // RSSHub订阅姬
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/runcode" // 在线运行代码
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜图
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/saucenao" // 以图搜图
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数
|
||||||
@ -135,15 +148,14 @@ import (
|
|||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/translation" // 翻译
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/translation" // 翻译
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru" // vits猫雷
|
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wantquotes" // 据意查句
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wantquotes" // 据意查句
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinvilg" // 百度文心AI画图
|
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wife" // 抽老婆
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wife" // 抽老婆
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordcount" // 聊天热词
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordcount" // 聊天热词
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordle" // 猜单词
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygo" // 游戏王相关插件
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygocdb" // 游戏王白鸽API卡查
|
||||||
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygotrade" // 游戏王集换社卡价查询
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ymgal" // 月幕galgame
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/yujn" // 遇见API
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/yujn" // 遇见API
|
||||||
|
|
||||||
@ -167,9 +179,9 @@ import (
|
|||||||
// vvvvvvvvvvvvvv //
|
// vvvvvvvvvvvvvv //
|
||||||
// vvvv //
|
// vvvv //
|
||||||
|
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/curse" // 骂人
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aichat" // AI聊天
|
||||||
|
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aireply" // 人工智能回复
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/curse" // 骂人
|
||||||
|
|
||||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复
|
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复
|
||||||
|
|
||||||
|
|||||||
302
plugin/aichat/cfg.go
Normal file
302
plugin/aichat/cfg.go
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
package aichat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/chat"
|
||||||
|
"github.com/fumiama/deepinfra"
|
||||||
|
"github.com/fumiama/deepinfra/model"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
cfg = newconfig()
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
apitypes = map[string]uint8{
|
||||||
|
"OpenAI": 0,
|
||||||
|
"OLLaMA": 1,
|
||||||
|
"GenAI": 2,
|
||||||
|
}
|
||||||
|
apilist = [3]string{"OpenAI", "OLLaMA", "GenAI"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModelType 支持打印 string 并生产 protocal
|
||||||
|
type ModelType int
|
||||||
|
|
||||||
|
func newModelType(typ string) (ModelType, error) {
|
||||||
|
t, ok := apitypes[typ]
|
||||||
|
if !ok {
|
||||||
|
return 0, errors.New("未知类型 " + typ)
|
||||||
|
}
|
||||||
|
return ModelType(t), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mt ModelType) String() string {
|
||||||
|
return apilist[mt]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mt ModelType) protocol(modn string, temp float32, topp float32, maxn uint) (mod model.Protocol, err error) {
|
||||||
|
switch cfg.Type {
|
||||||
|
case 0:
|
||||||
|
mod = model.NewOpenAI(
|
||||||
|
modn, cfg.Separator,
|
||||||
|
temp, topp, maxn,
|
||||||
|
)
|
||||||
|
case 1:
|
||||||
|
mod = model.NewOLLaMA(
|
||||||
|
modn, cfg.Separator,
|
||||||
|
temp, topp, maxn,
|
||||||
|
)
|
||||||
|
case 2:
|
||||||
|
mod = model.NewGenAI(
|
||||||
|
modn,
|
||||||
|
temp, topp, maxn,
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
err = errors.New("unsupported model type " + strconv.Itoa(int(cfg.Type)))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelBool 支持打印成 "是/否"
|
||||||
|
type ModelBool bool
|
||||||
|
|
||||||
|
func (mb ModelBool) String() string {
|
||||||
|
if mb {
|
||||||
|
return "是"
|
||||||
|
}
|
||||||
|
return "否"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelKey 支持隐藏密钥
|
||||||
|
type ModelKey string
|
||||||
|
|
||||||
|
func (mk ModelKey) String() string {
|
||||||
|
if len(mk) == 0 {
|
||||||
|
return "未设置"
|
||||||
|
}
|
||||||
|
if len(mk) <= 4 {
|
||||||
|
return "****"
|
||||||
|
}
|
||||||
|
key := string(mk)
|
||||||
|
return key[:2] + strings.Repeat("*", len(key)-4) + key[len(key)-2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
type config struct {
|
||||||
|
ModelName string
|
||||||
|
ImageModelName string
|
||||||
|
AgentModelName string
|
||||||
|
Type ModelType
|
||||||
|
ImageType ModelType
|
||||||
|
AgentType ModelType
|
||||||
|
MaxN uint
|
||||||
|
TopP float32
|
||||||
|
SystemP string
|
||||||
|
API string
|
||||||
|
ImageAPI string
|
||||||
|
AgentAPI string
|
||||||
|
Key ModelKey
|
||||||
|
ImageKey ModelKey
|
||||||
|
AgentKey ModelKey
|
||||||
|
Separator string
|
||||||
|
NoSystemP ModelBool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newconfig() config {
|
||||||
|
return config{
|
||||||
|
ModelName: model.ModelDeepDeek,
|
||||||
|
SystemP: chat.SystemPrompt,
|
||||||
|
API: deepinfra.OpenAIDeepInfra,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *config) String() string {
|
||||||
|
topp, maxn := c.mparams()
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.WriteString(fmt.Sprintf("• 模型名:%s\n", c.ModelName))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 图像模型名:%s\n", c.ImageModelName))
|
||||||
|
sb.WriteString(fmt.Sprintf("• Agent模型名:%s\n", c.AgentModelName))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 接口类型:%v\n", c.Type))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 图像接口类型:%v\n", c.ImageType))
|
||||||
|
sb.WriteString(fmt.Sprintf("• Agent接口类型:%v\n", c.AgentType))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 最大长度:%d\n", maxn))
|
||||||
|
sb.WriteString(fmt.Sprintf("• TopP:%.1f\n", topp))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 系统提示词:%s\n", c.SystemP))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 接口地址:%s\n", c.API))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 图像接口地址:%s\n", c.ImageAPI))
|
||||||
|
sb.WriteString(fmt.Sprintf("• Agent接口地址:%s\n", c.AgentAPI))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 密钥:%v\n", c.Key))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 图像密钥:%v\n", c.ImageKey))
|
||||||
|
sb.WriteString(fmt.Sprintf("• Agent密钥:%v\n", c.AgentKey))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 分隔符:%s\n", c.Separator))
|
||||||
|
sb.WriteString(fmt.Sprintf("• 支持系统提示词:%v\n", !c.NoSystemP))
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *config) isvalid() bool {
|
||||||
|
return c.ModelName != "" && c.API != "" && c.Key != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取全局模型参数:TopP和最大长度
|
||||||
|
func (c *config) mparams() (topp float32, maxn uint) {
|
||||||
|
// 处理TopP参数
|
||||||
|
topp = c.TopP
|
||||||
|
if topp == 0 {
|
||||||
|
topp = 0.9
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理最大长度参数
|
||||||
|
maxn = c.MaxN
|
||||||
|
if maxn == 0 {
|
||||||
|
maxn = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
return topp, maxn
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureconfig(ctx *zero.Ctx) bool {
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !cfg.isvalid() {
|
||||||
|
err := c.GetExtra(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln("ERROR: get extra err:", err)
|
||||||
|
}
|
||||||
|
if !cfg.isvalid() {
|
||||||
|
cfg = newconfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func newextrasetstr[T ~string](ptr *T) func(ctx *zero.Ctx) {
|
||||||
|
return func(ctx *zero.Ctx) {
|
||||||
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
if args == "" {
|
||||||
|
ctx.SendChain(message.Text("ERROR: empty args"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*ptr = T(args)
|
||||||
|
err := c.SetExtra(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newextrasetbool[T ~bool](ptr *T) func(ctx *zero.Ctx) {
|
||||||
|
return func(ctx *zero.Ctx) {
|
||||||
|
args := ctx.State["regex_matched"].([]string)
|
||||||
|
isno := args[1] == "不"
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*ptr = T(isno)
|
||||||
|
err := c.SetExtra(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newextrasetuint(ptr *uint) func(ctx *zero.Ctx) {
|
||||||
|
return func(ctx *zero.Ctx) {
|
||||||
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
if args == "" {
|
||||||
|
ctx.SendChain(message.Text("ERROR: empty args"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, err := strconv.ParseUint(args, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: parse args err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*ptr = uint(n)
|
||||||
|
err = c.SetExtra(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newextrasetfloat32(ptr *float32) func(ctx *zero.Ctx) {
|
||||||
|
return func(ctx *zero.Ctx) {
|
||||||
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
if args == "" {
|
||||||
|
ctx.SendChain(message.Text("ERROR: empty args"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n, err := strconv.ParseFloat(args, 32)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: parse args err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*ptr = float32(n)
|
||||||
|
err = c.SetExtra(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newextrasetmodeltype(ptr *ModelType) func(ctx *zero.Ctx) {
|
||||||
|
return func(ctx *zero.Ctx) {
|
||||||
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
if args == "" {
|
||||||
|
ctx.SendChain(message.Text("ERROR: empty args"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
typ, err := newModelType(args)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*ptr = typ
|
||||||
|
err = c.SetExtra(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
}
|
||||||
|
}
|
||||||
487
plugin/aichat/main.go
Normal file
487
plugin/aichat/main.go
Normal file
@ -0,0 +1,487 @@
|
|||||||
|
// Package aichat OpenAI聊天和群聊总结
|
||||||
|
package aichat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fumiama/deepinfra"
|
||||||
|
"github.com/fumiama/deepinfra/model"
|
||||||
|
goba "github.com/fumiama/go-onebot-agent"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
|
"github.com/FloatTech/AnimeAPI/airecord"
|
||||||
|
"github.com/FloatTech/floatbox/process"
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/chat"
|
||||||
|
"github.com/FloatTech/zbputils/control"
|
||||||
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// en data [8 temp] [8 rate] LSB
|
||||||
|
en = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
|
DisableOnDefault: false,
|
||||||
|
Extra: control.ExtraFromString("aichat"),
|
||||||
|
Brief: "OpenAI聊天",
|
||||||
|
Help: "- 设置AI聊天触发概率10\n" +
|
||||||
|
"- 设置AI聊天温度80\n" +
|
||||||
|
"- 设置AI聊天(识图|Agent)接口类型[OpenAI|OLLaMA|GenAI]\n" +
|
||||||
|
"- 设置AI聊天(不)使用Agent模式\n" +
|
||||||
|
"- 设置AI聊天(不)支持系统提示词\n" +
|
||||||
|
"- 设置AI聊天(识图|Agent)接口地址https://api.siliconflow.cn/v1/chat/completions\n" +
|
||||||
|
"- 设置AI聊天(识图|Agent)密钥xxx\n" +
|
||||||
|
"- 设置AI聊天(识图|Agent)模型名Qwen/Qwen3-8B\n" +
|
||||||
|
"- 查看AI聊天系统提示词\n" +
|
||||||
|
"- 重置AI聊天系统提示词\n" +
|
||||||
|
"- 设置AI聊天系统提示词xxx\n" +
|
||||||
|
"- 设置AI聊天分隔符</think>(留空则清除)\n" +
|
||||||
|
"- 设置AI聊天(不)响应AT\n" +
|
||||||
|
"- 设置AI聊天最大长度4096\n" +
|
||||||
|
"- 设置AI聊天TopP 0.9\n" +
|
||||||
|
"- 设置AI聊天(不)以AI语音输出\n" +
|
||||||
|
"- 查看AI聊天配置\n" +
|
||||||
|
"- 重置AI聊天\n" +
|
||||||
|
"- 群聊总结 [消息数目]|群聊总结 1000\n" +
|
||||||
|
"- /gpt [内容] (使用大模型聊天)\n",
|
||||||
|
|
||||||
|
PrivateDataFolder: "aichat",
|
||||||
|
}).ApplySingle(single.New(
|
||||||
|
single.WithKeyFn(func(ctx *zero.Ctx) int64 {
|
||||||
|
if ctx.Event.GroupID == 0 {
|
||||||
|
return -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
return ctx.Event.GroupID
|
||||||
|
}),
|
||||||
|
// no post option, silently quit
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
limit = ctxext.NewLimiterManager(time.Second*30, 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
en.OnMessage(ensureconfig, func(ctx *zero.Ctx) bool {
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
if gid == 0 {
|
||||||
|
gid = -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
stor, err := newstorage(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln("ERROR: ", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ctx.State["__aichat_stor__"] = stor
|
||||||
|
return ctx.ExtractPlainText() != "" &&
|
||||||
|
(!stor.noreplyat() || (stor.noreplyat() && !ctx.Event.IsToMe))
|
||||||
|
}).SetBlock(false).Handle(func(ctx *zero.Ctx) {
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
if gid == 0 {
|
||||||
|
gid = -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
stor := ctx.State["__aichat_stor__"].(storage)
|
||||||
|
rate := stor.rate()
|
||||||
|
if !ctx.Event.IsToMe && rand.Intn(100) >= int(rate) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ctx.Event.IsToMe {
|
||||||
|
ctx.Block()
|
||||||
|
}
|
||||||
|
if cfg.Key == "" {
|
||||||
|
logrus.Warnln("ERROR: get extra err: empty key")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
temperature := stor.temp()
|
||||||
|
topp, maxn := cfg.mparams()
|
||||||
|
|
||||||
|
if !stor.noagent() && cfg.AgentAPI != "" && cfg.AgentModelName != "" {
|
||||||
|
x := deepinfra.NewAPI(cfg.AgentAPI, string(cfg.AgentKey))
|
||||||
|
mod, err := cfg.Type.protocol(cfg.AgentModelName, temperature, topp, maxn)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln("ERROR: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
role := goba.PermRoleUser
|
||||||
|
if zero.AdminPermission(ctx) {
|
||||||
|
role = goba.PermRoleAdmin
|
||||||
|
if zero.SuperUserPermission(ctx) {
|
||||||
|
role = goba.PermRoleOwner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ag := chat.AgentOf(ctx.Event.SelfID)
|
||||||
|
if cfg.ImageAPI != "" && !ag.CanViewImage() {
|
||||||
|
mod, err := cfg.ImageType.protocol(cfg.ImageModelName, temperature, topp, maxn)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln("ERROR: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ag.SetViewImageAPI(deepinfra.NewAPI(cfg.ImageAPI, string(cfg.ImageKey)), mod)
|
||||||
|
}
|
||||||
|
ctx.NoTimeout()
|
||||||
|
hasresp := false
|
||||||
|
for i := 0; i < 8; i++ { // 最大运行 8 轮因为问答上下文只有 16
|
||||||
|
reqs := chat.CallAgent(ag, zero.SuperUserPermission(ctx), x, mod, gid, role)
|
||||||
|
if len(reqs) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
hasresp = true
|
||||||
|
for _, req := range reqs {
|
||||||
|
resp := ctx.CallAction(req.Action, req.Params)
|
||||||
|
logrus.Infoln("[aichat] agent get resp:", reqs)
|
||||||
|
ag.AddResponse(gid, &goba.APIResponse{
|
||||||
|
Status: resp.Status,
|
||||||
|
Data: json.RawMessage(resp.Data.Raw),
|
||||||
|
Message: resp.Message,
|
||||||
|
Wording: resp.Wording,
|
||||||
|
RetCode: resp.RetCode,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasresp {
|
||||||
|
ag.AddTerminus(gid)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// no response, fall back to normal chat
|
||||||
|
}
|
||||||
|
|
||||||
|
x := deepinfra.NewAPI(cfg.API, string(cfg.Key))
|
||||||
|
mod, err := cfg.Type.protocol(cfg.ModelName, temperature, topp, maxn)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln("ERROR: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := x.Request(chat.GetChatContext(mod, gid, cfg.SystemP, bool(cfg.NoSystemP)))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln("[aichat] post err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
txt := chat.Sanitize(strings.Trim(data, "\n "))
|
||||||
|
if len(txt) > 0 {
|
||||||
|
chat.AddChatReply(gid, txt)
|
||||||
|
nick := zero.BotConfig.NickName[rand.Intn(len(zero.BotConfig.NickName))]
|
||||||
|
txt = strings.ReplaceAll(txt, "{name}", ctx.CardOrNickName(ctx.Event.UserID))
|
||||||
|
txt = strings.ReplaceAll(txt, "{me}", nick)
|
||||||
|
id := any(nil)
|
||||||
|
if ctx.Event.IsToMe {
|
||||||
|
id = ctx.Event.MessageID
|
||||||
|
}
|
||||||
|
for _, t := range strings.Split(txt, "{segment}") {
|
||||||
|
if t == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logrus.Infoln("[aichat] 回复内容:", t)
|
||||||
|
recCfg := airecord.GetConfig()
|
||||||
|
record := ""
|
||||||
|
if !stor.norecord() {
|
||||||
|
record = ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, t)
|
||||||
|
}
|
||||||
|
if record != "" {
|
||||||
|
ctx.SendChain(message.Record(record))
|
||||||
|
} else {
|
||||||
|
if id != nil {
|
||||||
|
id = ctx.SendChain(message.Reply(id), message.Text(t))
|
||||||
|
} else {
|
||||||
|
id = ctx.SendChain(message.Text(t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
process.SleepAbout1sTo2s()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
en.OnPrefix("设置AI聊天触发概率", zero.AdminPermission).SetBlock(true).
|
||||||
|
Handle(ctxext.NewStorageSaveBitmapHandler(bitmaprate, 0, 100))
|
||||||
|
en.OnPrefix("设置AI聊天温度", zero.AdminPermission).SetBlock(true).
|
||||||
|
Handle(ctxext.NewStorageSaveBitmapHandler(bitmaptemp, 0, 100))
|
||||||
|
en.OnPrefix("设置AI聊天接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetmodeltype(&cfg.Type))
|
||||||
|
en.OnPrefix("设置AI聊天识图接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetmodeltype(&cfg.ImageType))
|
||||||
|
en.OnPrefix("设置AI聊天Agent接口类型", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetmodeltype(&cfg.AgentType))
|
||||||
|
en.OnPrefix("设置AI聊天接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.API))
|
||||||
|
en.OnPrefix("设置AI聊天识图接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.ImageAPI))
|
||||||
|
en.OnPrefix("设置AI聊天Agent接口地址", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.AgentAPI))
|
||||||
|
en.OnPrefix("设置AI聊天密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.Key))
|
||||||
|
en.OnPrefix("设置AI聊天识图密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.ImageKey))
|
||||||
|
en.OnPrefix("设置AI聊天Agent密钥", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.AgentKey))
|
||||||
|
en.OnPrefix("设置AI聊天模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.ModelName))
|
||||||
|
en.OnPrefix("设置AI聊天识图模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.ImageModelName))
|
||||||
|
en.OnPrefix("设置AI聊天Agent模型名", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.AgentModelName))
|
||||||
|
en.OnPrefix("设置AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.SystemP))
|
||||||
|
en.OnFullMatch("查看AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
ctx.SendChain(message.Text(cfg.SystemP))
|
||||||
|
})
|
||||||
|
en.OnFullMatch("重置AI聊天系统提示词", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
ctx.SendChain(message.Text("ERROR: no such plugin"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg.SystemP = chat.SystemPrompt
|
||||||
|
err := c.SetExtra(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
})
|
||||||
|
en.OnPrefix("设置AI聊天分隔符", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetstr(&cfg.Separator))
|
||||||
|
en.OnRegex("^设置AI聊天(不)?响应AT$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(ctxext.NewStorageSaveBoolHandler(bitmapnrat))
|
||||||
|
en.OnRegex("^设置AI聊天(不)?支持系统提示词$", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetbool(&cfg.NoSystemP))
|
||||||
|
en.OnRegex("^设置AI聊天(不)?使用Agent模式$", ensureconfig, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(ctxext.NewStorageSaveBoolHandler(bitmapnagt))
|
||||||
|
en.OnPrefix("设置AI聊天最大长度", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetuint(&cfg.MaxN))
|
||||||
|
en.OnPrefix("设置AI聊天TopP", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(newextrasetfloat32(&cfg.TopP))
|
||||||
|
en.OnRegex("^设置AI聊天(不)?以AI语音输出$", ensureconfig, zero.AdminPermission).SetBlock(true).
|
||||||
|
Handle(ctxext.NewStorageSaveBoolHandler(bitmapnrec))
|
||||||
|
en.OnFullMatch("查看AI聊天配置", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
stor, err := newstorage(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(
|
||||||
|
message.Text(
|
||||||
|
"【当前AI聊天本群配置】\n",
|
||||||
|
"• 触发概率:", int(stor.rate()), "\n",
|
||||||
|
"• 温度:", stor.temp(), "\n",
|
||||||
|
"• 以AI语音输出:", ModelBool(!stor.norecord()), "\n",
|
||||||
|
"• 使用Agent:", ModelBool(!stor.noagent()), "\n",
|
||||||
|
"• 响应@:", ModelBool(!stor.noreplyat()), "\n",
|
||||||
|
),
|
||||||
|
message.Text("【当前AI聊天全局配置】\n", &cfg),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
en.OnFullMatch("重置AI聊天", ensureconfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
chat.ResetChat()
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加群聊总结功能
|
||||||
|
en.OnRegex(`^群聊总结\s?(\d*)$`, ensureconfig, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(limit.LimitByGroup).Handle(func(ctx *zero.Ctx) {
|
||||||
|
ctx.SendChain(message.Text("少女思考中..."))
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
if gid == 0 {
|
||||||
|
gid = -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
p, _ := strconv.ParseInt(ctx.State["regex_matched"].([]string)[1], 10, 64)
|
||||||
|
if p > 1000 {
|
||||||
|
p = 1000
|
||||||
|
}
|
||||||
|
if p == 0 {
|
||||||
|
p = 200
|
||||||
|
}
|
||||||
|
group := ctx.GetGroupInfo(gid, false)
|
||||||
|
if group.MemberCount == 0 {
|
||||||
|
ctx.SendChain(message.Text(zero.BotConfig.NickName[0], "未加入", group.Name, "(", gid, "),无法获取总结"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages []string
|
||||||
|
|
||||||
|
h := ctx.GetGroupMessageHistory(gid, 0, p, false)
|
||||||
|
h.Get("messages").ForEach(func(_, msgObj gjson.Result) bool {
|
||||||
|
nickname := msgObj.Get("sender.nickname").Str
|
||||||
|
text := strings.TrimSpace(message.ParseMessageFromString(msgObj.Get("raw_message").Str).ExtractPlainText())
|
||||||
|
if text != "" {
|
||||||
|
messages = append(messages, nickname+": "+text)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(messages) == 0 {
|
||||||
|
ctx.SendChain(message.Text("ERROR: 历史消息为空或者无法获得历史消息"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造总结请求提示 (使用通用版省流提示词)
|
||||||
|
// 使用反引号定义多行字符串,更清晰
|
||||||
|
promptTemplate := `请对以下群聊对话进行【极简总结】。
|
||||||
|
要求:
|
||||||
|
1. 剔除客套与废话,直击主题。
|
||||||
|
2. 使用 Markdown 列表格式。
|
||||||
|
3. 按以下结构输出:
|
||||||
|
- 🎯 核心议题:(一句话概括)
|
||||||
|
- 💡 关键观点/结论:(提取3-5个重点)
|
||||||
|
- ✅ 下一步/待办:(如果有,明确谁做什么)
|
||||||
|
|
||||||
|
群聊对话内容如下:
|
||||||
|
`
|
||||||
|
summaryPrompt := promptTemplate + strings.Join(messages, "\n")
|
||||||
|
|
||||||
|
stor, err := newstorage(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 调用大模型API进行总结
|
||||||
|
summary, err := llmchat(summaryPrompt, stor.temp())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var b strings.Builder
|
||||||
|
b.WriteString("群 ")
|
||||||
|
b.WriteString(group.Name)
|
||||||
|
b.WriteByte('(')
|
||||||
|
b.WriteString(strconv.FormatInt(gid, 10))
|
||||||
|
b.WriteString(") 的 ")
|
||||||
|
b.WriteString(strconv.FormatInt(p, 10))
|
||||||
|
b.WriteString(" 条消息总结:\n\n")
|
||||||
|
b.WriteString(summary)
|
||||||
|
|
||||||
|
// 分割总结内容为多段(按1000字符长度切割)
|
||||||
|
summaryText := b.String()
|
||||||
|
msg := make(message.Message, 0)
|
||||||
|
for len(summaryText) > 0 {
|
||||||
|
if len(summaryText) <= 1000 {
|
||||||
|
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text(summaryText)))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找1000字符内的最后一个换行符,尽量在换行处分割
|
||||||
|
chunk := summaryText[:1000]
|
||||||
|
lastNewline := strings.LastIndex(chunk, "\n")
|
||||||
|
if lastNewline > 0 {
|
||||||
|
chunk = summaryText[:lastNewline+1]
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text(chunk)))
|
||||||
|
summaryText = summaryText[len(chunk):]
|
||||||
|
}
|
||||||
|
if len(msg) > 0 {
|
||||||
|
ctx.Send(msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加 /gpt 命令处理(同时支持回复消息和直接使用)
|
||||||
|
en.OnKeyword("/gpt", ensureconfig).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
if gid == 0 {
|
||||||
|
gid = -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
text := ctx.MessageString()
|
||||||
|
|
||||||
|
var query string
|
||||||
|
var replyContent string
|
||||||
|
|
||||||
|
// 检查是否是回复消息 (使用MessageElement检查而不是CQ码)
|
||||||
|
for _, elem := range ctx.Event.Message {
|
||||||
|
if elem.Type == "reply" {
|
||||||
|
// 提取被回复的消息ID
|
||||||
|
replyIDStr := elem.Data["id"]
|
||||||
|
replyID, err := strconv.ParseInt(replyIDStr, 10, 64)
|
||||||
|
if err == nil {
|
||||||
|
// 获取被回复的消息内容
|
||||||
|
replyMsg := ctx.GetMessage(replyID)
|
||||||
|
if replyMsg.Elements != nil {
|
||||||
|
replyContent = replyMsg.Elements.ExtractPlainText()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break // 找到回复元素后退出循环
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取 /gpt 后面的内容
|
||||||
|
parts := strings.SplitN(text, "/gpt", 2)
|
||||||
|
|
||||||
|
var gContent string
|
||||||
|
if len(parts) > 1 {
|
||||||
|
gContent = strings.TrimSpace(parts[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组合内容:优先使用回复内容,如果同时有/gpt内容则拼接
|
||||||
|
switch {
|
||||||
|
case replyContent != "" && gContent != "":
|
||||||
|
query = replyContent + "\n" + gContent
|
||||||
|
case replyContent != "":
|
||||||
|
query = replyContent
|
||||||
|
case gContent != "":
|
||||||
|
query = gContent
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
stor, err := newstorage(ctx, gid)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 调用大模型API进行聊天
|
||||||
|
reply, err := llmchat(query, stor.temp())
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分割总结内容为多段(按1000字符长度切割)
|
||||||
|
msg := make(message.Message, 0)
|
||||||
|
for len(reply) > 0 {
|
||||||
|
if len(reply) <= 1000 {
|
||||||
|
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text(reply)))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找1000字符内的最后一个换行符,尽量在换行处分割
|
||||||
|
chunk := reply[:1000]
|
||||||
|
lastNewline := strings.LastIndex(chunk, "\n")
|
||||||
|
if lastNewline > 0 {
|
||||||
|
chunk = reply[:lastNewline+1]
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text(chunk)))
|
||||||
|
reply = reply[len(chunk):]
|
||||||
|
}
|
||||||
|
if len(msg) > 0 {
|
||||||
|
ctx.Send(msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// llmchat 调用大模型API包装
|
||||||
|
func llmchat(prompt string, temp float32) (string, error) {
|
||||||
|
topp, maxn := cfg.mparams()
|
||||||
|
|
||||||
|
x := deepinfra.NewAPI(cfg.API, string(cfg.Key))
|
||||||
|
|
||||||
|
mod, err := cfg.Type.protocol(cfg.ModelName, temp, topp, maxn)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := x.Request(mod.User(model.NewContentText(prompt)))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(data), nil
|
||||||
|
}
|
||||||
49
plugin/aichat/storage.go
Normal file
49
plugin/aichat/storage.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package aichat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
bitmaprate = 0x0000ff
|
||||||
|
bitmaptemp = 0x00ff00
|
||||||
|
bitmapnagt = 0x010000
|
||||||
|
bitmapnrec = 0x020000
|
||||||
|
bitmapnrat = 0x040000
|
||||||
|
)
|
||||||
|
|
||||||
|
type storage ctxext.Storage
|
||||||
|
|
||||||
|
func newstorage(ctx *zero.Ctx, gid int64) (storage, error) {
|
||||||
|
s, err := ctxext.NewStorage(ctx, gid)
|
||||||
|
return storage(s), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) rate() uint8 {
|
||||||
|
return uint8((ctxext.Storage)(s).Get(bitmaprate))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) temp() float32 {
|
||||||
|
temp := int8((ctxext.Storage)(s).Get(bitmaptemp))
|
||||||
|
// 处理温度参数
|
||||||
|
if temp <= 0 {
|
||||||
|
temp = 70 // default setting
|
||||||
|
}
|
||||||
|
if temp > 100 {
|
||||||
|
temp = 100
|
||||||
|
}
|
||||||
|
return float32(temp) / 100
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) noagent() bool {
|
||||||
|
return (ctxext.Storage)(s).GetBool(bitmapnagt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) norecord() bool {
|
||||||
|
return (ctxext.Storage)(s).GetBool(bitmapnrec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s storage) noreplyat() bool {
|
||||||
|
return (ctxext.Storage)(s).GetBool(bitmapnrat)
|
||||||
|
}
|
||||||
149
plugin/aichat/storage_test.go
Normal file
149
plugin/aichat/storage_test.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package aichat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStorage_rate(t *testing.T) {
|
||||||
|
s := storage(ctxext.Storage(0))
|
||||||
|
|
||||||
|
// 测试默认值
|
||||||
|
if rate := s.rate(); rate != 0 {
|
||||||
|
t.Errorf("default rate() = %v, want 0", rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置值并测试
|
||||||
|
s = storage((ctxext.Storage)(s).Set(int64(100), bitmaprate))
|
||||||
|
if rate := s.rate(); rate != 100 {
|
||||||
|
t.Errorf("rate() after set = %v, want 100", rate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStorage_temp(t *testing.T) {
|
||||||
|
s := storage(ctxext.Storage(0))
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
setValue int64
|
||||||
|
expected float32
|
||||||
|
}{
|
||||||
|
{"default temp (0)", 0, 0.70}, // 默认值 70/100
|
||||||
|
{"valid temp 50", 50, 0.50}, // 50/100 = 0.50
|
||||||
|
{"valid temp 80", 80, 0.80}, // 80/100 = 0.80
|
||||||
|
{"max temp 100", 100, 1.00}, // 100/100 = 1.00
|
||||||
|
{"over max temp", 127, 1.00}, // 限制为 100/100 = 1.00
|
||||||
|
{"negative temp", -10, 0.70}, // 默认值 70/100
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
s = storage((ctxext.Storage)(s).Set(tt.setValue, bitmaptemp))
|
||||||
|
|
||||||
|
result := s.temp()
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("temp() = %v, want %v", result, tt.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStorage_noagent(t *testing.T) {
|
||||||
|
s := storage(ctxext.Storage(0))
|
||||||
|
|
||||||
|
// 测试默认值
|
||||||
|
if noagent := s.noagent(); noagent != false {
|
||||||
|
t.Errorf("default noagent() = %v, want false", noagent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置为 true 并测试
|
||||||
|
s = storage((ctxext.Storage)(s).Set(1, bitmapnagt))
|
||||||
|
if noagent := s.noagent(); noagent != true {
|
||||||
|
t.Errorf("noagent() after set true = %v, want true", noagent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStorage_norecord(t *testing.T) {
|
||||||
|
s := storage(ctxext.Storage(0))
|
||||||
|
|
||||||
|
// 测试默认值
|
||||||
|
if norecord := s.norecord(); norecord != false {
|
||||||
|
t.Errorf("default norecord() = %v, want false", norecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置为 true 并测试
|
||||||
|
s = storage((ctxext.Storage)(s).Set(1, bitmapnrec))
|
||||||
|
if norecord := s.norecord(); norecord != true {
|
||||||
|
t.Errorf("norecord() after set true = %v, want true", norecord)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStorage_noreplyat(t *testing.T) {
|
||||||
|
s := storage(ctxext.Storage(0))
|
||||||
|
|
||||||
|
// 测试默认值
|
||||||
|
if noreplyat := s.noreplyat(); noreplyat != false {
|
||||||
|
t.Errorf("default noreplyat() = %v, want false", noreplyat)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置为 true 并测试
|
||||||
|
s = storage((ctxext.Storage)(s).Set(1, bitmapnrat))
|
||||||
|
if noreplyat := s.noreplyat(); noreplyat != true {
|
||||||
|
t.Errorf("noreplyat() after set true = %v, want true", noreplyat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStorage_Integration(t *testing.T) {
|
||||||
|
s := storage(ctxext.Storage(0))
|
||||||
|
|
||||||
|
// 设置各种值
|
||||||
|
s = storage((ctxext.Storage)(s).Set(int64(75), bitmaprate))
|
||||||
|
s = storage((ctxext.Storage)(s).Set(int64(85), bitmaptemp))
|
||||||
|
s = storage((ctxext.Storage)(s).Set(1, bitmapnagt))
|
||||||
|
s = storage((ctxext.Storage)(s).Set(0, bitmapnrec))
|
||||||
|
s = storage((ctxext.Storage)(s).Set(1, bitmapnrat))
|
||||||
|
|
||||||
|
// 验证所有方法
|
||||||
|
if rate := s.rate(); rate != 75 {
|
||||||
|
t.Errorf("rate() = %v, want 75", rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if temp := s.temp(); temp != 0.85 {
|
||||||
|
t.Errorf("temp() = %v, want 0.85", temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if noagent := s.noagent(); !noagent {
|
||||||
|
t.Errorf("noagent() = %v, want true", noagent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if norecord := s.norecord(); norecord {
|
||||||
|
t.Errorf("norecord() = %v, want false", norecord)
|
||||||
|
}
|
||||||
|
|
||||||
|
if noreplyat := s.noreplyat(); !noreplyat {
|
||||||
|
t.Errorf("noreplyat() = %v, want true", noreplyat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkStorage_rate(b *testing.B) {
|
||||||
|
s := storage(ctxext.Storage(0))
|
||||||
|
|
||||||
|
s = storage((ctxext.Storage)(s).Set(int64(100), bitmaprate))
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
s.rate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkStorage_temp(b *testing.B) {
|
||||||
|
s := storage(ctxext.Storage(0))
|
||||||
|
|
||||||
|
s = storage((ctxext.Storage)(s).Set(int64(80), bitmaptemp))
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
s.temp()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,16 +20,15 @@ import (
|
|||||||
"github.com/FloatTech/floatbox/web"
|
"github.com/FloatTech/floatbox/web"
|
||||||
"github.com/FloatTech/gg"
|
"github.com/FloatTech/gg"
|
||||||
"github.com/FloatTech/imgfactory"
|
"github.com/FloatTech/imgfactory"
|
||||||
"github.com/FloatTech/rendercard"
|
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
"github.com/FloatTech/zbputils/img/text"
|
"github.com/FloatTech/zbputils/img/text"
|
||||||
"github.com/disintegration/imaging"
|
"github.com/disintegration/imaging"
|
||||||
"github.com/shirou/gopsutil/v3/cpu"
|
"github.com/shirou/gopsutil/v4/cpu"
|
||||||
"github.com/shirou/gopsutil/v3/disk"
|
"github.com/shirou/gopsutil/v4/disk"
|
||||||
"github.com/shirou/gopsutil/v3/host"
|
"github.com/shirou/gopsutil/v4/host"
|
||||||
"github.com/shirou/gopsutil/v3/mem"
|
"github.com/shirou/gopsutil/v4/mem"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"golang.org/x/text/cases"
|
"golang.org/x/text/cases"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
@ -41,7 +40,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
backgroundURL = "https://iw233.cn/api.php?sort=mp"
|
backgroundURL = "https://pic.re/image"
|
||||||
referer = "https://weibo.com/"
|
referer = "https://weibo.com/"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -237,14 +236,17 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string, botrunsta
|
|||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
titlecard := gg.NewContext(cardw, titlecardh)
|
titlecard := gg.NewContext(cardw, titlecardh)
|
||||||
bwg.Wait()
|
bwg.Wait()
|
||||||
titlecard.DrawImage(blurback, -70, -70)
|
|
||||||
|
|
||||||
titlecard.DrawRoundedRectangle(1, 1, float64(titlecard.W()-1*2), float64(titlecardh-1*2), 16)
|
titlecard.DrawRoundedRectangle(1, 1, float64(titlecard.W()-1*2), float64(titlecardh-1*2), 16)
|
||||||
|
titlecard.ClipPreserve()
|
||||||
|
titlecard.DrawImage(blurback, -70, -70)
|
||||||
|
titlecard.SetColor(colorswitch(140))
|
||||||
|
titlecard.FillPreserve()
|
||||||
|
|
||||||
titlecard.SetLineWidth(3)
|
titlecard.SetLineWidth(3)
|
||||||
titlecard.SetColor(colorswitch(100))
|
titlecard.SetColor(colorswitch(100))
|
||||||
titlecard.StrokePreserve()
|
titlecard.ResetClip()
|
||||||
titlecard.SetColor(colorswitch(140))
|
titlecard.Stroke()
|
||||||
titlecard.Fill()
|
|
||||||
|
|
||||||
titlecard.DrawImage(avatarf.Circle(0).Image(), (titlecardh-avatarf.H())/2, (titlecardh-avatarf.H())/2)
|
titlecard.DrawImage(avatarf.Circle(0).Image(), (titlecardh-avatarf.H())/2, (titlecardh-avatarf.H())/2)
|
||||||
|
|
||||||
@ -288,20 +290,23 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string, botrunsta
|
|||||||
fw, _ = titlecard.MeasureString(bs)
|
fw, _ = titlecard.MeasureString(bs)
|
||||||
|
|
||||||
titlecard.DrawStringAnchored(bs, float64(titlecardh)+fw/2, float64(titlecardh)*(0.5+0.75/2), 0.5, 0.5)
|
titlecard.DrawStringAnchored(bs, float64(titlecardh)+fw/2, float64(titlecardh)*(0.5+0.75/2), 0.5, 0.5)
|
||||||
titleimg = rendercard.Fillet(titlecard.Image(), 16)
|
titleimg = titlecard.Image()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
basiccard := gg.NewContext(cardw, basiccardh)
|
basiccard := gg.NewContext(cardw, basiccardh)
|
||||||
bwg.Wait()
|
bwg.Wait()
|
||||||
basiccard.DrawImage(blurback, -70, -70-titlecardh-40)
|
|
||||||
|
|
||||||
basiccard.DrawRoundedRectangle(1, 1, float64(basiccard.W()-1*2), float64(basiccardh-1*2), 16)
|
basiccard.DrawRoundedRectangle(1, 1, float64(basiccard.W()-1*2), float64(basiccardh-1*2), 16)
|
||||||
|
basiccard.ClipPreserve()
|
||||||
|
basiccard.DrawImage(blurback, -70, -70-titlecardh-40)
|
||||||
|
basiccard.SetColor(colorswitch(140))
|
||||||
|
basiccard.FillPreserve()
|
||||||
|
|
||||||
basiccard.SetLineWidth(3)
|
basiccard.SetLineWidth(3)
|
||||||
basiccard.SetColor(colorswitch(100))
|
basiccard.SetColor(colorswitch(100))
|
||||||
basiccard.StrokePreserve()
|
basiccard.ResetClip()
|
||||||
basiccard.SetColor(colorswitch(140))
|
basiccard.Stroke()
|
||||||
basiccard.Fill()
|
|
||||||
|
|
||||||
bslen := len(basicstate)
|
bslen := len(basicstate)
|
||||||
for i, v := range basicstate {
|
for i, v := range basicstate {
|
||||||
@ -361,20 +366,23 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string, botrunsta
|
|||||||
basiccard.DrawStringAnchored(s, (float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200+15+fw+15+basiccard.FontHeight()/2+float64(k)*textoffsety, 0.5, 0.5)
|
basiccard.DrawStringAnchored(s, (float64(basiccard.W())-200*float64(bslen))/float64(bslen+1)+200/2+offset, 20+200+15+fw+15+basiccard.FontHeight()/2+float64(k)*textoffsety, 0.5, 0.5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
basicimg = rendercard.Fillet(basiccard.Image(), 16)
|
basicimg = basiccard.Image()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
diskcard := gg.NewContext(cardw, diskcardh)
|
diskcard := gg.NewContext(cardw, diskcardh)
|
||||||
bwg.Wait()
|
bwg.Wait()
|
||||||
diskcard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40)
|
|
||||||
|
|
||||||
diskcard.DrawRoundedRectangle(1, 1, float64(diskcard.W()-1*2), float64(diskcardh-1*2), 16)
|
diskcard.DrawRoundedRectangle(1, 1, float64(diskcard.W()-1*2), float64(diskcardh-1*2), 16)
|
||||||
|
diskcard.ClipPreserve()
|
||||||
|
diskcard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40)
|
||||||
|
diskcard.SetColor(colorswitch(140))
|
||||||
|
diskcard.FillPreserve()
|
||||||
|
|
||||||
diskcard.SetLineWidth(3)
|
diskcard.SetLineWidth(3)
|
||||||
diskcard.SetColor(colorswitch(100))
|
diskcard.SetColor(colorswitch(100))
|
||||||
diskcard.StrokePreserve()
|
diskcard.ResetClip()
|
||||||
diskcard.SetColor(colorswitch(140))
|
diskcard.Stroke()
|
||||||
diskcard.Fill()
|
|
||||||
|
|
||||||
err = diskcard.ParseFontFace(fontbyte, 32)
|
err = diskcard.ParseFontFace(fontbyte, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -427,6 +435,7 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string, botrunsta
|
|||||||
}
|
}
|
||||||
|
|
||||||
diskcard.DrawRoundedRectangle(40, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+offset, float64(diskcard.W())-40-100, 50, 12)
|
diskcard.DrawRoundedRectangle(40, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+offset, float64(diskcard.W())-40-100, 50, 12)
|
||||||
|
diskcard.ClipPreserve()
|
||||||
diskcard.Fill()
|
diskcard.Fill()
|
||||||
|
|
||||||
colors := darkcolor
|
colors := darkcolor
|
||||||
@ -445,6 +454,7 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string, botrunsta
|
|||||||
|
|
||||||
diskcard.DrawRoundedRectangle(40, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+offset, (float64(diskcard.W())-40-100)*v.precent*0.01, 50, 12)
|
diskcard.DrawRoundedRectangle(40, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+offset, (float64(diskcard.W())-40-100)*v.precent*0.01, 50, 12)
|
||||||
diskcard.Fill()
|
diskcard.Fill()
|
||||||
|
diskcard.ResetClip()
|
||||||
|
|
||||||
diskcard.SetColor(fontcolorswitch())
|
diskcard.SetColor(fontcolorswitch())
|
||||||
|
|
||||||
@ -456,20 +466,23 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string, botrunsta
|
|||||||
diskcard.DrawStringAnchored(strconv.FormatFloat(v.precent, 'f', 0, 64)+"%", float64(diskcard.W())-100/2, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+50/2+offset, 0.5, 0.5)
|
diskcard.DrawStringAnchored(strconv.FormatFloat(v.precent, 'f', 0, 64)+"%", float64(diskcard.W())-100/2, 40+(float64(diskcardh-40*2)-50*float64(dslen))/float64(dslen-1)+50/2+offset, 0.5, 0.5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
diskimg = rendercard.Fillet(diskcard.Image(), 16)
|
diskimg = diskcard.Image()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
moreinfocard := gg.NewContext(cardw, moreinfocardh)
|
moreinfocard := gg.NewContext(cardw, moreinfocardh)
|
||||||
bwg.Wait()
|
bwg.Wait()
|
||||||
moreinfocard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40-diskcardh-40)
|
|
||||||
|
|
||||||
moreinfocard.DrawRoundedRectangle(1, 1, float64(moreinfocard.W()-1*2), float64(moreinfocard.H()-1*2), 16)
|
moreinfocard.DrawRoundedRectangle(1, 1, float64(moreinfocard.W()-1*2), float64(moreinfocard.H()-1*2), 16)
|
||||||
|
moreinfocard.ClipPreserve()
|
||||||
|
moreinfocard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40-diskcardh-40)
|
||||||
|
moreinfocard.SetColor(colorswitch(140))
|
||||||
|
moreinfocard.FillPreserve()
|
||||||
|
|
||||||
moreinfocard.SetLineWidth(3)
|
moreinfocard.SetLineWidth(3)
|
||||||
moreinfocard.SetColor(colorswitch(100))
|
moreinfocard.SetColor(colorswitch(100))
|
||||||
moreinfocard.StrokePreserve()
|
moreinfocard.ResetClip()
|
||||||
moreinfocard.SetColor(colorswitch(140))
|
moreinfocard.Stroke()
|
||||||
moreinfocard.Fill()
|
|
||||||
|
|
||||||
err = moreinfocard.ParseFontFace(fontbyte, 32)
|
err = moreinfocard.ParseFontFace(fontbyte, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -488,7 +501,7 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string, botrunsta
|
|||||||
moreinfocard.DrawStringAnchored(v.name, 20+fw/2, 30+(float64(moreinfocardh-30*2)-moreinfocard.FontHeight()*float64(milen))/float64(milen-1)+moreinfocard.FontHeight()/2+offset, 0.5, 0.5)
|
moreinfocard.DrawStringAnchored(v.name, 20+fw/2, 30+(float64(moreinfocardh-30*2)-moreinfocard.FontHeight()*float64(milen))/float64(milen-1)+moreinfocard.FontHeight()/2+offset, 0.5, 0.5)
|
||||||
moreinfocard.DrawStringAnchored(v.text[0], float64(moreinfocard.W())-20-fw1/2, 30+(float64(moreinfocardh-30*2)-moreinfocard.FontHeight()*float64(milen))/float64(milen-1)+moreinfocard.FontHeight()/2+offset, 0.5, 0.5)
|
moreinfocard.DrawStringAnchored(v.text[0], float64(moreinfocard.W())-20-fw1/2, 30+(float64(moreinfocardh-30*2)-moreinfocard.FontHeight()*float64(milen))/float64(milen-1)+moreinfocard.FontHeight()/2+offset, 0.5, 0.5)
|
||||||
}
|
}
|
||||||
moreinfoimg = rendercard.Fillet(moreinfocard.Image(), 16)
|
moreinfoimg = moreinfocard.Image()
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
@ -668,7 +681,7 @@ func diskstate() (stateinfo []*status, err error) {
|
|||||||
func moreinfo(m *ctrl.Control[*zero.Ctx]) (stateinfo []*status, err error) {
|
func moreinfo(m *ctrl.Control[*zero.Ctx]) (stateinfo []*status, err error) {
|
||||||
var mems runtime.MemStats
|
var mems runtime.MemStats
|
||||||
runtime.ReadMemStats(&mems)
|
runtime.ReadMemStats(&mems)
|
||||||
fmtmem := storagefmt(float64(mems.Sys))
|
fmtmem := storagefmt(float64(mems.Alloc))
|
||||||
|
|
||||||
hostinfo, err := host.Info()
|
hostinfo, err := host.Info()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
56
plugin/aiimage/config.go
Normal file
56
plugin/aiimage/config.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Package aiimage 提供AI画图功能配置
|
||||||
|
package aiimage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
// storage 管理画图配置存储
|
||||||
|
type storage struct {
|
||||||
|
sync.RWMutex
|
||||||
|
db sql.Sqlite
|
||||||
|
}
|
||||||
|
|
||||||
|
// imageConfig 存储AI画图配置信息
|
||||||
|
type imageConfig struct {
|
||||||
|
ID int64 `db:"id"` // 主键ID
|
||||||
|
APIKey string `db:"apiKey"` // API密钥
|
||||||
|
APIURL string `db:"apiUrl"` // API地址
|
||||||
|
ModelName string `db:"modelName"` // 画图模型名称
|
||||||
|
}
|
||||||
|
|
||||||
|
// getConfig 获取当前配置
|
||||||
|
func (sdb *storage) getConfig() imageConfig {
|
||||||
|
sdb.RLock()
|
||||||
|
defer sdb.RUnlock()
|
||||||
|
cfg := imageConfig{}
|
||||||
|
_ = sdb.db.Find("config", &cfg, "WHERE id = 1")
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// setConfig 设置AI画图配置
|
||||||
|
func (sdb *storage) setConfig(apiKey, apiURL, modelName string) error {
|
||||||
|
sdb.Lock()
|
||||||
|
defer sdb.Unlock()
|
||||||
|
return sdb.db.Insert("config", &imageConfig{
|
||||||
|
ID: 1,
|
||||||
|
APIKey: apiKey,
|
||||||
|
APIURL: apiURL,
|
||||||
|
ModelName: modelName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintConfig 返回格式化后的配置信息
|
||||||
|
func (sdb *storage) PrintConfig() string {
|
||||||
|
cfg := sdb.getConfig()
|
||||||
|
var builder strings.Builder
|
||||||
|
builder.WriteString("当前AI画图配置:\n")
|
||||||
|
builder.WriteString(fmt.Sprintf("• 密钥: %s\n", cfg.APIKey))
|
||||||
|
builder.WriteString(fmt.Sprintf("• 接口地址: %s\n", cfg.APIURL))
|
||||||
|
builder.WriteString(fmt.Sprintf("• 模型名: %s\n", cfg.ModelName))
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
171
plugin/aiimage/main.go
Normal file
171
plugin/aiimage/main.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
// Package aiimage AI画图
|
||||||
|
package aiimage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||||
|
"github.com/FloatTech/floatbox/web"
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/control"
|
||||||
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var sdb = &storage{}
|
||||||
|
|
||||||
|
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
|
DisableOnDefault: false,
|
||||||
|
Extra: control.ExtraFromString("aiimage"),
|
||||||
|
Brief: "AI画图",
|
||||||
|
Help: "- 设置AI画图密钥xxx\n" +
|
||||||
|
"- 设置AI画图接口地址https://api.siliconflow.cn/v1/images/generations\n" +
|
||||||
|
"- 设置AI画图模型名Kwai-Kolors/Kolors\n" +
|
||||||
|
"- 查看AI画图配置\n" +
|
||||||
|
"- AI画图 [描述]",
|
||||||
|
PrivateDataFolder: "aiimage",
|
||||||
|
})
|
||||||
|
|
||||||
|
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
|
sdb.db = sql.New(en.DataFolder() + "aiimage.db")
|
||||||
|
err := sdb.db.Open(time.Hour)
|
||||||
|
if err == nil {
|
||||||
|
// 创建配置表
|
||||||
|
err = sdb.db.Create("config", &imageConfig{})
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("[ERROR]:", err))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("[ERROR]:", err))
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
en.OnPrefix("设置AI画图密钥", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
apiKey := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
cfg := sdb.getConfig()
|
||||||
|
err := sdb.setConfig(apiKey, cfg.APIURL, cfg.ModelName)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: 设置API密钥失败: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功设置API密钥"))
|
||||||
|
})
|
||||||
|
|
||||||
|
en.OnPrefix("设置AI画图接口地址", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
apiURL := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
cfg := sdb.getConfig()
|
||||||
|
err := sdb.setConfig(cfg.APIKey, apiURL, cfg.ModelName)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: 设置API地址失败: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功设置API地址"))
|
||||||
|
})
|
||||||
|
|
||||||
|
en.OnPrefix("设置AI画图模型名", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
modelName := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
cfg := sdb.getConfig()
|
||||||
|
err := sdb.setConfig(cfg.APIKey, cfg.APIURL, modelName)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: 设置模型失败: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("成功设置模型: ", modelName))
|
||||||
|
})
|
||||||
|
|
||||||
|
en.OnFullMatch("查看AI画图配置", getdb, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
ctx.SendChain(message.Text(sdb.PrintConfig()))
|
||||||
|
})
|
||||||
|
|
||||||
|
en.OnPrefix("AI画图", getdb).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
ctx.SendChain(message.Text("少女思考中..."))
|
||||||
|
prompt := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
if prompt == "" {
|
||||||
|
ctx.SendChain(message.Text("请输入图片描述"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := sdb.getConfig()
|
||||||
|
if cfg.APIKey == "" || cfg.APIURL == "" || cfg.ModelName == "" {
|
||||||
|
ctx.SendChain(message.Text("请先配置API密钥、地址和模型"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 准备请求数据
|
||||||
|
reqBytes, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"model": cfg.ModelName,
|
||||||
|
"prompt": prompt,
|
||||||
|
"image_size": "1024x1024",
|
||||||
|
"batch_size": 4,
|
||||||
|
"num_inference_steps": 20,
|
||||||
|
"guidance_scale": 7.5,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 发送API请求
|
||||||
|
data, err := web.RequestDataWithHeaders(
|
||||||
|
web.NewDefaultClient(),
|
||||||
|
cfg.APIURL,
|
||||||
|
"POST",
|
||||||
|
func(req *http.Request) error {
|
||||||
|
req.Header.Set("Authorization", "Bearer "+cfg.APIKey)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
bytes.NewReader(reqBytes),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("API请求失败: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析API响应
|
||||||
|
jsonData := gjson.ParseBytes(data)
|
||||||
|
images := jsonData.Get("images")
|
||||||
|
if !images.Exists() {
|
||||||
|
images = jsonData.Get("data")
|
||||||
|
if !images.Exists() {
|
||||||
|
ctx.SendChain(message.Text("未获取到图片URL"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送生成的图片和相关信息
|
||||||
|
inferenceTime := jsonData.Get("timings.inference").Float()
|
||||||
|
seed := jsonData.Get("seed").Int()
|
||||||
|
msg := make(message.Message, 0, 1)
|
||||||
|
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Text("图片生成成功!\n",
|
||||||
|
"提示词: ", prompt, "\n",
|
||||||
|
"模型: ", cfg.ModelName, "\n",
|
||||||
|
"推理时间: ", inferenceTime, "秒\n",
|
||||||
|
"种子: ", seed)))
|
||||||
|
|
||||||
|
// 添加所有图片
|
||||||
|
images.ForEach(func(_, value gjson.Result) bool {
|
||||||
|
url := value.Get("url").String()
|
||||||
|
if url != "" {
|
||||||
|
msg = append(msg, ctxext.FakeSenderForwardNode(ctx, message.Image(url)))
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(msg) > 0 {
|
||||||
|
ctx.Send(msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
134
plugin/airecord/record.go
Normal file
134
plugin/airecord/record.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
// Package airecord 群应用:AI声聊
|
||||||
|
package airecord
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
|
"github.com/FloatTech/AnimeAPI/airecord"
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/control"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
|
DisableOnDefault: false,
|
||||||
|
Extra: control.ExtraFromString("airecord"),
|
||||||
|
Brief: "群应用:AI声聊",
|
||||||
|
Help: "- 设置AI语音群号1048452984(tips:机器人任意所在群聊即可)\n" +
|
||||||
|
"- 设置AI语音模型\n" +
|
||||||
|
"- 查看AI语音配置\n" +
|
||||||
|
"- 发送AI语音xxx",
|
||||||
|
PrivateDataFolder: "airecord",
|
||||||
|
})
|
||||||
|
|
||||||
|
en.OnPrefix("设置AI语音群号", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
u := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
num, err := strconv.ParseInt(u, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: parse gid err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = airecord.SetCustomGID(num)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set gid err: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("设置AI语音群号为", num))
|
||||||
|
})
|
||||||
|
en.OnFullMatch("设置AI语音模型", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
|
||||||
|
recv, cancel := next.Repeat()
|
||||||
|
defer cancel()
|
||||||
|
jsonData := ctx.GetAICharacters(0, 1)
|
||||||
|
|
||||||
|
// 转换为字符串数组
|
||||||
|
var names []string
|
||||||
|
// 初始化两个映射表
|
||||||
|
nameToID := make(map[string]string)
|
||||||
|
nameToURL := make(map[string]string)
|
||||||
|
characters := jsonData.Get("#.characters")
|
||||||
|
|
||||||
|
// 遍历每个角色对象
|
||||||
|
characters.ForEach(func(_, group gjson.Result) bool {
|
||||||
|
group.ForEach(func(_, character gjson.Result) bool {
|
||||||
|
// 提取当前角色的三个字段
|
||||||
|
name := character.Get("character_name").String()
|
||||||
|
names = append(names, name)
|
||||||
|
// 存入映射表(重复名称会覆盖,保留最后出现的条目)
|
||||||
|
nameToID[name] = character.Get("character_id").String()
|
||||||
|
nameToURL[name] = character.Get("preview_url").String()
|
||||||
|
return true // 继续遍历
|
||||||
|
})
|
||||||
|
return true // 继续遍历
|
||||||
|
})
|
||||||
|
var builder strings.Builder
|
||||||
|
// 写入开头文本
|
||||||
|
builder.WriteString("请选择语音模型序号:\n")
|
||||||
|
|
||||||
|
// 遍历names数组,拼接序号和名称
|
||||||
|
for i, v := range names {
|
||||||
|
// 将数字转换为字符串(不依赖fmt)
|
||||||
|
numStr := strconv.Itoa(i)
|
||||||
|
// 拼接格式:"序号. 名称\n"
|
||||||
|
builder.WriteString(numStr)
|
||||||
|
builder.WriteString(". ")
|
||||||
|
builder.WriteString(v)
|
||||||
|
builder.WriteString("\n")
|
||||||
|
}
|
||||||
|
// 获取最终字符串
|
||||||
|
ctx.SendChain(message.Text(builder.String()))
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-time.After(time.Second * 120):
|
||||||
|
ctx.SendChain(message.Text("设置AI语音模型指令过期"))
|
||||||
|
return
|
||||||
|
case ct := <-recv:
|
||||||
|
msg := ct.Event.Message.ExtractPlainText()
|
||||||
|
num, err := strconv.Atoi(msg)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("请输入数字!"))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if num < 0 || num >= len(names) {
|
||||||
|
ctx.SendChain(message.Text("序号非法!"))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = airecord.SetRecordModel(names[num], nameToID[names[num]])
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: set model err: ", err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("已选择语音模型: ", names[num]))
|
||||||
|
ctx.SendChain(message.Record(nameToURL[names[num]]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
en.OnFullMatch("查看AI语音配置", zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
ctx.SendChain(message.Text(airecord.PrintRecordConfig()))
|
||||||
|
})
|
||||||
|
en.OnPrefix("发送AI语音", zero.UserOrGrpAdmin).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
u := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
recCfg := airecord.GetConfig()
|
||||||
|
record := ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, u)
|
||||||
|
if record == "" {
|
||||||
|
id := ctx.SendGroupAIRecord(recCfg.ModelID, ctx.Event.GroupID, u)
|
||||||
|
if id == "" {
|
||||||
|
ctx.SendChain(message.Text("ERROR: get record err: empty record"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Record(record))
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,286 +0,0 @@
|
|||||||
package aireply
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/RomiChan/syncx"
|
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
|
||||||
|
|
||||||
"github.com/FloatTech/AnimeAPI/aireply"
|
|
||||||
"github.com/FloatTech/AnimeAPI/tts"
|
|
||||||
"github.com/FloatTech/AnimeAPI/tts/baidutts"
|
|
||||||
"github.com/FloatTech/AnimeAPI/tts/genshin"
|
|
||||||
"github.com/FloatTech/AnimeAPI/tts/lolimi"
|
|
||||||
"github.com/FloatTech/AnimeAPI/tts/ttscn"
|
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
|
||||||
"github.com/FloatTech/zbputils/control"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 数据结构: [8 bits] [8 bits] [8 bits]
|
|
||||||
// [具体人物] [tts模式] [回复模式]
|
|
||||||
|
|
||||||
// defaultttsindexkey
|
|
||||||
// 数据结构: [8 bits] [8 bits]
|
|
||||||
// [具体人物] [tts模式]
|
|
||||||
|
|
||||||
// [tts模式]: 0~200 genshin 201 baidu 202 ttscn 203 lolimi
|
|
||||||
|
|
||||||
const (
|
|
||||||
baiduttsindex = 201 + iota
|
|
||||||
ttscnttsindex
|
|
||||||
lolimittsindex
|
|
||||||
)
|
|
||||||
|
|
||||||
// extrattsname is the tts other than genshin vits
|
|
||||||
var extrattsname = []string{"百度", "TTSCN", "桑帛云"}
|
|
||||||
|
|
||||||
var ttscnspeakers = [...]string{
|
|
||||||
"晓晓(女 - 年轻人)",
|
|
||||||
"云扬(男 - 年轻人)",
|
|
||||||
"晓辰(女 - 年轻人 - 抖音热门)",
|
|
||||||
"晓涵(女 - 年轻人)",
|
|
||||||
"晓墨(女 - 年轻人)",
|
|
||||||
"晓秋(女 - 中年人)",
|
|
||||||
"晓睿(女 - 老年)",
|
|
||||||
"晓双(女 - 儿童)",
|
|
||||||
"晓萱(女 - 年轻人)",
|
|
||||||
"晓颜(女 - 年轻人)",
|
|
||||||
"晓悠(女 - 儿童)",
|
|
||||||
"云希(男 - 年轻人 - 抖音热门)",
|
|
||||||
"云野(男 - 中年人)",
|
|
||||||
"晓梦(女 - 年轻人)",
|
|
||||||
"晓伊(女 - 儿童)",
|
|
||||||
"晓甄(女 - 年轻人)",
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultttsindexkey = -2905
|
|
||||||
|
|
||||||
var (
|
|
||||||
原 = newapikeystore("./data/tts/o.txt")
|
|
||||||
ཆཏ = newapikeystore("./data/tts/c.txt")
|
|
||||||
百 = newapikeystore("./data/tts/b.txt")
|
|
||||||
桑 = newapikeystore("./data/tts/s.txt")
|
|
||||||
)
|
|
||||||
|
|
||||||
type replymode []string
|
|
||||||
|
|
||||||
func (r replymode) setReplyMode(ctx *zero.Ctx, name string) error {
|
|
||||||
gid := ctx.Event.GroupID
|
|
||||||
if gid == 0 {
|
|
||||||
gid = -ctx.Event.UserID
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
var index int64
|
|
||||||
for i, s := range r {
|
|
||||||
if s == name {
|
|
||||||
ok = true
|
|
||||||
index = int64(i)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return errors.New("no such mode")
|
|
||||||
}
|
|
||||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
|
||||||
if !ok {
|
|
||||||
return errors.New("no such plugin")
|
|
||||||
}
|
|
||||||
return m.SetData(gid, (m.GetData(gid)&^0xff)|(index&0xff))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply {
|
|
||||||
k := 桑.k
|
|
||||||
gid := ctx.Event.GroupID
|
|
||||||
if gid == 0 {
|
|
||||||
gid = -ctx.Event.UserID
|
|
||||||
}
|
|
||||||
m, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
|
||||||
if ok {
|
|
||||||
switch m.GetData(gid) & 0xff {
|
|
||||||
case 0:
|
|
||||||
return aireply.NewLolimiAi(aireply.JingfengURL, aireply.JingfengBotName, k, false, 0)
|
|
||||||
case 1:
|
|
||||||
return aireply.NewLolimiAi(aireply.MomoURL, aireply.MomoBotName, k, false, 0)
|
|
||||||
case 2:
|
|
||||||
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
|
|
||||||
case 3:
|
|
||||||
return aireply.NewXiaoAi(aireply.XiaoAiURL, aireply.XiaoAiBotName)
|
|
||||||
case 4:
|
|
||||||
if ཆཏ.k != "" {
|
|
||||||
return aireply.NewChatGPT(aireply.ChatGPTURL, ཆཏ.k)
|
|
||||||
}
|
|
||||||
return aireply.NewLolimiAi(aireply.JingfengURL, aireply.JingfengBotName, k, false, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return aireply.NewLolimiAi(aireply.JingfengURL, aireply.JingfengBotName, k, false, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var ttsins = func() map[string]tts.TTS {
|
|
||||||
m := make(map[string]tts.TTS, 512)
|
|
||||||
for _, mode := range append(genshin.SoundList[:], extrattsname...) {
|
|
||||||
m[mode] = nil
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}()
|
|
||||||
|
|
||||||
var ttsModes = func() []string {
|
|
||||||
s := append(genshin.SoundList[:], make([]string, baiduttsindex-len(genshin.SoundList))...) // 0-200
|
|
||||||
s = append(s, extrattsname...) // 201 202 ...
|
|
||||||
return s
|
|
||||||
}()
|
|
||||||
|
|
||||||
type ttsmode syncx.Map[int64, int64]
|
|
||||||
|
|
||||||
func list(list []string, num int) string {
|
|
||||||
s := ""
|
|
||||||
for i, value := range list {
|
|
||||||
s += value
|
|
||||||
if (i+1)%num == 0 {
|
|
||||||
s += "\n"
|
|
||||||
} else {
|
|
||||||
s += " | "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func newttsmode() *ttsmode {
|
|
||||||
t := &ttsmode{}
|
|
||||||
m, ok := control.Lookup("tts")
|
|
||||||
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, 0)
|
|
||||||
if ok {
|
|
||||||
index := m.GetData(defaultttsindexkey)
|
|
||||||
msk := index & 0xff
|
|
||||||
if msk >= 0 && (msk < int64(len(ttsModes))) {
|
|
||||||
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, character int) error {
|
|
||||||
gid := ctx.Event.GroupID
|
|
||||||
if gid == 0 {
|
|
||||||
gid = -ctx.Event.UserID
|
|
||||||
}
|
|
||||||
_, ok := ttsins[name]
|
|
||||||
if !ok {
|
|
||||||
return errors.New("不支持设置语音人物" + name)
|
|
||||||
}
|
|
||||||
var index = int64(-1)
|
|
||||||
for i, s := range genshin.SoundList {
|
|
||||||
if s == name {
|
|
||||||
index = int64(i + 1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if index == -1 {
|
|
||||||
switch name {
|
|
||||||
case extrattsname[0]:
|
|
||||||
index = baiduttsindex
|
|
||||||
case extrattsname[1]:
|
|
||||||
index = ttscnttsindex
|
|
||||||
case extrattsname[2]:
|
|
||||||
index = lolimittsindex
|
|
||||||
default:
|
|
||||||
return errors.New("语音人物" + name + "未注册index")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
|
||||||
// 按原来的逻辑map存的是前16位
|
|
||||||
storeIndex := (m.GetData(gid) &^ 0xffff00) | ((index << 8) & 0xff00) | ((int64(character) << 16) & 0xff0000)
|
|
||||||
(*syncx.Map[int64, int64])(t).Store(gid, (storeIndex>>8)&0xffff)
|
|
||||||
return m.SetData(gid, storeIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ttsmode) getSoundMode(ctx *zero.Ctx) (tts.TTS, error) {
|
|
||||||
gid := ctx.Event.GroupID
|
|
||||||
if gid == 0 {
|
|
||||||
gid = -ctx.Event.UserID
|
|
||||||
}
|
|
||||||
i, ok := (*syncx.Map[int64, int64])(t).Load(gid)
|
|
||||||
if !ok {
|
|
||||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
|
||||||
i = m.GetData(gid) >> 8
|
|
||||||
}
|
|
||||||
m := i & 0xff
|
|
||||||
if m <= 0 || (m >= int64(len(ttsModes))) {
|
|
||||||
i, _ = (*syncx.Map[int64, int64])(t).Load(defaultttsindexkey)
|
|
||||||
if i == 0 {
|
|
||||||
i = ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).GetData(defaultttsindexkey)
|
|
||||||
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, i)
|
|
||||||
}
|
|
||||||
m = i & 0xff
|
|
||||||
}
|
|
||||||
mode := ttsModes[m]
|
|
||||||
ins, ok := ttsins[mode]
|
|
||||||
if !ok || ins == nil {
|
|
||||||
switch mode {
|
|
||||||
case extrattsname[0]:
|
|
||||||
id, sec, _ := strings.Cut(百.k, ",")
|
|
||||||
ins = baidutts.NewBaiduTTS(int(i&0xff00)>>8, id, sec)
|
|
||||||
case extrattsname[1]:
|
|
||||||
var err error
|
|
||||||
ins, err = ttscn.NewTTSCN("中文(普通话,简体)", ttscnspeakers[int(i&0xff00)>>8], ttscn.KBRates[0])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
case extrattsname[2]:
|
|
||||||
ins = lolimi.NewLolimi(int(i&0xff00) >> 8)
|
|
||||||
default: // 原神
|
|
||||||
k := 原.k
|
|
||||||
if k != "" {
|
|
||||||
ins = genshin.NewGenshin(int(m-1), 原.k)
|
|
||||||
ttsins[mode] = ins
|
|
||||||
} else {
|
|
||||||
ins = lolimi.NewLolimi(int(i&0xff00) >> 8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ins, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ttsmode) resetSoundMode(ctx *zero.Ctx) error {
|
|
||||||
gid := ctx.Event.GroupID
|
|
||||||
if gid == 0 {
|
|
||||||
gid = -ctx.Event.UserID
|
|
||||||
}
|
|
||||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
|
||||||
// 只保留后面8位
|
|
||||||
(*syncx.Map[int64, int64])(t).Delete(gid)
|
|
||||||
return m.SetData(gid, (m.GetData(gid) & 0xff)) // 重置数据
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *ttsmode) setDefaultSoundMode(name string, character int) error {
|
|
||||||
_, ok := ttsins[name]
|
|
||||||
if !ok {
|
|
||||||
return errors.New("不支持设置语音人物" + name)
|
|
||||||
}
|
|
||||||
index := int64(-1)
|
|
||||||
for i, s := range genshin.SoundList {
|
|
||||||
if s == name {
|
|
||||||
index = int64(i + 1)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if index == -1 {
|
|
||||||
switch name {
|
|
||||||
case extrattsname[0]:
|
|
||||||
index = baiduttsindex
|
|
||||||
case extrattsname[1]:
|
|
||||||
index = ttscnttsindex
|
|
||||||
case extrattsname[2]:
|
|
||||||
index = lolimittsindex
|
|
||||||
default:
|
|
||||||
return errors.New("语音人物" + name + "未注册index")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m, ok := control.Lookup("tts")
|
|
||||||
if !ok {
|
|
||||||
return errors.New("[tts] service not found")
|
|
||||||
}
|
|
||||||
storeIndex := (index & 0xff) | ((int64(character) << 8) & 0xff00)
|
|
||||||
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, storeIndex)
|
|
||||||
return m.SetData(defaultttsindexkey, storeIndex)
|
|
||||||
}
|
|
||||||
@ -1,235 +0,0 @@
|
|||||||
// Package aireply AI 回复
|
|
||||||
package aireply
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/FloatTech/AnimeAPI/tts/genshin"
|
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
|
||||||
"github.com/FloatTech/zbputils/control"
|
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
|
||||||
)
|
|
||||||
|
|
||||||
var replmd = replymode([]string{"婧枫", "沫沫", "青云客", "小爱", "ChatGPT"})
|
|
||||||
|
|
||||||
var ttsmd = newttsmode()
|
|
||||||
|
|
||||||
func init() { // 插件主体
|
|
||||||
ent := control.Register("tts", &ctrl.Options[*zero.Ctx]{
|
|
||||||
DisableOnDefault: true,
|
|
||||||
Brief: "人工智能语音回复",
|
|
||||||
Help: "- @Bot 任意文本(任意一句话回复)\n" +
|
|
||||||
"- 设置语音模式[原神人物/百度/TTSCN/桑帛云] 数字(百度/TTSCN说话人/桑帛云)\n" +
|
|
||||||
"- 设置默认语音模式[原神人物/百度/TTSCN/桑帛云] 数字(百度/TTSCN说话人/桑帛云)\n" +
|
|
||||||
"- 恢复成默认语音模式\n" +
|
|
||||||
"- 设置语音回复模式[沫沫|婧枫|青云客|小爱|ChatGPT]\n" +
|
|
||||||
"- 设置原神语音 api key xxxxxx (key请加开发群获得)\n" +
|
|
||||||
"- 设置百度语音 api id xxxxxx secret xxxxxx (请自行获得)\n" +
|
|
||||||
"当前适用的原神人物含有以下: \n" + list(genshin.SoundList[:], 5) +
|
|
||||||
"\n当前适用的TTSCN人物含有以下(以数字顺序代表): \n" + list(ttscnspeakers[:], 5),
|
|
||||||
PrivateDataFolder: "tts",
|
|
||||||
})
|
|
||||||
|
|
||||||
enr := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
|
||||||
DisableOnDefault: false,
|
|
||||||
Brief: "人工智能回复",
|
|
||||||
Help: "- @Bot 任意文本(任意一句话回复)\n- 设置文字回复模式[婧枫|沫沫|青云客|小爱|ChatGPT]\n- 设置 ChatGPT api key xxx",
|
|
||||||
PrivateDataFolder: "aireply",
|
|
||||||
})
|
|
||||||
|
|
||||||
enr.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
|
||||||
Handle(func(ctx *zero.Ctx) {
|
|
||||||
aireply := replmd.getReplyMode(ctx)
|
|
||||||
reply := message.ParseMessageFromString(aireply.Talk(ctx.Event.UserID, ctx.ExtractPlainText(), zero.BotConfig.NickName[0]))
|
|
||||||
// 回复
|
|
||||||
time.Sleep(time.Second * 1)
|
|
||||||
reply = append(reply, message.Reply(ctx.Event.MessageID))
|
|
||||||
ctx.Send(reply)
|
|
||||||
})
|
|
||||||
setReplyMode := func(ctx *zero.Ctx) {
|
|
||||||
param := ctx.State["args"].(string)
|
|
||||||
err := replmd.setReplyMode(ctx, param)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("成功"))
|
|
||||||
}
|
|
||||||
enr.OnPrefix("设置文字回复模式", zero.AdminPermission).SetBlock(true).Handle(setReplyMode)
|
|
||||||
enr.OnRegex(`^设置\s*桑帛云\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
||||||
err := 桑.set(ctx.State["regex_matched"].([]string)[1])
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SendChain(message.Text("设置成功"))
|
|
||||||
})
|
|
||||||
enr.OnRegex(`^设置\s*ChatGPT\s*api\s*key\s*(.*)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
||||||
err := ཆཏ.set(ctx.State["regex_matched"].([]string)[1])
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SendChain(message.Text("设置成功"))
|
|
||||||
})
|
|
||||||
|
|
||||||
endpre := regexp.MustCompile(`\pP$`)
|
|
||||||
ttscachedir := ent.DataFolder() + "cache/"
|
|
||||||
_ = os.RemoveAll(ttscachedir)
|
|
||||||
err := os.MkdirAll(ttscachedir, 0755)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
ent.OnMessage(zero.OnlyToMe).SetBlock(true).Limit(ctxext.LimitByUser).
|
|
||||||
Handle(func(ctx *zero.Ctx) {
|
|
||||||
msg := ctx.ExtractPlainText()
|
|
||||||
// 获取回复模式
|
|
||||||
r := replmd.getReplyMode(ctx)
|
|
||||||
// 获取回复的文本
|
|
||||||
reply := message.ParseMessageFromString(r.TalkPlain(ctx.Event.UserID, msg, zero.BotConfig.NickName[0]))
|
|
||||||
// 过滤掉文字消息
|
|
||||||
filterMsg := make([]message.MessageSegment, 0, len(reply))
|
|
||||||
sb := strings.Builder{}
|
|
||||||
for _, v := range reply {
|
|
||||||
if v.Type != "text" {
|
|
||||||
filterMsg = append(filterMsg, v)
|
|
||||||
} else {
|
|
||||||
sb.WriteString(v.Data["text"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 纯文本
|
|
||||||
plainReply := sb.String()
|
|
||||||
plainReply = strings.ReplaceAll(plainReply, "\n", "")
|
|
||||||
// 获取语音
|
|
||||||
speaker, err := ttsmd.getSoundMode(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rec, err := speaker.Speak(ctx.Event.UserID, func() string {
|
|
||||||
if !endpre.MatchString(plainReply) {
|
|
||||||
return plainReply + "。"
|
|
||||||
}
|
|
||||||
return plainReply
|
|
||||||
})
|
|
||||||
// 发送前面的图片
|
|
||||||
if len(filterMsg) != 0 {
|
|
||||||
filterMsg = append(filterMsg, message.Reply(ctx.Event.MessageID))
|
|
||||||
ctx.Send(filterMsg)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(plainReply))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 发送语音
|
|
||||||
if id := ctx.SendChain(message.Record(rec)); id.ID() == 0 {
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(plainReply))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
ent.OnPrefix("设置语音回复模式", zero.AdminPermission).SetBlock(true).Handle(setReplyMode)
|
|
||||||
ent.OnRegex(`^设置语音模式\s*([\S\D]*)\s*(\d*)$`, zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
||||||
param := ctx.State["regex_matched"].([]string)[1]
|
|
||||||
num := ctx.State["regex_matched"].([]string)[2]
|
|
||||||
n := 0
|
|
||||||
var err error
|
|
||||||
if num != "" {
|
|
||||||
n, err = strconv.Atoi(num)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 保存设置
|
|
||||||
logrus.Debugln("[tts] t.setSoundMode( ctx", param, n, ")")
|
|
||||||
err = ttsmd.setSoundMode(ctx, param, n)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
banner := genshin.TestRecord[param]
|
|
||||||
if banner == "" {
|
|
||||||
banner = genshin.TestRecord["默认"]
|
|
||||||
}
|
|
||||||
logrus.Debugln("[tts] banner:", banner, "get sound mode...")
|
|
||||||
// 设置验证
|
|
||||||
speaker, err := ttsmd.getSoundMode(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logrus.Debugln("[tts] got sound mode, speaking...")
|
|
||||||
rec, err := speaker.Speak(ctx.Event.UserID, func() string { return banner })
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("无法发送测试语音,请重试。"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logrus.Debugln("[tts] sending...")
|
|
||||||
if id := ctx.SendChain(message.Record(rec).Add("cache", 0)); id.ID() == 0 {
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("无法发送测试语音,请重试。"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second * 2)
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功,当前为", speaker))
|
|
||||||
})
|
|
||||||
|
|
||||||
ent.OnRegex(`^设置默认语音模式\s*([\S\D]*)\s+(\d*)$`, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
||||||
param := ctx.State["regex_matched"].([]string)[1]
|
|
||||||
num := ctx.State["regex_matched"].([]string)[2]
|
|
||||||
n := 0
|
|
||||||
var err error
|
|
||||||
if num != "" {
|
|
||||||
n, err = strconv.Atoi(num)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 保存设置
|
|
||||||
err = ttsmd.setDefaultSoundMode(param, n)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功"))
|
|
||||||
})
|
|
||||||
|
|
||||||
ent.OnFullMatch("恢复成默认语音模式", zero.AdminPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
||||||
err := ttsmd.resetSoundMode(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 设置验证
|
|
||||||
speaker, err := ttsmd.getSoundMode(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("设置成功,当前为", speaker))
|
|
||||||
})
|
|
||||||
|
|
||||||
ent.OnRegex(`^设置原神语音\s*api\s*key\s*([0-9a-zA-Z-_]{54}==)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
||||||
err := 原.set(ctx.State["regex_matched"].([]string)[1])
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SendChain(message.Text("设置成功"))
|
|
||||||
})
|
|
||||||
|
|
||||||
ent.OnRegex(`^设置百度语音\s*api\s*id\s*(.*)\s*secret\s*(.*)\s*$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
|
||||||
err := 百.set(ctx.State["regex_matched"].([]string)[1] + "," + ctx.State["regex_matched"].([]string)[2])
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.SendChain(message.Text("设置成功"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
package aireply
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/FloatTech/floatbox/binary"
|
|
||||||
"github.com/FloatTech/floatbox/file"
|
|
||||||
)
|
|
||||||
|
|
||||||
type apikeystore struct {
|
|
||||||
k string
|
|
||||||
p string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newapikeystore(p string) (s apikeystore) {
|
|
||||||
s.p = p
|
|
||||||
if file.IsExist(p) {
|
|
||||||
data, err := os.ReadFile(p)
|
|
||||||
if err == nil {
|
|
||||||
s.k = binary.BytesToString(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *apikeystore) set(k string) error {
|
|
||||||
s.k = k
|
|
||||||
return os.WriteFile(s.p, binary.StringToBytes(k), 0644)
|
|
||||||
}
|
|
||||||
145
plugin/animetrace/main.go
Normal file
145
plugin/animetrace/main.go
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
// Package animetrace AnimeTrace 动画/Galgame识别
|
||||||
|
package animetrace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/jpeg"
|
||||||
|
"mime/multipart"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/FloatTech/floatbox/web"
|
||||||
|
"github.com/FloatTech/imgfactory"
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/control"
|
||||||
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
"github.com/disintegration/imaging"
|
||||||
|
"github.com/tidwall/gjson"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
|
DisableOnDefault: false,
|
||||||
|
Brief: "AnimeTrace 动画/Galgame识别插件",
|
||||||
|
Help: "- Gal识图\n- 动漫识图\n- 动漫识图 2\n- 动漫识图 [模型名]\n- Gal识图 [模型名]",
|
||||||
|
})
|
||||||
|
|
||||||
|
engine.OnPrefix("gal识图", zero.OnlyGroup, zero.MustProvidePicture).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
args := ctx.State["args"].(string)
|
||||||
|
var model string
|
||||||
|
switch strings.TrimSpace(args) {
|
||||||
|
case "":
|
||||||
|
model = "full_game_model_kira" // 默认使用的模型
|
||||||
|
default:
|
||||||
|
model = args // 自定义设置模型
|
||||||
|
}
|
||||||
|
processImageRecognition(ctx, model)
|
||||||
|
})
|
||||||
|
|
||||||
|
engine.OnPrefix("动漫识图", zero.OnlyGroup, zero.MustProvidePicture).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
args := ctx.State["args"].(string)
|
||||||
|
var model string
|
||||||
|
switch strings.TrimSpace(args) {
|
||||||
|
case "":
|
||||||
|
model = "anime_model_lovelive"
|
||||||
|
case "2":
|
||||||
|
model = "pre_stable"
|
||||||
|
default:
|
||||||
|
model = args
|
||||||
|
}
|
||||||
|
processImageRecognition(ctx, model)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理图片识别
|
||||||
|
func processImageRecognition(ctx *zero.Ctx, model string) {
|
||||||
|
urls := ctx.State["image_url"].([]string)
|
||||||
|
if len(urls) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imageData, err := imgfactory.Load(urls[0])
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(message.Text("下载图片失败: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ctx.Send(message.Text(model))
|
||||||
|
respBody, err := createAndSendMultipartRequest("https://api.animetrace.com/v1/search", imageData, map[string]string{
|
||||||
|
"is_multi": "0",
|
||||||
|
"model": model,
|
||||||
|
"ai_detect": "0",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(message.Text("识别请求失败: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
code := gjson.Get(string(respBody), "code").Int()
|
||||||
|
if code != 0 {
|
||||||
|
ctx.Send(message.Text("错误: ", gjson.Get(string(respBody), "zh_message").String()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dataArray := gjson.Get(string(respBody), "data").Array()
|
||||||
|
if len(dataArray) == 0 {
|
||||||
|
ctx.Send(message.Text("未识别到任何角色"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var sk message.Message
|
||||||
|
sk = append(sk, ctxext.FakeSenderForwardNode(ctx, message.Text("共识别到 ", len(dataArray), " 个角色,可能是以下来源")))
|
||||||
|
for _, value := range dataArray {
|
||||||
|
boxArray := value.Get("box").Array()
|
||||||
|
imgWidth, imgHeight := imageData.Bounds().Dx(), imageData.Bounds().Dy() // 你可以从 `imageData.Bounds()` 获取
|
||||||
|
box := []int{
|
||||||
|
int(boxArray[0].Float() * float64(imgWidth)),
|
||||||
|
int(boxArray[1].Float() * float64(imgHeight)),
|
||||||
|
int(boxArray[2].Float() * float64(imgWidth)),
|
||||||
|
int(boxArray[3].Float() * float64(imgHeight)),
|
||||||
|
}
|
||||||
|
croppedImg := imaging.Crop(imageData, image.Rect(box[0], box[1], box[2], box[3]))
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := imaging.Encode(&buf, croppedImg, imaging.JPEG, imaging.JPEGQuality(80)); err != nil {
|
||||||
|
ctx.Send(message.Text("图片编码失败: ", err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
base64Str := base64.StdEncoding.EncodeToString(buf.Bytes())
|
||||||
|
var sb strings.Builder
|
||||||
|
value.Get("character").ForEach(func(_, character gjson.Result) bool {
|
||||||
|
sb.WriteString(fmt.Sprintf("《%s》的角色 %s\n", character.Get("work").String(), character.Get("character").String()))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
sk = append(sk, ctxext.FakeSenderForwardNode(ctx, message.Image("base64://"+base64Str), message.Text(sb.String())))
|
||||||
|
}
|
||||||
|
ctx.SendGroupForwardMessage(ctx.Event.GroupID, sk)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送图片识别请求
|
||||||
|
func createAndSendMultipartRequest(url string, img image.Image, formFields map[string]string) ([]byte, error) {
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
|
||||||
|
// 直接编码图片
|
||||||
|
part, err := writer.CreateFormFile("file", "image.jpg")
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("创建文件字段失败: " + err.Error())
|
||||||
|
}
|
||||||
|
if err := jpeg.Encode(part, img, &jpeg.Options{Quality: 80}); err != nil {
|
||||||
|
return nil, errors.New("图片编码失败: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入其他字段
|
||||||
|
for key, value := range formFields {
|
||||||
|
if err := writer.WriteField(key, value); err != nil {
|
||||||
|
return nil, errors.New("写入表单字段失败 (" + key + "): " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writer.Close(); err != nil {
|
||||||
|
return nil, errors.New("关闭 multipart writer 失败: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return web.PostData(url, writer.FormDataContentType(), body)
|
||||||
|
}
|
||||||
@ -17,7 +17,12 @@ import (
|
|||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
const bandur time.Duration = time.Minute * 10
|
const (
|
||||||
|
bandur time.Duration = time.Minute * 2
|
||||||
|
add = "添加违禁词"
|
||||||
|
del = "删除违禁词"
|
||||||
|
list = "查看违禁词"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
managers *ctrl.Manager[*zero.Ctx] // managers lazy load
|
managers *ctrl.Manager[*zero.Ctx] // managers lazy load
|
||||||
@ -41,7 +46,7 @@ func init() {
|
|||||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
DisableOnDefault: false,
|
DisableOnDefault: false,
|
||||||
Brief: "违禁词检测",
|
Brief: "违禁词检测",
|
||||||
Help: "- /[添加|删除|查看]违禁词",
|
Help: "- [添加|删除|查看]违禁词",
|
||||||
PrivateDataFolder: "anti_abuse",
|
PrivateDataFolder: "anti_abuse",
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -56,10 +61,14 @@ func init() {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
engine.OnMessage(onceRule, zero.OnlyGroup, func(ctx *zero.Ctx) bool {
|
notAntiabuse := func(ctx *zero.Ctx) bool {
|
||||||
if !ctx.Event.IsToMe {
|
if zero.PrefixRule(add)(ctx) || zero.PrefixRule(del)(ctx) || zero.PrefixRule(list)(ctx) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
engine.OnMessage(onceRule, notAntiabuse, zero.OnlyGroup, func(ctx *zero.Ctx) bool {
|
||||||
uid := ctx.Event.UserID
|
uid := ctx.Event.UserID
|
||||||
gid := ctx.Event.GroupID
|
gid := ctx.Event.GroupID
|
||||||
msg := strings.ReplaceAll(ctx.MessageString(), "\n", "")
|
msg := strings.ReplaceAll(ctx.MessageString(), "\n", "")
|
||||||
@ -70,7 +79,8 @@ func init() {
|
|||||||
if err := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).Manager.DoBlock(uid); err == nil {
|
if err := ctx.State["manager"].(*ctrl.Control[*zero.Ctx]).Manager.DoBlock(uid); err == nil {
|
||||||
t := time.Now().Unix()
|
t := time.Now().Unix()
|
||||||
cache.Set(uid, struct{}{})
|
cache.Set(uid, struct{}{})
|
||||||
ctx.SetThisGroupBan(uid, int64(bandur.Minutes()))
|
ctx.SetThisGroupBan(uid, int64(bandur.Seconds()))
|
||||||
|
ctx.DeleteMessage(ctx.Event.MessageID)
|
||||||
ctx.SendChain(message.Text("检测到违禁词, 已封禁/屏蔽", bandur))
|
ctx.SendChain(message.Text("检测到违禁词, 已封禁/屏蔽", bandur))
|
||||||
db.Lock()
|
db.Lock()
|
||||||
defer db.Unlock()
|
defer db.Unlock()
|
||||||
@ -92,9 +102,9 @@ func init() {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
engine.OnCommand("添加违禁词", zero.OnlyGroup, zero.AdminPermission, onceRule).Handle(
|
engine.OnPrefix(add, zero.OnlyGroup, zero.AdminPermission, onceRule).SetBlock(true).Handle(
|
||||||
func(ctx *zero.Ctx) {
|
func(ctx *zero.Ctx) {
|
||||||
args := ctx.State["args"].(string)
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
if err := db.insertWord(ctx.Event.GroupID, args); err != nil {
|
if err := db.insertWord(ctx.Event.GroupID, args); err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
} else {
|
} else {
|
||||||
@ -102,9 +112,9 @@ func init() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
engine.OnCommand("删除违禁词", zero.OnlyGroup, zero.AdminPermission, onceRule).Handle(
|
engine.OnPrefix(del, zero.OnlyGroup, zero.AdminPermission, onceRule).SetBlock(true).Handle(
|
||||||
func(ctx *zero.Ctx) {
|
func(ctx *zero.Ctx) {
|
||||||
args := ctx.State["args"].(string)
|
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
if err := db.deleteWord(ctx.Event.GroupID, args); err != nil {
|
if err := db.deleteWord(ctx.Event.GroupID, args); err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
} else {
|
} else {
|
||||||
@ -112,7 +122,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
engine.OnCommand("查看违禁词", zero.OnlyGroup, onceRule).Handle(
|
engine.OnPrefix(list, zero.OnlyGroup, onceRule).SetBlock(true).Handle(
|
||||||
func(ctx *zero.Ctx) {
|
func(ctx *zero.Ctx) {
|
||||||
b, err := text.RenderToBase64(db.listWords(ctx.Event.GroupID), text.FontFile, 400, 20)
|
b, err := text.RenderToBase64(db.listWords(ctx.Event.GroupID), text.FontFile, 400, 20)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -30,7 +30,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func newantidb(path string) (*antidb, error) {
|
func newantidb(path string) (*antidb, error) {
|
||||||
db := &antidb{Sqlite: sqlite.Sqlite{DBPath: path}}
|
db := &antidb{Sqlite: sqlite.New(path)}
|
||||||
err := db.Open(bandur)
|
err := db.Open(bandur)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -46,7 +46,7 @@ func newantidb(path string) (*antidb, error) {
|
|||||||
cache.Touch(nilbt.ID, -time.Since(t))
|
cache.Touch(nilbt.ID, -time.Since(t))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
_ = db.Del("__bantime__", "WHERE time<="+strconv.FormatInt(time.Now().Add(time.Minute-bandur).Unix(), 10))
|
_ = db.Del("__bantime__", "WHERE time <= ?", strconv.FormatInt(time.Now().Add(time.Minute-bandur).Unix(), 10))
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
type datagetter func(string, bool) ([]byte, error)
|
type datagetter func(string, bool) ([]byte, error)
|
||||||
|
|
||||||
func (dgtr datagetter) randImage(file ...string) message.MessageSegment {
|
func (dgtr datagetter) randImage(file ...string) message.Segment {
|
||||||
data, err := dgtr(file[rand.Intn(len(file))], true)
|
data, err := dgtr(file[rand.Intn(len(file))], true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return message.Text("ERROR: ", err)
|
return message.Text("ERROR: ", err)
|
||||||
@ -27,7 +27,7 @@ func (dgtr datagetter) randImage(file ...string) message.MessageSegment {
|
|||||||
return message.ImageBytes(data)
|
return message.ImageBytes(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dgtr datagetter) randRecord(file ...string) message.MessageSegment {
|
func (dgtr datagetter) randRecord(file ...string) message.Segment {
|
||||||
data, err := dgtr(file[rand.Intn(len(file))], true)
|
data, err := dgtr(file[rand.Intn(len(file))], true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return message.Text("ERROR: ", err)
|
return message.Text("ERROR: ", err)
|
||||||
@ -35,7 +35,7 @@ func (dgtr datagetter) randRecord(file ...string) message.MessageSegment {
|
|||||||
return message.Record("base64://" + base64.StdEncoding.EncodeToString(data))
|
return message.Record("base64://" + base64.StdEncoding.EncodeToString(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
func randText(text ...string) message.MessageSegment {
|
func randText(text ...string) message.Segment {
|
||||||
return message.Text(text[rand.Intn(len(text))])
|
return message.Text(text[rand.Intn(len(text))])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -224,7 +224,7 @@ func (g *group) reply(bdres *baiduRes) message.Message {
|
|||||||
g.mu.Lock()
|
g.mu.Lock()
|
||||||
defer g.mu.Unlock()
|
defer g.mu.Unlock()
|
||||||
// 建立消息段
|
// 建立消息段
|
||||||
msgs := make([]message.MessageSegment, 0, 8)
|
msgs := make([]message.Segment, 0, 8)
|
||||||
// 生成简略审核结果回复
|
// 生成简略审核结果回复
|
||||||
msgs = append(msgs, message.Text(bdres.Conclusion, "\n"))
|
msgs = append(msgs, message.Text(bdres.Conclusion, "\n"))
|
||||||
// 查看是否开启详细审核内容提示, 并确定审核内容值为疑似, 或者不合规
|
// 查看是否开启详细审核内容提示, 并确定审核内容值为疑似, 或者不合规
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -31,7 +30,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
re = regexp.MustCompile(`^\d+$`)
|
|
||||||
danmakuTypeMap = map[int64]string{
|
danmakuTypeMap = map[int64]string{
|
||||||
0: "普通消息",
|
0: "普通消息",
|
||||||
1: "礼物",
|
1: "礼物",
|
||||||
@ -73,7 +71,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
engine.OnRegex(`^>user info\s?(.{1,25})$`, getPara).SetBlock(true).
|
engine.OnRegex(`^>user info\s?(.{1,25})$`, bz.RequireUser(cfg)).SetBlock(true).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
id := ctx.State["uid"].(string)
|
id := ctx.State["uid"].(string)
|
||||||
card, err := bz.GetMemberCard(id)
|
card, err := bz.GetMemberCard(id)
|
||||||
@ -91,7 +89,7 @@ func init() {
|
|||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
engine.OnRegex(`^>vup info\s?(.{1,25})$`, getPara).SetBlock(true).
|
engine.OnRegex(`^>vup info\s?(.{1,25})$`, bz.RequireUser(cfg)).SetBlock(true).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
id := ctx.State["uid"].(string)
|
id := ctx.State["uid"].(string)
|
||||||
// 获取详情
|
// 获取详情
|
||||||
@ -114,7 +112,7 @@ func init() {
|
|||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
engine.OnRegex(`^查成分\s?(.{1,25})$`, getPara, getdb).SetBlock(true).
|
engine.OnRegex(`^查成分\s?(.{1,25})$`, bz.RequireUser(cfg), getdb).SetBlock(true).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
id := ctx.State["uid"].(string)
|
id := ctx.State["uid"].(string)
|
||||||
today := time.Now().Format("20060102")
|
today := time.Now().Format("20060102")
|
||||||
@ -134,7 +132,7 @@ func init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
vupLen := len(vups)
|
vupLen := len(vups)
|
||||||
medals, err := bz.GetMedalWall(cfg, id)
|
medals, err := cfg.GetMedalWall(id)
|
||||||
sort.Sort(bz.MedalSorter(medals))
|
sort.Sort(bz.MedalSorter(medals))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
@ -275,7 +273,7 @@ func init() {
|
|||||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||||
})
|
})
|
||||||
|
|
||||||
engine.OnRegex(`^查弹幕\s?(\S{1,25})\s?(\d*)$`, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
engine.OnRegex(`^查弹幕\s?(\S{1,25})\s?(\d*)$`, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
id := ctx.State["uid"].(string)
|
id := ctx.State["uid"].(string)
|
||||||
pagenum := ctx.State["regex_matched"].([]string)[2]
|
pagenum := ctx.State["regex_matched"].([]string)[2]
|
||||||
if pagenum == "" {
|
if pagenum == "" {
|
||||||
@ -582,51 +580,3 @@ func int2rbg(t int64) (int64, int64, int64) {
|
|||||||
b, g, r := int64(buf[0]), int64(buf[1]), int64(buf[2])
|
b, g, r := int64(buf[0]), int64(buf[1]), int64(buf[2])
|
||||||
return r, g, b
|
return r, g, b
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPara(ctx *zero.Ctx) bool {
|
|
||||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
|
||||||
if !re.MatchString(keyword) {
|
|
||||||
searchRes, err := bz.SearchUser(cfg, keyword)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
ctx.State["uid"] = strconv.FormatInt(searchRes[0].Mid, 10)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
|
|
||||||
recv, cancel := next.Repeat()
|
|
||||||
defer cancel()
|
|
||||||
ctx.SendChain(message.Text("输入为纯数字, 请选择查询uid还是用户名, 输入对应序号:\n0. 查询uid\n1. 查询用户名"))
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-time.After(time.Second * 10):
|
|
||||||
ctx.SendChain(message.Text("时间太久啦!", zero.BotConfig.NickName[0], "帮你选择查询uid"))
|
|
||||||
ctx.State["uid"] = keyword
|
|
||||||
return true
|
|
||||||
case c := <-recv:
|
|
||||||
msg := c.Event.Message.ExtractPlainText()
|
|
||||||
num, err := strconv.Atoi(msg)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("请输入数字!"))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if num < 0 || num > 1 {
|
|
||||||
ctx.SendChain(message.Text("序号非法!"))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if num == 0 {
|
|
||||||
ctx.State["uid"] = keyword
|
|
||||||
return true
|
|
||||||
} else if num == 1 {
|
|
||||||
searchRes, err := bz.SearchUser(cfg, keyword)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
ctx.State["uid"] = strconv.FormatInt(searchRes[0].Mid, 10)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,326 +0,0 @@
|
|||||||
package bilibili
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
|
||||||
"github.com/FloatTech/floatbox/binary"
|
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
msgType = map[int]string{
|
|
||||||
1: "转发了动态",
|
|
||||||
2: "有图营业",
|
|
||||||
4: "无图营业",
|
|
||||||
8: "投稿了视频",
|
|
||||||
16: "投稿了短视频",
|
|
||||||
64: "投稿了文章",
|
|
||||||
256: "投稿了音频",
|
|
||||||
2048: "发布了简报",
|
|
||||||
4200: "发布了直播",
|
|
||||||
4308: "发布了直播",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// dynamicCard2msg 处理DynCard
|
|
||||||
func dynamicCard2msg(dynamicCard *bz.DynamicCard) (msg []message.MessageSegment, err error) {
|
|
||||||
var (
|
|
||||||
card bz.Card
|
|
||||||
vote bz.Vote
|
|
||||||
cType int
|
|
||||||
)
|
|
||||||
msg = make([]message.MessageSegment, 0, 16)
|
|
||||||
// 初始化结构体
|
|
||||||
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Card), &card)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if dynamicCard.Extension.Vote != "" {
|
|
||||||
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Extension.Vote), &vote)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cType = dynamicCard.Desc.Type
|
|
||||||
// 生成消息
|
|
||||||
switch cType {
|
|
||||||
case 1:
|
|
||||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
|
||||||
card.Item.Content, "\n",
|
|
||||||
"转发的内容: \n"))
|
|
||||||
var originMsg []message.MessageSegment
|
|
||||||
var co bz.Card
|
|
||||||
co, err = bz.LoadCardDetail(card.Origin)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
originMsg, err = card2msg(dynamicCard, &co, card.Item.OrigType)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
msg = append(msg, originMsg...)
|
|
||||||
case 2:
|
|
||||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Item.Description))
|
|
||||||
for i := 0; i < len(card.Item.Pictures); i++ {
|
|
||||||
msg = append(msg, message.Image(card.Item.Pictures[i].ImgSrc))
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Item.Content, "\n"))
|
|
||||||
if dynamicCard.Extension.Vote != "" {
|
|
||||||
msg = append(msg, message.Text("【投票】", vote.Desc, "\n",
|
|
||||||
"截止日期: ", time.Unix(int64(vote.Endtime), 0).Format("2006-01-02 15:04:05"), "\n",
|
|
||||||
"参与人数: ", bz.HumanNum(vote.JoinNum), "\n",
|
|
||||||
"投票选项( 最多选择", vote.ChoiceCnt, "项 )\n"))
|
|
||||||
for i := 0; i < len(vote.Options); i++ {
|
|
||||||
msg = append(msg, message.Text("- ", vote.Options[i].Idx, ". ", vote.Options[i].Desc, "\n"))
|
|
||||||
if vote.Options[i].ImgURL != "" {
|
|
||||||
msg = append(msg, message.Image(vote.Options[i].ImgURL))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 8:
|
|
||||||
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Title))
|
|
||||||
msg = append(msg, message.Image(card.Pic))
|
|
||||||
msg = append(msg, message.Text(card.Desc, "\n",
|
|
||||||
card.ShareSubtitle, "\n",
|
|
||||||
"视频链接: ", card.ShortLink, "\n"))
|
|
||||||
case 16:
|
|
||||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Item.Description))
|
|
||||||
msg = append(msg, message.Image(card.Item.Cover.Default))
|
|
||||||
case 64:
|
|
||||||
msg = append(msg, message.Text(card.Author.(map[string]any)["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Title, "\n",
|
|
||||||
card.Summary))
|
|
||||||
for i := 0; i < len(card.ImageUrls); i++ {
|
|
||||||
msg = append(msg, message.Image(card.ImageUrls[i]))
|
|
||||||
}
|
|
||||||
if card.ID != 0 {
|
|
||||||
msg = append(msg, message.Text("文章链接: https://www.bilibili.com/read/cv", card.ID, "\n"))
|
|
||||||
}
|
|
||||||
case 256:
|
|
||||||
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Title))
|
|
||||||
msg = append(msg, message.Image(card.Cover))
|
|
||||||
msg = append(msg, message.Text(card.Intro, "\n"))
|
|
||||||
if card.ID != 0 {
|
|
||||||
msg = append(msg, message.Text("音频链接: https://www.bilibili.com/audio/au", card.ID, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2048:
|
|
||||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
|
||||||
card.Vest.Content, "\n",
|
|
||||||
card.Sketch.Title, "\n",
|
|
||||||
card.Sketch.DescText, "\n"))
|
|
||||||
msg = append(msg, message.Image(card.Sketch.CoverURL))
|
|
||||||
msg = append(msg, message.Text("分享链接: ", card.Sketch.TargetURL, "\n"))
|
|
||||||
case 4308:
|
|
||||||
if dynamicCard.Desc.UserProfile.Info.Uname != "" {
|
|
||||||
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, msgType[cType], "\n"))
|
|
||||||
}
|
|
||||||
msg = append(msg, message.Image(card.LivePlayInfo.Cover))
|
|
||||||
msg = append(msg, message.Text("\n", card.LivePlayInfo.Title, "\n",
|
|
||||||
"房间号: ", card.LivePlayInfo.RoomID, "\n",
|
|
||||||
"分区: ", card.LivePlayInfo.ParentAreaName))
|
|
||||||
if card.LivePlayInfo.ParentAreaName != card.LivePlayInfo.AreaName {
|
|
||||||
msg = append(msg, message.Text("-", card.LivePlayInfo.AreaName))
|
|
||||||
}
|
|
||||||
if card.LivePlayInfo.LiveStatus == 0 {
|
|
||||||
msg = append(msg, message.Text("未开播 \n"))
|
|
||||||
} else {
|
|
||||||
msg = append(msg, message.Text("直播中 ", card.LivePlayInfo.WatchedShow, "\n"))
|
|
||||||
}
|
|
||||||
msg = append(msg, message.Text("直播链接: ", card.LivePlayInfo.Link))
|
|
||||||
default:
|
|
||||||
msg = append(msg, message.Text("动态id: ", dynamicCard.Desc.DynamicIDStr, "未知动态类型: ", cType, "\n"))
|
|
||||||
}
|
|
||||||
if dynamicCard.Desc.DynamicIDStr != "" {
|
|
||||||
msg = append(msg, message.Text("动态链接: ", bz.TURL, dynamicCard.Desc.DynamicIDStr))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// card2msg cType=1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308时,处理Card字符串,cType为card类型
|
|
||||||
func card2msg(dynamicCard *bz.DynamicCard, card *bz.Card, cType int) (msg []message.MessageSegment, err error) {
|
|
||||||
var (
|
|
||||||
vote bz.Vote
|
|
||||||
)
|
|
||||||
msg = make([]message.MessageSegment, 0, 16)
|
|
||||||
// 生成消息
|
|
||||||
switch cType {
|
|
||||||
case 1:
|
|
||||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
|
||||||
card.Item.Content, "\n",
|
|
||||||
"转发的内容: \n"))
|
|
||||||
var originMsg []message.MessageSegment
|
|
||||||
var co bz.Card
|
|
||||||
co, err = bz.LoadCardDetail(card.Origin)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
originMsg, err = card2msg(dynamicCard, &co, card.Item.OrigType)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
msg = append(msg, originMsg...)
|
|
||||||
case 2:
|
|
||||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Item.Description))
|
|
||||||
for i := 0; i < len(card.Item.Pictures); i++ {
|
|
||||||
msg = append(msg, message.Image(card.Item.Pictures[i].ImgSrc))
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Item.Content, "\n"))
|
|
||||||
if dynamicCard.Extension.Vote != "" {
|
|
||||||
msg = append(msg, message.Text("【投票】", vote.Desc, "\n",
|
|
||||||
"截止日期: ", time.Unix(int64(vote.Endtime), 0).Format("2006-01-02 15:04:05"), "\n",
|
|
||||||
"参与人数: ", bz.HumanNum(vote.JoinNum), "\n",
|
|
||||||
"投票选项( 最多选择", vote.ChoiceCnt, "项 )\n"))
|
|
||||||
for i := 0; i < len(vote.Options); i++ {
|
|
||||||
msg = append(msg, message.Text("- ", vote.Options[i].Idx, ". ", vote.Options[i].Desc, "\n"))
|
|
||||||
if vote.Options[i].ImgURL != "" {
|
|
||||||
msg = append(msg, message.Image(vote.Options[i].ImgURL))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 8:
|
|
||||||
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Title))
|
|
||||||
msg = append(msg, message.Image(card.Pic))
|
|
||||||
msg = append(msg, message.Text(card.Desc, "\n",
|
|
||||||
card.ShareSubtitle, "\n",
|
|
||||||
"视频链接: ", card.ShortLink, "\n"))
|
|
||||||
case 16:
|
|
||||||
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Item.Description))
|
|
||||||
msg = append(msg, message.Image(card.Item.Cover.Default))
|
|
||||||
case 64:
|
|
||||||
msg = append(msg, message.Text(card.Author.(map[string]any)["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Title, "\n",
|
|
||||||
card.Summary))
|
|
||||||
for i := 0; i < len(card.ImageUrls); i++ {
|
|
||||||
msg = append(msg, message.Image(card.ImageUrls[i]))
|
|
||||||
}
|
|
||||||
if card.ID != 0 {
|
|
||||||
msg = append(msg, message.Text("文章链接: https://www.bilibili.com/read/cv", card.ID, "\n"))
|
|
||||||
}
|
|
||||||
case 256:
|
|
||||||
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), msgType[cType], "\n",
|
|
||||||
card.Title))
|
|
||||||
msg = append(msg, message.Image(card.Cover))
|
|
||||||
msg = append(msg, message.Text(card.Intro, "\n"))
|
|
||||||
if card.ID != 0 {
|
|
||||||
msg = append(msg, message.Text("音频链接: https://www.bilibili.com/audio/au", card.ID, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2048:
|
|
||||||
msg = append(msg, message.Text(card.User.Uname, msgType[cType], "\n",
|
|
||||||
card.Vest.Content, "\n",
|
|
||||||
card.Sketch.Title, "\n",
|
|
||||||
card.Sketch.DescText, "\n"))
|
|
||||||
msg = append(msg, message.Image(card.Sketch.CoverURL))
|
|
||||||
msg = append(msg, message.Text("分享链接: ", card.Sketch.TargetURL, "\n"))
|
|
||||||
case 4308:
|
|
||||||
if dynamicCard.Desc.UserProfile.Info.Uname != "" {
|
|
||||||
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, msgType[cType], "\n"))
|
|
||||||
}
|
|
||||||
msg = append(msg, message.Image(card.LivePlayInfo.Cover))
|
|
||||||
msg = append(msg, message.Text("\n", card.LivePlayInfo.Title, "\n",
|
|
||||||
"房间号: ", card.LivePlayInfo.RoomID, "\n",
|
|
||||||
"分区: ", card.LivePlayInfo.ParentAreaName))
|
|
||||||
if card.LivePlayInfo.ParentAreaName != card.LivePlayInfo.AreaName {
|
|
||||||
msg = append(msg, message.Text("-", card.LivePlayInfo.AreaName))
|
|
||||||
}
|
|
||||||
if card.LivePlayInfo.LiveStatus == 0 {
|
|
||||||
msg = append(msg, message.Text("未开播 \n"))
|
|
||||||
} else {
|
|
||||||
msg = append(msg, message.Text("直播中 ", card.LivePlayInfo.WatchedShow, "\n"))
|
|
||||||
}
|
|
||||||
msg = append(msg, message.Text("直播链接: ", card.LivePlayInfo.Link))
|
|
||||||
default:
|
|
||||||
msg = append(msg, message.Text("动态id: ", dynamicCard.Desc.DynamicIDStr, "未知动态类型: ", cType, "\n"))
|
|
||||||
}
|
|
||||||
if dynamicCard.Desc.DynamicIDStr != "" {
|
|
||||||
msg = append(msg, message.Text("动态链接: ", bz.TURL, dynamicCard.Desc.DynamicIDStr))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// dynamicDetail 用动态id查动态信息
|
|
||||||
func dynamicDetail(cookiecfg *bz.CookieConfig, dynamicIDStr string) (msg []message.MessageSegment, err error) {
|
|
||||||
dyc, err := bz.GetDynamicDetail(cookiecfg, dynamicIDStr)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return dynamicCard2msg(&dyc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// articleCard2msg 专栏转消息
|
|
||||||
func articleCard2msg(card bz.Card, defaultID string) (msg []message.MessageSegment) {
|
|
||||||
msg = make([]message.MessageSegment, 0, 16)
|
|
||||||
for i := 0; i < len(card.OriginImageUrls); i++ {
|
|
||||||
msg = append(msg, message.Image(card.OriginImageUrls[i]))
|
|
||||||
}
|
|
||||||
msg = append(msg, message.Text("\n", card.Title, "\n", "UP主: ", card.AuthorName, "\n",
|
|
||||||
"阅读: ", bz.HumanNum(card.Stats.View), " 评论: ", bz.HumanNum(card.Stats.Reply), "\n",
|
|
||||||
bz.CVURL, defaultID))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// liveCard2msg 直播卡片转消息
|
|
||||||
func liveCard2msg(card bz.RoomCard) (msg []message.MessageSegment) {
|
|
||||||
msg = make([]message.MessageSegment, 0, 16)
|
|
||||||
msg = append(msg, message.Image(card.RoomInfo.Keyframe))
|
|
||||||
msg = append(msg, message.Text("\n", card.RoomInfo.Title, "\n",
|
|
||||||
"主播: ", card.AnchorInfo.BaseInfo.Uname, "\n",
|
|
||||||
"房间号: ", card.RoomInfo.RoomID, "\n"))
|
|
||||||
if card.RoomInfo.ShortID != 0 {
|
|
||||||
msg = append(msg, message.Text("短号: ", card.RoomInfo.ShortID, "\n"))
|
|
||||||
}
|
|
||||||
msg = append(msg, message.Text("分区: ", card.RoomInfo.ParentAreaName))
|
|
||||||
if card.RoomInfo.ParentAreaName != card.RoomInfo.AreaName {
|
|
||||||
msg = append(msg, message.Text("-", card.RoomInfo.AreaName))
|
|
||||||
}
|
|
||||||
if card.RoomInfo.LiveStatus == 0 {
|
|
||||||
msg = append(msg, message.Text("未开播 \n"))
|
|
||||||
} else {
|
|
||||||
msg = append(msg, message.Text("直播中 ", bz.HumanNum(card.RoomInfo.Online), "人气\n"))
|
|
||||||
}
|
|
||||||
if card.RoomInfo.ShortID != 0 {
|
|
||||||
msg = append(msg, message.Text("直播间链接: ", bz.LURL, card.RoomInfo.ShortID))
|
|
||||||
} else {
|
|
||||||
msg = append(msg, message.Text("直播间链接: ", bz.LURL, card.RoomInfo.RoomID))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// videoCard2msg 视频卡片转消息
|
|
||||||
func videoCard2msg(card bz.Card) (msg []message.MessageSegment, err error) {
|
|
||||||
var mCard bz.MemberCard
|
|
||||||
msg = make([]message.MessageSegment, 0, 16)
|
|
||||||
mCard, err = bz.GetMemberCard(card.Owner.Mid)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
msg = append(msg, message.Text("标题: ", card.Title, "\n"))
|
|
||||||
if card.Rights.IsCooperation == 1 {
|
|
||||||
for i := 0; i < len(card.Staff); i++ {
|
|
||||||
msg = append(msg, message.Text(card.Staff[i].Title, ": ", card.Staff[i].Name, " 粉丝: ", bz.HumanNum(card.Staff[i].Follower), "\n"))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
msg = append(msg, message.Text("UP主: ", card.Owner.Name, " 粉丝: ", bz.HumanNum(mCard.Fans), "\n"))
|
|
||||||
}
|
|
||||||
msg = append(msg, message.Text("播放: ", bz.HumanNum(card.Stat.View), " 弹幕: ", bz.HumanNum(card.Stat.Danmaku)))
|
|
||||||
msg = append(msg, message.Image(card.Pic))
|
|
||||||
msg = append(msg, message.Text("\n点赞: ", bz.HumanNum(card.Stat.Like), " 投币: ", bz.HumanNum(card.Stat.Coin), "\n",
|
|
||||||
"收藏: ", bz.HumanNum(card.Stat.Favorite), " 分享: ", bz.HumanNum(card.Stat.Share), "\n",
|
|
||||||
bz.VURL, card.BvID, "\n\n"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
package bilibili
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestArticleInfo(t *testing.T) {
|
|
||||||
card, err := bz.GetArticleInfo("17279244")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log(articleCard2msg(card, "17279244"))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMemberCard(t *testing.T) {
|
|
||||||
card, err := bz.GetMemberCard(2)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Logf("%+v\n", card)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVideoInfo(t *testing.T) {
|
|
||||||
card, err := bz.GetVideoInfo("10007")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log(videoCard2msg(card))
|
|
||||||
card, err = bz.GetVideoInfo("BV1xx411c7mD")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log(videoCard2msg(card))
|
|
||||||
card, err = bz.GetVideoInfo("bv1xx411c7mD")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log(videoCard2msg(card))
|
|
||||||
card, err = bz.GetVideoInfo("BV1mF411j7iU")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log(videoCard2msg(card))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLiveRoomInfo(t *testing.T) {
|
|
||||||
card, err := bz.GetLiveRoomInfo("83171")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
t.Log(liveCard2msg(card))
|
|
||||||
}
|
|
||||||
@ -1,26 +1,35 @@
|
|||||||
// Package bilibili bilibili卡片解析
|
// Package bilibiliparse bilibili卡片解析
|
||||||
package bilibili
|
package bilibiliparse
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||||
|
"github.com/FloatTech/floatbox/file"
|
||||||
"github.com/FloatTech/floatbox/web"
|
"github.com/FloatTech/floatbox/web"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
"github.com/pkg/errors"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
enableHex = 0x10
|
enableVideoSummary = int64(0x10)
|
||||||
unableHex = 0x7fffffff_fffffffd
|
disableVideoSummary = ^enableVideoSummary
|
||||||
|
enableVideoDownload = int64(0x20)
|
||||||
|
disableVideoDownload = ^enableVideoDownload
|
||||||
|
bilibiliparseReferer = "https://www.bilibili.com"
|
||||||
|
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -33,15 +42,20 @@ var (
|
|||||||
searchDynamicRe = regexp.MustCompile(searchDynamic)
|
searchDynamicRe = regexp.MustCompile(searchDynamic)
|
||||||
searchArticleRe = regexp.MustCompile(searchArticle)
|
searchArticleRe = regexp.MustCompile(searchArticle)
|
||||||
searchLiveRoomRe = regexp.MustCompile(searchLiveRoom)
|
searchLiveRoomRe = regexp.MustCompile(searchLiveRoom)
|
||||||
|
cachePath string
|
||||||
|
cfg = bz.NewCookieConfig("data/Bilibili/config.json")
|
||||||
)
|
)
|
||||||
|
|
||||||
// 插件主体
|
// 插件主体
|
||||||
func init() {
|
func init() {
|
||||||
en := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{
|
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
DisableOnDefault: false,
|
DisableOnDefault: false,
|
||||||
Brief: "b站链接解析",
|
Brief: "b站链接解析",
|
||||||
Help: "例:- t.bilibili.com/642277677329285174\n- bilibili.com/read/cv17134450\n- bilibili.com/video/BV13B4y1x7pS\n- live.bilibili.com/22603245 ",
|
Help: "例:- t.bilibili.com/642277677329285174\n- bilibili.com/read/cv17134450\n- bilibili.com/video/BV13B4y1x7pS\n- live.bilibili.com/22603245 ",
|
||||||
})
|
})
|
||||||
|
cachePath = en.DataFolder() + "cache/"
|
||||||
|
_ = os.RemoveAll(cachePath)
|
||||||
|
_ = os.MkdirAll(cachePath, 0755)
|
||||||
en.OnRegex(`((b23|acg).tv|bili2233.cn)\\?/[0-9a-zA-Z]+`).SetBlock(true).Limit(limit.LimitByGroup).
|
en.OnRegex(`((b23|acg).tv|bili2233.cn)\\?/[0-9a-zA-Z]+`).SetBlock(true).Limit(limit.LimitByGroup).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
u := ctx.State["regex_matched"].([]string)[0]
|
u := ctx.State["regex_matched"].([]string)[0]
|
||||||
@ -82,9 +96,9 @@ func init() {
|
|||||||
data := c.GetData(ctx.Event.GroupID)
|
data := c.GetData(ctx.Event.GroupID)
|
||||||
switch option {
|
switch option {
|
||||||
case "开启", "打开", "启用":
|
case "开启", "打开", "启用":
|
||||||
data |= enableHex
|
data |= enableVideoSummary
|
||||||
case "关闭", "关掉", "禁用":
|
case "关闭", "关掉", "禁用":
|
||||||
data &= unableHex
|
data &= disableVideoSummary
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -95,6 +109,35 @@ func init() {
|
|||||||
}
|
}
|
||||||
ctx.SendChain(message.Text("已", option, "视频总结"))
|
ctx.SendChain(message.Text("已", option, "视频总结"))
|
||||||
})
|
})
|
||||||
|
en.OnRegex(`^(开启|打开|启用|关闭|关掉|禁用)视频上传$`, zero.AdminPermission).SetBlock(true).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
gid := ctx.Event.GroupID
|
||||||
|
if gid <= 0 {
|
||||||
|
// 个人用户设为负数
|
||||||
|
gid = -ctx.Event.UserID
|
||||||
|
}
|
||||||
|
option := ctx.State["regex_matched"].([]string)[1]
|
||||||
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
|
if !ok {
|
||||||
|
ctx.SendChain(message.Text("找不到服务!"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := c.GetData(ctx.Event.GroupID)
|
||||||
|
switch option {
|
||||||
|
case "开启", "打开", "启用":
|
||||||
|
data |= enableVideoDownload
|
||||||
|
case "关闭", "关掉", "禁用":
|
||||||
|
data &= disableVideoDownload
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := c.SetData(gid, data)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("出错啦: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text("已", option, "视频上传"))
|
||||||
|
})
|
||||||
en.OnRegex(searchVideo).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleVideo)
|
en.OnRegex(searchVideo).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleVideo)
|
||||||
en.OnRegex(searchDynamic).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleDynamic)
|
en.OnRegex(searchDynamic).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleDynamic)
|
||||||
en.OnRegex(searchArticle).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleArticle)
|
en.OnRegex(searchArticle).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleArticle)
|
||||||
@ -111,13 +154,13 @@ func handleVideo(ctx *zero.Ctx) {
|
|||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg, err := videoCard2msg(card)
|
msg, err := card.ToVideoMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||||
if ok && c.GetData(ctx.Event.GroupID)&enableHex == enableHex {
|
if ok && c.GetData(ctx.Event.GroupID)&enableVideoSummary == enableVideoSummary {
|
||||||
summaryMsg, err := getVideoSummary(cfg, card)
|
summaryMsg, err := getVideoSummary(cfg, card)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg = append(msg, message.Text("ERROR: ", err))
|
msg = append(msg, message.Text("ERROR: ", err))
|
||||||
@ -126,10 +169,18 @@ func handleVideo(ctx *zero.Ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.SendChain(msg...)
|
ctx.SendChain(msg...)
|
||||||
|
if ok && c.GetData(ctx.Event.GroupID)&enableVideoDownload == enableVideoDownload {
|
||||||
|
downLoadMsg, err := getVideoDownload(cfg, card, cachePath)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(downLoadMsg...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDynamic(ctx *zero.Ctx) {
|
func handleDynamic(ctx *zero.Ctx) {
|
||||||
msg, err := dynamicDetail(cfg, ctx.State["regex_matched"].([]string)[2])
|
msg, err := cfg.GetDetailMessage(ctx.State["regex_matched"].([]string)[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
@ -143,20 +194,25 @@ func handleArticle(ctx *zero.Ctx) {
|
|||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.SendChain(articleCard2msg(card, ctx.State["regex_matched"].([]string)[1])...)
|
ctx.SendChain(card.ToArticleMessage(ctx.State["regex_matched"].([]string)[1])...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleLive(ctx *zero.Ctx) {
|
func handleLive(ctx *zero.Ctx) {
|
||||||
card, err := bz.GetLiveRoomInfo(ctx.State["regex_matched"].([]string)[1])
|
cookie, err := cfg.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.SendChain(liveCard2msg(card)...)
|
card, err := bz.GetLiveRoomInfo(ctx.State["regex_matched"].([]string)[1], cookie)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.SendChain(card.ToMessage()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getVideoSummary AI视频总结
|
// getVideoSummary AI视频总结
|
||||||
func getVideoSummary(cookiecfg *bz.CookieConfig, card bz.Card) (msg []message.MessageSegment, err error) {
|
func getVideoSummary(cookiecfg *bz.CookieConfig, card bz.Card) (msg []message.Segment, err error) {
|
||||||
var (
|
var (
|
||||||
data []byte
|
data []byte
|
||||||
videoSummary bz.VideoSummary
|
videoSummary bz.VideoSummary
|
||||||
@ -177,7 +233,7 @@ func getVideoSummary(cookiecfg *bz.CookieConfig, card bz.Card) (msg []message.Me
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(data, &videoSummary)
|
err = json.Unmarshal(data, &videoSummary)
|
||||||
msg = make([]message.MessageSegment, 0, 16)
|
msg = make([]message.Segment, 0, 16)
|
||||||
msg = append(msg, message.Text("已为你生成视频总结\n\n"))
|
msg = append(msg, message.Text("已为你生成视频总结\n\n"))
|
||||||
msg = append(msg, message.Text(videoSummary.Data.ModelResult.Summary, "\n\n"))
|
msg = append(msg, message.Text(videoSummary.Data.ModelResult.Summary, "\n\n"))
|
||||||
for _, v := range videoSummary.Data.ModelResult.Outline {
|
for _, v := range videoSummary.Data.ModelResult.Outline {
|
||||||
@ -189,3 +245,47 @@ func getVideoSummary(cookiecfg *bz.CookieConfig, card bz.Card) (msg []message.Me
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getVideoDownload(cookiecfg *bz.CookieConfig, card bz.Card, cachePath string) (msg []message.Segment, err error) {
|
||||||
|
var (
|
||||||
|
data []byte
|
||||||
|
videoDownload bz.VideoDownload
|
||||||
|
stderr bytes.Buffer
|
||||||
|
)
|
||||||
|
today := time.Now().Format("20060102")
|
||||||
|
videoFile := fmt.Sprintf("%s%s%s.mp4", cachePath, card.BvID, today)
|
||||||
|
if file.IsExist(videoFile) {
|
||||||
|
msg = append(msg, message.Video("file:///"+file.BOTPATH+"/"+videoFile))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err = web.RequestDataWithHeaders(web.NewDefaultClient(), bz.SignURL(fmt.Sprintf(bz.VideoDownloadURL, card.BvID, card.CID)), "GET", func(req *http.Request) error {
|
||||||
|
if cookiecfg != nil {
|
||||||
|
cookie := ""
|
||||||
|
cookie, err = cookiecfg.Load()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req.Header.Add("cookie", cookie)
|
||||||
|
}
|
||||||
|
req.Header.Set("User-Agent", ua)
|
||||||
|
return nil
|
||||||
|
}, nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(data, &videoDownload)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
headers := fmt.Sprintf("User-Agent: %s\nReferer: %s", ua, bilibiliparseReferer)
|
||||||
|
// 限制最多下载8分钟视频
|
||||||
|
cmd := exec.Command("ffmpeg", "-ss", "0", "-t", "480", "-headers", headers, "-i", videoDownload.Data.Durl[0].URL, "-c", "copy", videoFile)
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Errorf("未配置ffmpeg,%v", stderr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg = append(msg, message.Video("file:///"+file.BOTPATH+"/"+videoFile))
|
||||||
|
return
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
// Package bilibili b站推送
|
// Package bilibilipush b站推送
|
||||||
package bilibili
|
package bilibilipush
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -34,10 +34,11 @@ var (
|
|||||||
lastTime = map[int64]int64{}
|
lastTime = map[int64]int64{}
|
||||||
liveStatus = map[int64]int{}
|
liveStatus = map[int64]int{}
|
||||||
upMap = map[int64]string{}
|
upMap = map[int64]string{}
|
||||||
|
cfg = bz.NewCookieConfig("data/Bilibili/config.json")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
en := control.Register("bilibilipush", &ctrl.Options[*zero.Ctx]{
|
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
DisableOnDefault: false,
|
DisableOnDefault: false,
|
||||||
Brief: "b站推送",
|
Brief: "b站推送",
|
||||||
Help: "- 添加b站订阅[uid|name]\n" +
|
Help: "- 添加b站订阅[uid|name]\n" +
|
||||||
@ -75,7 +76,7 @@ func init() {
|
|||||||
ctx.SendChain(message.Text("已关闭艾特全体Oo"))
|
ctx.SendChain(message.Text("已关闭艾特全体Oo"))
|
||||||
})
|
})
|
||||||
|
|
||||||
en.OnRegex(`^添加[B|b]站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
en.OnRegex(`^添加[B|b]站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
||||||
name, err := getName(buid, cfg)
|
name, err := getName(buid, cfg)
|
||||||
if err != nil || name == "" {
|
if err != nil || name == "" {
|
||||||
@ -93,7 +94,7 @@ func init() {
|
|||||||
ctx.SendChain(message.Text("已添加" + name + "的订阅"))
|
ctx.SendChain(message.Text("已添加" + name + "的订阅"))
|
||||||
})
|
})
|
||||||
|
|
||||||
en.OnRegex(`^取消[B|b]站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
en.OnRegex(`^取消[B|b]站订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
||||||
name, err := getName(buid, cfg)
|
name, err := getName(buid, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -110,7 +111,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
ctx.SendChain(message.Text("已取消" + name + "的订阅"))
|
ctx.SendChain(message.Text("已取消" + name + "的订阅"))
|
||||||
})
|
})
|
||||||
en.OnRegex(`^取消[B|b]站动态订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
en.OnRegex(`^取消[B|b]站动态订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
||||||
name, err := getName(buid, cfg)
|
name, err := getName(buid, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -127,7 +128,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
ctx.SendChain(message.Text("已取消" + name + "的动态订阅"))
|
ctx.SendChain(message.Text("已取消" + name + "的动态订阅"))
|
||||||
})
|
})
|
||||||
en.OnRegex(`^取消[B|b]站直播订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, getPara).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
en.OnRegex(`^取消[B|b]站直播订阅\s?(.{1,25})$`, zero.UserOrGrpAdmin, bz.RequireUser(cfg)).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
buid, _ := strconv.ParseInt(ctx.State["uid"].(string), 10, 64)
|
||||||
gid := ctx.Event.GroupID
|
gid := ctx.Event.GroupID
|
||||||
if gid == 0 {
|
if gid == 0 {
|
||||||
@ -333,7 +334,7 @@ func sendDynamic(ctx *zero.Ctx) error {
|
|||||||
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
msg, err := dynamicCard2msg(&dc)
|
msg, err := dc.ToMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
||||||
return err
|
return err
|
||||||
@ -388,7 +389,7 @@ func sendLive(ctx *zero.Ctx) error {
|
|||||||
if lCover == "" {
|
if lCover == "" {
|
||||||
lCover = value.Get("keyframe").String()
|
lCover = value.Get("keyframe").String()
|
||||||
}
|
}
|
||||||
var msg []message.MessageSegment
|
var msg []message.Segment
|
||||||
msg = append(msg, message.Text(lName+" 正在直播:\n"))
|
msg = append(msg, message.Text(lName+" 正在直播:\n"))
|
||||||
msg = append(msg, message.Text(lTitle))
|
msg = append(msg, message.Text(lTitle))
|
||||||
msg = append(msg, message.Image(lCover))
|
msg = append(msg, message.Image(lCover))
|
||||||
@ -399,7 +400,7 @@ func sendLive(ctx *zero.Ctx) error {
|
|||||||
switch {
|
switch {
|
||||||
case gid > 0:
|
case gid > 0:
|
||||||
if res := bdb.getAtAll(gid); res == 1 {
|
if res := bdb.getAtAll(gid); res == 1 {
|
||||||
msg = append([]message.MessageSegment{message.AtAll()}, msg...)
|
msg = append([]message.Segment{message.AtAll()}, msg...)
|
||||||
}
|
}
|
||||||
ctx.SendGroupMessage(gid, msg)
|
ctx.SendGroupMessage(gid, msg)
|
||||||
case gid < 0:
|
case gid < 0:
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package bilibili
|
package bilibilipush
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/FloatTech/floatbox/binary"
|
"github.com/FloatTech/floatbox/binary"
|
||||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/img/text"
|
"github.com/FloatTech/zbputils/img/text"
|
||||||
@ -24,7 +25,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
db.DBPath = engine.DataFolder() + "bookreview.db"
|
db = sql.New(engine.DataFolder() + "bookreview.db")
|
||||||
// os.RemoveAll(dbpath)
|
// os.RemoveAll(dbpath)
|
||||||
_, _ = engine.GetLazyData("bookreview.db", true)
|
_, _ = engine.GetLazyData("bookreview.db", true)
|
||||||
err := db.Open(time.Hour)
|
err := db.Open(time.Hour)
|
||||||
|
|||||||
@ -7,11 +7,11 @@ type book struct {
|
|||||||
BookReview string `db:"bookreview"`
|
BookReview string `db:"bookreview"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var db = &sql.Sqlite{}
|
var db sql.Sqlite
|
||||||
|
|
||||||
// 暂时随机选择一个书评
|
// 暂时随机选择一个书评
|
||||||
func getBookReviewByKeyword(keyword string) (b book) {
|
func getBookReviewByKeyword(keyword string) (b book) {
|
||||||
_ = db.Find("bookreview", &b, "where bookreview LIKE '%"+keyword+"%'")
|
_ = db.Find("bookreview", &b, "WHERE bookreview LIKE ?", "%"+keyword+"%")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,15 +3,21 @@ package chatcount
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"sync"
|
||||||
|
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
|
"github.com/FloatTech/floatbox/file"
|
||||||
|
"github.com/FloatTech/imgfactory"
|
||||||
|
"github.com/FloatTech/rendercard"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
"github.com/FloatTech/zbputils/img/text"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -37,28 +43,66 @@ func init() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
engine.OnPrefix(`查询水群`, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
engine.OnPrefix(`查询水群`, zero.OnlyGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
param := ctx.State["args"].(string)
|
||||||
|
var uid int64
|
||||||
|
if len(ctx.Event.Message) > 1 && ctx.Event.Message[1].Type == "at" {
|
||||||
|
uid, _ = strconv.ParseInt(ctx.Event.Message[1].Data["qq"], 10, 64)
|
||||||
|
} else if param == "" {
|
||||||
|
uid = ctx.Event.UserID
|
||||||
|
}
|
||||||
name := ctx.NickName()
|
name := ctx.NickName()
|
||||||
todayTime, todayMessage, totalTime, totalMessage := ctdb.getChatTime(ctx.Event.GroupID, ctx.Event.UserID)
|
todayTime, todayMessage, totalTime, totalMessage := ctdb.getChatTime(ctx.Event.GroupID, uid)
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf("%s今天水了%d分%d秒,发了%d条消息;总计水了%d分%d秒,发了%d条消息。", name, todayTime/60, todayTime%60, todayMessage, totalTime/60, totalTime%60, totalMessage)))
|
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(fmt.Sprintf("%s今天水了%d分%d秒,发了%d条消息;总计水了%d分%d秒,发了%d条消息。", name, todayTime/60, todayTime%60, todayMessage, totalTime/60, totalTime%60, totalMessage)))
|
||||||
})
|
})
|
||||||
engine.OnFullMatch("查看水群排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
|
engine.OnFullMatch("查看水群排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
text := strings.Builder{}
|
|
||||||
text.WriteString("今日水群排行榜:\n")
|
|
||||||
chatTimeList := ctdb.getChatRank(ctx.Event.GroupID)
|
chatTimeList := ctdb.getChatRank(ctx.Event.GroupID)
|
||||||
for i := 0; i < len(chatTimeList) && i < rankSize; i++ {
|
if len(chatTimeList) == 0 {
|
||||||
text.WriteString("第")
|
ctx.SendChain(message.Text("ERROR: 没有水群数据"))
|
||||||
text.WriteString(strconv.Itoa(i + 1))
|
return
|
||||||
text.WriteString("名:")
|
}
|
||||||
text.WriteString(ctx.CardOrNickName(chatTimeList[i].UserID))
|
rankinfo := make([]*rendercard.RankInfo, len(chatTimeList))
|
||||||
text.WriteString(" - ")
|
|
||||||
text.WriteString(strconv.FormatInt(chatTimeList[i].TodayMessage, 10))
|
wg := &sync.WaitGroup{}
|
||||||
text.WriteString("条,共")
|
wg.Add(len(chatTimeList))
|
||||||
text.WriteString(strconv.FormatInt(chatTimeList[i].TodayTime/60, 10))
|
for i := 0; i < len(chatTimeList) && i < rankSize; i++ {
|
||||||
text.WriteString("分")
|
go func(i int) {
|
||||||
text.WriteString(strconv.FormatInt(chatTimeList[i].TodayTime%60, 10))
|
defer wg.Done()
|
||||||
text.WriteString("秒\n")
|
resp, err := http.Get("https://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(chatTimeList[i].UserID, 10) + "&s=100")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
img, _, err := image.Decode(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rankinfo[i] = &rendercard.RankInfo{
|
||||||
|
TopLeftText: ctx.CardOrNickName(chatTimeList[i].UserID),
|
||||||
|
BottomLeftText: "消息数: " + strconv.FormatInt(chatTimeList[i].TodayMessage, 10) + " 条",
|
||||||
|
RightText: strconv.FormatInt(chatTimeList[i].TodayTime/60, 10) + "分" + strconv.FormatInt(chatTimeList[i].TodayTime%60, 10) + "秒",
|
||||||
|
Avatar: img,
|
||||||
|
}
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
fontbyte, err := file.GetLazyData(text.GlowSansFontFile, control.Md5File, true)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
img, err := rendercard.DrawRankingCard(fontbyte, "今日水群排行榜", rankinfo)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sendimg, err := imgfactory.ToBytes(img)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if id := ctx.SendChain(message.ImageBytes(sendimg)); id.ID() == 0 {
|
||||||
|
ctx.SendChain(message.Text("ERROR: 可能被风控了"))
|
||||||
}
|
}
|
||||||
ctx.SendChain(message.Text(text.String()))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import (
|
|||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,16 +34,7 @@ var (
|
|||||||
Brief: "国际象棋",
|
Brief: "国际象棋",
|
||||||
Help: helpString,
|
Help: helpString,
|
||||||
PrivateDataFolder: "chess",
|
PrivateDataFolder: "chess",
|
||||||
}).ApplySingle(single.New(
|
}).ApplySingle(ctxext.GroupSingle)
|
||||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
|
||||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
|
||||||
ctx.Send(
|
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
|
||||||
message.Text("有操作正在执行, 请稍后再试..."),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@ -235,7 +235,7 @@ func play(groupCode, senderUin int64, moveStr string) (msg message.Message, err
|
|||||||
chessRoomMap.Store(groupCode, room)
|
chessRoomMap.Store(groupCode, room)
|
||||||
}
|
}
|
||||||
// 生成棋盘图片
|
// 生成棋盘图片
|
||||||
var boardImgEle message.MessageSegment
|
var boardImgEle message.Segment
|
||||||
if !room.isBlindfold {
|
if !room.isBlindfold {
|
||||||
boardImgEle, err = getBoardElement(groupCode)
|
boardImgEle, err = getBoardElement(groupCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -400,7 +400,7 @@ func createGame(isBlindfold bool, groupCode, senderUin int64, senderName string)
|
|||||||
room.blackPlayer = senderUin
|
room.blackPlayer = senderUin
|
||||||
room.blackName = senderName
|
room.blackName = senderName
|
||||||
chessRoomMap.Store(groupCode, room)
|
chessRoomMap.Store(groupCode, room)
|
||||||
var boardImgEle message.MessageSegment
|
var boardImgEle message.Segment
|
||||||
if !room.isBlindfold {
|
if !room.isBlindfold {
|
||||||
boardImgEle, err = getBoardElement(groupCode)
|
boardImgEle, err = getBoardElement(groupCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -442,7 +442,7 @@ func abortGame(room chessRoom, groupCode int64, hint string) (message.Message, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getBoardElement 获取棋盘图片的消息内容
|
// getBoardElement 获取棋盘图片的消息内容
|
||||||
func getBoardElement(groupCode int64) (imgMsg message.MessageSegment, err error) {
|
func getBoardElement(groupCode int64) (imgMsg message.Segment, err error) {
|
||||||
fontdata, err := file.GetLazyData(text.GNUUnifontFontFile, control.Md5File, true)
|
fontdata, err := file.GetLazyData(text.GNUUnifontFontFile, control.Md5File, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
)
|
)
|
||||||
@ -23,7 +24,7 @@ func init() {
|
|||||||
|
|
||||||
en.OnRegex("^抽象翻译((\\s|[\\r\\n]|[\\p{Han}\\p{P}A-Za-z0-9])+)$",
|
en.OnRegex("^抽象翻译((\\s|[\\r\\n]|[\\p{Han}\\p{P}A-Za-z0-9])+)$",
|
||||||
fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
db.DBPath = en.DataFolder() + "cxh.db"
|
db = sql.New(en.DataFolder() + "cxh.db")
|
||||||
// os.RemoveAll(dbpath)
|
// os.RemoveAll(dbpath)
|
||||||
_, _ = en.GetLazyData("cxh.db", true)
|
_, _ = en.GetLazyData("cxh.db", true)
|
||||||
err := db.Open(time.Hour)
|
err := db.Open(time.Hour)
|
||||||
|
|||||||
@ -11,11 +11,11 @@ type emoji struct {
|
|||||||
Emoji string `db:"emoji"`
|
Emoji string `db:"emoji"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var db = &sql.Sqlite{}
|
var db sql.Sqlite
|
||||||
|
|
||||||
func getPinyinByWord(word string) string {
|
func getPinyinByWord(word string) string {
|
||||||
var p pinyin
|
var p pinyin
|
||||||
_ = db.Find("pinyin", &p, "where word = '"+word+"'")
|
_ = db.Find("pinyin", &p, "WHERE word = ?", word)
|
||||||
return p.Pronun
|
return p.Pronun
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,6 +25,6 @@ func getPronunByDWord(w0, w1 rune) string {
|
|||||||
|
|
||||||
func getEmojiByPronun(pronun string) string {
|
func getEmojiByPronun(pronun string) string {
|
||||||
var e emoji
|
var e emoji
|
||||||
_ = db.Find("emoji", &e, "where pronunciation = '"+pronun+"'")
|
_ = db.Find("emoji", &e, "WHERE pronunciation = ?", pronun)
|
||||||
return e.Emoji
|
return e.Emoji
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import (
|
|||||||
|
|
||||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||||
"github.com/FloatTech/floatbox/math"
|
"github.com/FloatTech/floatbox/math"
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
)
|
)
|
||||||
@ -24,7 +25,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
db.DBPath = engine.DataFolder() + "cp.db"
|
db = sql.New(engine.DataFolder() + "cp.db")
|
||||||
// os.RemoveAll(dbpath)
|
// os.RemoveAll(dbpath)
|
||||||
_, _ = engine.GetLazyData("cp.db", true)
|
_, _ = engine.GetLazyData("cp.db", true)
|
||||||
err := db.Open(time.Hour)
|
err := db.Open(time.Hour)
|
||||||
|
|||||||
@ -9,7 +9,7 @@ type cpstory struct {
|
|||||||
Story string `db:"story"`
|
Story string `db:"story"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var db = &sql.Sqlite{}
|
var db sql.Sqlite
|
||||||
|
|
||||||
func getRandomCpStory() (cs cpstory) {
|
func getRandomCpStory() (cs cpstory) {
|
||||||
_ = db.Pick("cp_story", &cs)
|
_ = db.Pick("cp_story", &cs)
|
||||||
|
|||||||
95
plugin/crypter/fumo.go
Normal file
95
plugin/crypter/fumo.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Package crypter Fumo语
|
||||||
|
package crypter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Base64字符表
|
||||||
|
const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
|
||||||
|
// Fumo语字符表 - 使用各种fumo变体来表示base64字符
|
||||||
|
var fumoChars = []string{
|
||||||
|
"fumo-", "Fumo-", "fUmo-", "fuMo-", "fumO-", "FUmo-", "FuMo-", "FumO-",
|
||||||
|
"fUMo-", "fUmO-", "fuMO-", "FUMo-", "FUmO-", "fUMO-", "FUMO-", "fumo.",
|
||||||
|
"Fumo.", "fUmo.", "fuMo.", "fumO.", "FUmo.", "FuMo.", "FumO.", "fUMo.",
|
||||||
|
"fUmO.", "fuMO.", "FUMo.", "FUmO.", "fUMO.", "FUMO.", "fumo,", "Fumo,",
|
||||||
|
"fUmo,", "fuMo,", "fumO,", "FUmo,", "FuMo,", "FumO,", "fUMo,", "fUmO,",
|
||||||
|
"fuMO,", "FUMo,", "FuMO,", "fUMO,", "FUMO,", "fumo+", "Fumo+", "fUmo+",
|
||||||
|
"fuMo+", "fumO+", "FUmo+", "FuMo+", "FumO+", "fUMo+", "fUmO+", "fuMO+",
|
||||||
|
"FUMo+", "FUmO+", "fUMO+", "FUMO+", "fumo|", "Fumo|", "fUmo|", "fuMo|",
|
||||||
|
"fumO|", "FUmo|", "FuMo|", "FumO|", "fUMo|", "fUmO|", "fuMO|", "fumo/",
|
||||||
|
"Fumo/", "fUmo/",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base64 2 Fumo
|
||||||
|
// 创建编码映射表
|
||||||
|
var encodeMap = make(map[byte]string)
|
||||||
|
|
||||||
|
// 创建解码映射表
|
||||||
|
var decodeMap = make(map[string]byte)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := 0; i < 64 && i < len(fumoChars); i++ {
|
||||||
|
base64Char := base64Chars[i]
|
||||||
|
fumoChar := fumoChars[i]
|
||||||
|
|
||||||
|
encodeMap[base64Char] = fumoChar
|
||||||
|
decodeMap[fumoChar] = base64Char
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加密
|
||||||
|
func encryptFumo(text string) string {
|
||||||
|
if text == "" {
|
||||||
|
return "请输入要加密的文本"
|
||||||
|
}
|
||||||
|
textBytes := []byte(text)
|
||||||
|
base64String := base64.StdEncoding.EncodeToString(textBytes)
|
||||||
|
base64Body := strings.TrimRight(base64String, "=")
|
||||||
|
paddingCount := len(base64String) - len(base64Body)
|
||||||
|
var fumoBody strings.Builder
|
||||||
|
for _, char := range base64Body {
|
||||||
|
if fumoChar, exists := encodeMap[byte(char)]; exists {
|
||||||
|
fumoBody.WriteString(fumoChar)
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("Fumo加密失败: 未知字符 %c", char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result := fumoBody.String() + strings.Repeat("=", paddingCount)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解密
|
||||||
|
func decryptFumo(fumoText string) string {
|
||||||
|
if fumoText == "" {
|
||||||
|
return "请输入要解密的Fumo语密文"
|
||||||
|
}
|
||||||
|
fumoBody := strings.TrimRight(fumoText, "=")
|
||||||
|
paddingCount := len(fumoText) - len(fumoBody)
|
||||||
|
fumoPattern := regexp.MustCompile(`(\w+[-.,+|/])`)
|
||||||
|
fumoWords := fumoPattern.FindAllString(fumoBody, -1)
|
||||||
|
reconstructed := strings.Join(fumoWords, "")
|
||||||
|
if reconstructed != fumoBody {
|
||||||
|
return "Fumo解密失败: 包含无效的Fumo字符或格式错误"
|
||||||
|
}
|
||||||
|
var base64Body strings.Builder
|
||||||
|
for _, fumoWord := range fumoWords {
|
||||||
|
if base64Char, exists := decodeMap[fumoWord]; exists {
|
||||||
|
base64Body.WriteByte(base64Char)
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("Fumo解密失败: 包含无效的Fumo字符 %s", fumoWord)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base64String := base64Body.String() + strings.Repeat("=", paddingCount)
|
||||||
|
decodedBytes, err := base64.StdEncoding.DecodeString(base64String)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("Fumo解密失败: Base64解码错误 %v", err)
|
||||||
|
}
|
||||||
|
originalText := string(decodedBytes)
|
||||||
|
return originalText
|
||||||
|
}
|
||||||
42
plugin/crypter/handlers.go
Normal file
42
plugin/crypter/handlers.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Package crypter 处理函数
|
||||||
|
package crypter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/FloatTech/AnimeAPI/airecord"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
// hou
|
||||||
|
func houEncryptHandler(ctx *zero.Ctx) {
|
||||||
|
text := ctx.State["regex_matched"].([]string)[1]
|
||||||
|
result := encodeHou(text)
|
||||||
|
logrus.Infoln("[crypter] 回复内容:", result)
|
||||||
|
recCfg := airecord.GetConfig()
|
||||||
|
record := ctx.GetAIRecord(recCfg.ModelID, recCfg.Customgid, result)
|
||||||
|
if record != "" {
|
||||||
|
ctx.SendChain(message.Record(record))
|
||||||
|
} else {
|
||||||
|
ctx.SendChain(message.Text(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func houDecryptHandler(ctx *zero.Ctx) {
|
||||||
|
text := ctx.State["regex_matched"].([]string)[1]
|
||||||
|
result := decodeHou(text)
|
||||||
|
ctx.SendChain(message.Text(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
// fumo
|
||||||
|
func fumoEncryptHandler(ctx *zero.Ctx) {
|
||||||
|
text := ctx.State["regex_matched"].([]string)[1]
|
||||||
|
result := encryptFumo(text)
|
||||||
|
ctx.SendChain(message.Text(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
func fumoDecryptHandler(ctx *zero.Ctx) {
|
||||||
|
text := ctx.State["regex_matched"].([]string)[1]
|
||||||
|
result := decryptFumo(text)
|
||||||
|
ctx.SendChain(message.Text(result))
|
||||||
|
}
|
||||||
88
plugin/crypter/hou.go
Normal file
88
plugin/crypter/hou.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// Package crypter 齁语加解密
|
||||||
|
package crypter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 齁语密码表
|
||||||
|
var houCodebook = []string{
|
||||||
|
"齁", "哦", "噢", "喔", "咕", "咿", "嗯", "啊",
|
||||||
|
"~", "哈", "!", "唔", "哼", "❤", "呃", "呼",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 索引: 0 1 2 3 4 5 6 7
|
||||||
|
// 8 9 10 11 12 13 14 15
|
||||||
|
|
||||||
|
// 创建映射表
|
||||||
|
var houCodebookMap = make(map[string]int)
|
||||||
|
|
||||||
|
// 初始化映射表
|
||||||
|
func init() {
|
||||||
|
for idx, ch := range houCodebook {
|
||||||
|
houCodebookMap[ch] = idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeHou(text string) string {
|
||||||
|
if text == "" {
|
||||||
|
return "请输入要加密的文本"
|
||||||
|
}
|
||||||
|
var encoded strings.Builder
|
||||||
|
textBytes := []byte(text)
|
||||||
|
for _, b := range textBytes {
|
||||||
|
high := (b >> 4) & 0x0F
|
||||||
|
low := b & 0x0F
|
||||||
|
encoded.WriteString(houCodebook[high])
|
||||||
|
encoded.WriteString(houCodebook[low])
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoded.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeHou(code string) string {
|
||||||
|
if code == "" {
|
||||||
|
return "请输入要解密的齁语密文"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤出有效的齁语字符
|
||||||
|
var validChars []string
|
||||||
|
for _, r := range code {
|
||||||
|
charStr := string(r)
|
||||||
|
if _, exists := houCodebookMap[charStr]; exists {
|
||||||
|
validChars = append(validChars, charStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(validChars)%2 != 0 {
|
||||||
|
return "齁语密文长度错误,无法解密"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解密过程
|
||||||
|
var byteList []byte
|
||||||
|
for i := 0; i < len(validChars); i += 2 {
|
||||||
|
highIdx, highExists := houCodebookMap[validChars[i]]
|
||||||
|
lowIdx, lowExists := houCodebookMap[validChars[i+1]]
|
||||||
|
|
||||||
|
if !highExists || !lowExists {
|
||||||
|
return "齁语密文包含无效字符"
|
||||||
|
}
|
||||||
|
|
||||||
|
originalByte := byte((highIdx << 4) | lowIdx)
|
||||||
|
byteList = append(byteList, originalByte)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := string(byteList)
|
||||||
|
|
||||||
|
if !isValidUTF8(result) {
|
||||||
|
return "齁语解密失败,结果不是有效的文本"
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查字符串是否为有效的UTF-8编码
|
||||||
|
func isValidUTF8(s string) bool {
|
||||||
|
// Go的string类型默认就是UTF-8,如果转换没有出错说明是有效的
|
||||||
|
return len(s) > 0 || s == ""
|
||||||
|
}
|
||||||
31
plugin/crypter/main.go
Normal file
31
plugin/crypter/main.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Package crypter 奇怪语言加解密
|
||||||
|
package crypter
|
||||||
|
|
||||||
|
import (
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/control"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
|
DisableOnDefault: false,
|
||||||
|
Brief: "奇怪语言加解密",
|
||||||
|
Help: "多种语言加解密插件\n" +
|
||||||
|
"- 齁语加解密:\n" +
|
||||||
|
"- 齁语加密 [文本] 或 h加密 [文本]\n" +
|
||||||
|
"- 齁语解密 [密文] 或 h解密 [密文]\n\n" +
|
||||||
|
"- Fumo语加解密:\n" +
|
||||||
|
"- fumo加密 [文本]\n" +
|
||||||
|
"- fumo解密 [密文]\n\n",
|
||||||
|
PublicDataFolder: "Crypter",
|
||||||
|
})
|
||||||
|
|
||||||
|
// hou
|
||||||
|
engine.OnRegex(`^(?:齁语加密|h加密)\s*(.+)$`).SetBlock(true).Handle(houEncryptHandler)
|
||||||
|
engine.OnRegex(`^(?:齁语解密|h解密)\s*(.+)$`).SetBlock(true).Handle(houDecryptHandler)
|
||||||
|
|
||||||
|
// Fumo
|
||||||
|
engine.OnRegex(`^fumo加密\s*(.+)$`).SetBlock(true).Handle(fumoEncryptHandler)
|
||||||
|
engine.OnRegex(`^fumo解密\s*(.+)$`).SetBlock(true).Handle(fumoDecryptHandler)
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||||
"github.com/FloatTech/floatbox/process"
|
"github.com/FloatTech/floatbox/process"
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
@ -29,7 +30,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
db.DBPath = engine.DataFolder() + "curse.db"
|
db = sql.New(engine.DataFolder() + "curse.db")
|
||||||
_, err := engine.GetLazyData("curse.db", true)
|
_, err := engine.GetLazyData("curse.db", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
|||||||
@ -8,9 +8,9 @@ type curse struct {
|
|||||||
Level string `db:"level"`
|
Level string `db:"level"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var db = &sql.Sqlite{}
|
var db sql.Sqlite
|
||||||
|
|
||||||
func getRandomCurseByLevel(level string) (c curse) {
|
func getRandomCurseByLevel(level string) (c curse) {
|
||||||
_ = db.Find("curse", &c, "where level = '"+level+"' ORDER BY RANDOM() limit 1")
|
_ = db.Find("curse", &c, "WHERE level = ? ORDER BY RANDOM() limit 1", level)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,16 +2,14 @@
|
|||||||
package dailynews
|
package dailynews
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/FloatTech/floatbox/binary"
|
|
||||||
"github.com/FloatTech/floatbox/web"
|
"github.com/FloatTech/floatbox/web"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/tidwall/gjson"
|
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
const api = "http://dwz.2xb.cn/zaob"
|
const api = "https://uapis.cn/api/v1/daily/news-image"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
@ -28,7 +26,6 @@ func init() {
|
|||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
picURL := gjson.Get(binary.BytesToString(data), "imageUrl").String()
|
ctx.SendChain(message.ImageBytes(data))
|
||||||
ctx.SendChain(message.Image(picURL))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ type text struct {
|
|||||||
// LoadText 加载小作文
|
// LoadText 加载小作文
|
||||||
func LoadText(dbfile string) error {
|
func LoadText(dbfile string) error {
|
||||||
_, err := file.GetLazyData(dbfile, control.Md5File, false)
|
_, err := file.GetLazyData(dbfile, control.Md5File, false)
|
||||||
db.DBPath = dbfile
|
db = sql.New(dbfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ func RandText() string {
|
|||||||
// HentaiText 发大病
|
// HentaiText 发大病
|
||||||
func HentaiText() string {
|
func HentaiText() string {
|
||||||
var t text
|
var t text
|
||||||
err := db.Find("text", &t, "where id = -3802576048116006195")
|
err := db.Find("text", &t, "WHERE id = -3802576048116006195")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.Error()
|
return err.Error()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
package dish
|
package dish
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ type dish struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
db = &sql.Sqlite{}
|
db sql.Sqlite
|
||||||
initialized = false
|
initialized = false
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,7 +36,7 @@ func init() {
|
|||||||
PublicDataFolder: "Dish",
|
PublicDataFolder: "Dish",
|
||||||
})
|
})
|
||||||
|
|
||||||
db.DBPath = en.DataFolder() + "dishes.db"
|
db = sql.New(en.DataFolder() + "dishes.db")
|
||||||
|
|
||||||
if _, err := en.GetLazyData("dishes.db", true); err != nil {
|
if _, err := en.GetLazyData("dishes.db", true); err != nil {
|
||||||
logrus.Warnln("[dish]获取菜谱数据库文件失败")
|
logrus.Warnln("[dish]获取菜谱数据库文件失败")
|
||||||
@ -62,7 +61,7 @@ func init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
name := ctx.NickName()
|
name := ctx.CardOrNickName(ctx.Event.UserID)
|
||||||
dishName := ctx.State["args"].(string)
|
dishName := ctx.State["args"].(string)
|
||||||
|
|
||||||
if dishName == "" {
|
if dishName == "" {
|
||||||
@ -77,17 +76,15 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var d dish
|
var d dish
|
||||||
if err := db.Find("dish", &d, fmt.Sprintf("WHERE name like '%%%s%%'", dishName)); err != nil {
|
if err := db.Find("dish", &d, "WHERE name LIKE ?", "%"+dishName+"%"); err != nil {
|
||||||
ctx.SendChain(message.Text("客官,本店没有" + dishName))
|
ctx.SendChain(message.Text("客官,本店没有" + dishName))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SendChain(message.Text(fmt.Sprintf(
|
ctx.SendChain(message.Text(
|
||||||
"已为客官%s找到%s的做法辣!\n"+
|
"已为客官", name, "找到", d.Name, "的做法辣!\n",
|
||||||
"原材料:%s\n"+
|
"原材料:", d.Materials, "\n",
|
||||||
"步骤:\n"+
|
"步骤:", d.Steps,
|
||||||
"%s",
|
|
||||||
name, d.Name, d.Materials, d.Steps),
|
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -105,12 +102,10 @@ func init() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SendChain(message.Text(fmt.Sprintf(
|
ctx.SendChain(message.Text(
|
||||||
"已为客官%s送上%s的做法:\n"+
|
"已为客官", name, "送上", d.Name, "的做法:\n",
|
||||||
"原材料:%s\n"+
|
"原材料:", d.Materials, "\n",
|
||||||
"步骤:\n"+
|
"步骤:", d.Steps,
|
||||||
"%s",
|
|
||||||
name, d.Name, d.Materials, d.Steps),
|
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ type sea struct {
|
|||||||
Time string `db:"time"` // we need to know the current time,master>
|
Time string `db:"time"` // we need to know the current time,master>
|
||||||
}
|
}
|
||||||
|
|
||||||
var seaSide = &sql.Sqlite{}
|
var seaSide sql.Sqlite
|
||||||
var seaLocker sync.RWMutex
|
var seaLocker sync.RWMutex
|
||||||
|
|
||||||
// We need a container to inject what we need :(
|
// We need a container to inject what we need :(
|
||||||
@ -39,15 +39,15 @@ func init() {
|
|||||||
Help: "- @bot pick" + "- @bot throw xxx (xxx为投递内容)",
|
Help: "- @bot pick" + "- @bot throw xxx (xxx为投递内容)",
|
||||||
PrivateDataFolder: "driftbottle",
|
PrivateDataFolder: "driftbottle",
|
||||||
})
|
})
|
||||||
seaSide.DBPath = en.DataFolder() + "sea.db"
|
seaSide = sql.New(en.DataFolder() + "sea.db")
|
||||||
err := seaSide.Open(time.Hour)
|
err := seaSide.Open(time.Hour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = createChannel(seaSide)
|
_ = createChannel(&seaSide)
|
||||||
en.OnFullMatch("pick", zero.OnlyToMe, zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
en.OnFullMatch("pick", zero.OnlyToMe, zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
be, err := fetchBottle(seaSide)
|
be, err := fetchBottle(&seaSide)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERR:", err))
|
ctx.SendChain(message.Text("ERR:", err))
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ func init() {
|
|||||||
senderFormatTime,
|
senderFormatTime,
|
||||||
ctx.CardOrNickName(ctx.Event.UserID),
|
ctx.CardOrNickName(ctx.Event.UserID),
|
||||||
rawMessageCallBack,
|
rawMessageCallBack,
|
||||||
).throw(seaSide)
|
).throw(&seaSide)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
|
|||||||
@ -79,7 +79,7 @@ func match(ctx *zero.Ctx) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func face2emoji(face message.MessageSegment) rune {
|
func face2emoji(face message.Segment) rune {
|
||||||
if face.Type == "text" {
|
if face.Type == "text" {
|
||||||
r := []rune(face.Data["text"])
|
r := []rune(face.Data["text"])
|
||||||
if len(r) != 1 {
|
if len(r) != 1 {
|
||||||
|
|||||||
118
plugin/emozi/main.go
Normal file
118
plugin/emozi/main.go
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Package emozi 颜文字抽象转写
|
||||||
|
package emozi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/FloatTech/AnimeAPI/emozi"
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/control"
|
||||||
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
|
DisableOnDefault: false,
|
||||||
|
Brief: "颜文字抽象转写",
|
||||||
|
Help: "- 抽象转写[文段]\n- 抽象还原[文段]\n- 抽象登录[用户名]",
|
||||||
|
PrivateDataFolder: "emozi",
|
||||||
|
})
|
||||||
|
usr := emozi.Anonymous()
|
||||||
|
data, err := os.ReadFile(en.DataFolder() + "user.txt")
|
||||||
|
refresh := func() {
|
||||||
|
go func() {
|
||||||
|
t := time.NewTicker(time.Hour)
|
||||||
|
defer t.Stop()
|
||||||
|
for range t.C {
|
||||||
|
if !usr.IsValid() {
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
err := usr.Login()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln("[emozi] 重新登录账号失败:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
refresher := sync.Once{}
|
||||||
|
if err == nil {
|
||||||
|
arr := strings.Split(string(data), "\n")
|
||||||
|
if len(arr) >= 2 {
|
||||||
|
usr = emozi.NewUser(arr[0], arr[1])
|
||||||
|
err = usr.Login()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Infoln("[emozi]", "以", arr[0], "身份登录失败:", err)
|
||||||
|
usr = emozi.Anonymous()
|
||||||
|
} else {
|
||||||
|
logrus.Infoln("[emozi]", "以", arr[0], "身份登录成功")
|
||||||
|
refresher.Do(refresh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
en.OnPrefix("抽象转写").Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
txt := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
out, chs, err := usr.Marshal(false, txt)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(chs) == 0 {
|
||||||
|
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(out)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i, c := range chs {
|
||||||
|
ch := ctx.Get("请选择第" + strconv.Itoa(i) + "个多音字(1~" + strconv.Itoa(c) + ")")
|
||||||
|
n, err := strconv.Atoi(ch)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n < 1 || n > c {
|
||||||
|
ctx.SendChain(message.Text("ERROR: 输入越界"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
chs[i] = n - 1
|
||||||
|
}
|
||||||
|
out, _, err = usr.Marshal(false, txt, chs...)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(out)))
|
||||||
|
})
|
||||||
|
en.OnPrefix("抽象还原").Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
txt := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
out, err := usr.Unmarshal(false, txt)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text(out)))
|
||||||
|
})
|
||||||
|
en.OnPrefix("抽象登录", zero.OnlyPrivate).Limit(ctxext.LimitByUser).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
name := strings.TrimSpace(ctx.State["args"].(string))
|
||||||
|
pswd := strings.TrimSpace(ctx.Get("请输入密码"))
|
||||||
|
newusr := emozi.NewUser(name, pswd)
|
||||||
|
err := newusr.Login()
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = os.WriteFile(en.DataFolder()+"user.txt", []byte(name+"\n"+pswd), 0644)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
usr = newusr
|
||||||
|
refresher.Do(refresh)
|
||||||
|
ctx.SendChain(message.Text("成功"))
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -146,7 +146,7 @@ func init() {
|
|||||||
digest := md5.Sum(helper.StringToBytes(zipfile + strconv.Itoa(index) + title + text))
|
digest := md5.Sum(helper.StringToBytes(zipfile + strconv.Itoa(index) + title + text))
|
||||||
cachefile := cache + hex.EncodeToString(digest[:])
|
cachefile := cache + hex.EncodeToString(digest[:])
|
||||||
|
|
||||||
err = pool.SendImageFromPool(cachefile, cachefile, func() error {
|
err = pool.SendImageFromPool(cachefile, func(cachefile string) error {
|
||||||
f, err := os.Create(cachefile)
|
f, err := os.Create(cachefile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -154,7 +154,7 @@ func init() {
|
|||||||
_, err = draw(background, fontdata, title, text, f)
|
_, err = draw(background, fontdata, title, text, f)
|
||||||
_ = f.Close()
|
_ = f.Close()
|
||||||
return err
|
return err
|
||||||
}, ctxext.Send(ctx), ctxext.GetMessage(ctx))
|
}, ctxext.Send(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
|
|||||||
@ -21,7 +21,7 @@ type joke struct {
|
|||||||
Text string `db:"text"`
|
Text string `db:"text"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var db = &sql.Sqlite{}
|
var db sql.Sqlite
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
@ -32,7 +32,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
en.OnPrefixGroup([]string{"讲个笑话", "夸夸"}, fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
en.OnPrefixGroup([]string{"讲个笑话", "夸夸"}, fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
db.DBPath = en.DataFolder() + "jokes.db"
|
db = sql.New(en.DataFolder() + "jokes.db")
|
||||||
_, err := en.GetLazyData("jokes.db", true)
|
_, err := en.GetLazyData("jokes.db", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
|||||||
@ -20,7 +20,7 @@ func dlchan(name string, s *string, wg *sync.WaitGroup, exit func(error)) {
|
|||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
target := datapath + `materials/` + name
|
target := datapath + `materials/` + name
|
||||||
if file.IsNotExist(target) {
|
if file.IsNotExist(target) {
|
||||||
data, err := web.RequestDataWith(web.NewTLS12Client(), `https://gitcode.net/m0_60838134/imagematerials/-/raw/main/`+name, "GET", "gitcode.net", web.RandUA(), nil)
|
data, err := web.GetData(`https://gitea.seku.su/fumiama/ImageMaterials/raw/branch/master/` + name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = os.Remove(target)
|
_ = os.Remove(target)
|
||||||
exit(err)
|
exit(err)
|
||||||
@ -48,7 +48,7 @@ func dlchan(name string, s *string, wg *sync.WaitGroup, exit func(error)) {
|
|||||||
func dlblock(name string) (string, error) {
|
func dlblock(name string) (string, error) {
|
||||||
target := datapath + `materials/` + name
|
target := datapath + `materials/` + name
|
||||||
if file.IsNotExist(target) {
|
if file.IsNotExist(target) {
|
||||||
data, err := web.RequestDataWith(web.NewTLS12Client(), `https://gitcode.net/m0_60838134/imagematerials/-/raw/main/`+name, "GET", "gitcode.net", web.RandUA(), nil)
|
data, err := web.GetData(`https://gitea.seku.su/fumiama/ImageMaterials/raw/branch/master/` + name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = os.Remove(target)
|
_ = os.Remove(target)
|
||||||
return "", err
|
return "", err
|
||||||
|
|||||||
@ -246,11 +246,7 @@ func init() {
|
|||||||
ctx.SendChain(message.Text(serviceErr, err))
|
ctx.SendChain(message.Text(serviceErr, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err == nil {
|
|
||||||
ctx.SendChain(message.Text("成功!"))
|
ctx.SendChain(message.Text("成功!"))
|
||||||
} else {
|
|
||||||
ctx.SendChain(message.Text(serviceErr, err))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
// 下载歌曲到对应的歌单里面
|
// 下载歌曲到对应的歌单里面
|
||||||
engine.OnRegex(`^下载歌单\s*((https:\/\/music\.163\.com\/#\/playlist\?id=)?(\d+)|http:\/\/music\.163\.com\/playlist\/(\d+).*[^\s$])\s*到\s*(.*)$`, zero.SuperUserPermission).SetBlock(true).Limit(ctxext.LimitByGroup).
|
engine.OnRegex(`^下载歌单\s*((https:\/\/music\.163\.com\/#\/playlist\?id=)?(\d+)|http:\/\/music\.163\.com\/playlist\/(\d+).*[^\s$])\s*到\s*(.*)$`, zero.SuperUserPermission).SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||||
|
|||||||
@ -130,7 +130,7 @@ func init() {
|
|||||||
after := time.NewTimer(120 * time.Second)
|
after := time.NewTimer(120 * time.Second)
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
var (
|
var (
|
||||||
messageStr message.MessageSegment // 文本信息
|
messageStr message.Segment // 文本信息
|
||||||
tickCount = 0 // 音频数量
|
tickCount = 0 // 音频数量
|
||||||
answerCount = 0 // 问答次数
|
answerCount = 0 // 问答次数
|
||||||
win bool // 是否赢得游戏
|
win bool // 是否赢得游戏
|
||||||
@ -281,7 +281,7 @@ func cutMusic(musicName, pathOfMusic, outputPath string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 数据匹配(结果信息,答题次数,提示次数,是否结束游戏)
|
// 数据匹配(结果信息,答题次数,提示次数,是否结束游戏)
|
||||||
func gameMatch(c *zero.Ctx, beginner int64, musicInfo []string, answerTimes, tickTimes int) (message.MessageSegment, int, int, bool) {
|
func gameMatch(c *zero.Ctx, beginner int64, musicInfo []string, answerTimes, tickTimes int) (message.Segment, int, int, bool) {
|
||||||
answer := strings.Replace(c.Event.Message.String(), "-", "", 1)
|
answer := strings.Replace(c.Event.Message.String(), "-", "", 1)
|
||||||
// 回答内容转小写,比对时再把标准答案转小写
|
// 回答内容转小写,比对时再把标准答案转小写
|
||||||
answer = ConvertText(answer)
|
answer = ConvertText(answer)
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import (
|
|||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
// 图片输出
|
// 图片输出
|
||||||
@ -65,17 +64,7 @@ var (
|
|||||||
"- 下载歌单[网易云歌单链接/ID]到[歌单名称]\n" +
|
"- 下载歌单[网易云歌单链接/ID]到[歌单名称]\n" +
|
||||||
"- 解除绑定 [歌单名称]",
|
"- 解除绑定 [歌单名称]",
|
||||||
PrivateDataFolder: "guessmusic",
|
PrivateDataFolder: "guessmusic",
|
||||||
}).ApplySingle(single.New(
|
}).ApplySingle(ctxext.NewGroupSingle("已经有正在进行的游戏..."))
|
||||||
single.WithKeyFn(func(ctx *zero.Ctx) int64 { return ctx.Event.GroupID }),
|
|
||||||
single.WithPostFn[int64](func(ctx *zero.Ctx) {
|
|
||||||
ctx.Break()
|
|
||||||
ctx.Send(
|
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
|
||||||
message.Text("已经有正在进行的游戏..."),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
))
|
|
||||||
// 用于存放歌曲三个片段的缓存文件夹
|
// 用于存放歌曲三个片段的缓存文件夹
|
||||||
cachePath = engine.DataFolder() + "cache/"
|
cachePath = engine.DataFolder() + "cache/"
|
||||||
// 用于存放用户的配置
|
// 用于存放用户的配置
|
||||||
@ -535,7 +524,7 @@ func getFileURLbyFileName(ctx *zero.Ctx, fileName string) (fileSearchName, fileU
|
|||||||
for _, fileNameOflist := range files {
|
for _, fileNameOflist := range files {
|
||||||
if strings.Contains(fileNameOflist.Get("file_name").String(), fileName) {
|
if strings.Contains(fileNameOflist.Get("file_name").String(), fileName) {
|
||||||
fileSearchName = fileNameOflist.Get("file_name").String()
|
fileSearchName = fileNameOflist.Get("file_name").String()
|
||||||
fileURL = ctx.GetThisGroupFileUrl(fileNameOflist.Get("busid").Int(), fileNameOflist.Get("file_id").String())
|
fileURL = ctx.GetThisGroupFileURL(fileNameOflist.Get("busid").Int(), fileNameOflist.Get("file_id").String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -561,7 +550,7 @@ func getFileURLbyfolderID(ctx *zero.Ctx, fileName, folderid string) (fileSearchN
|
|||||||
for _, fileNameOflist := range files {
|
for _, fileNameOflist := range files {
|
||||||
if strings.Contains(fileNameOflist.Get("file_name").String(), fileName) {
|
if strings.Contains(fileNameOflist.Get("file_name").String(), fileName) {
|
||||||
fileSearchName = fileNameOflist.Get("file_name").String()
|
fileSearchName = fileNameOflist.Get("file_name").String()
|
||||||
fileURL = ctx.GetThisGroupFileUrl(fileNameOflist.Get("busid").Int(), fileNameOflist.Get("file_id").String())
|
fileURL = ctx.GetThisGroupFileURL(fileNameOflist.Get("busid").Int(), fileNameOflist.Get("file_id").String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import (
|
|||||||
sql "github.com/FloatTech/sqlite"
|
sql "github.com/FloatTech/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
var db = &sql.Sqlite{}
|
var db sql.Sqlite
|
||||||
var mu sync.RWMutex
|
var mu sync.RWMutex
|
||||||
|
|
||||||
type picture struct {
|
type picture struct {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/FloatTech/floatbox/binary"
|
"github.com/FloatTech/floatbox/binary"
|
||||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/antchfx/htmlquery"
|
"github.com/antchfx/htmlquery"
|
||||||
@ -31,7 +32,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
db.DBPath = engine.DataFolder() + "pics.db"
|
db = sql.New(engine.DataFolder() + "pics.db")
|
||||||
_, _ = engine.GetLazyData("pics.db", false)
|
_, _ = engine.GetLazyData("pics.db", false)
|
||||||
err := db.Open(time.Hour)
|
err := db.Open(time.Hour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -95,7 +96,7 @@ func init() {
|
|||||||
u := "https:" + v.Attr[0].Val
|
u := "https:" + v.Attr[0].Val
|
||||||
i := crc64.Checksum(binary.StringToBytes(u), crc64.MakeTable(crc64.ISO))
|
i := crc64.Checksum(binary.StringToBytes(u), crc64.MakeTable(crc64.ISO))
|
||||||
mu.RLock()
|
mu.RLock()
|
||||||
ok := db.CanFind("picture", "where id="+strconv.FormatUint(i, 10))
|
ok := db.CanFind("picture", "WHERE id = ?", i)
|
||||||
mu.RUnlock()
|
mu.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/FloatTech/floatbox/binary"
|
"github.com/FloatTech/floatbox/binary"
|
||||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/img/text"
|
"github.com/FloatTech/zbputils/img/text"
|
||||||
@ -26,7 +27,7 @@ func init() { // 插件主体
|
|||||||
})
|
})
|
||||||
|
|
||||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
db.DBPath = engine.DataFolder() + "item.db"
|
db = sql.New(engine.DataFolder() + "item.db")
|
||||||
_, err := engine.GetLazyData("item.db", true)
|
_, err := engine.GetLazyData("item.db", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
|||||||
@ -17,14 +17,16 @@ type item struct {
|
|||||||
Datetime time.Time `db:"datetime"`
|
Datetime time.Time `db:"datetime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var db = &sql.Sqlite{}
|
var db sql.Sqlite
|
||||||
|
|
||||||
func getRandomAudioByCategory(category string) (t item) {
|
func getRandomAudioByCategory(category string) (t item) {
|
||||||
_ = db.Find("item", &t, "where category = '"+category+"' ORDER BY RANDOM() limit 1")
|
_ = db.Find("item", &t, "WHERE category = ? ORDER BY RANDOM() limit 1", category)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRandomAudioByCategoryAndKeyword(category string, keyword string) (t item) {
|
func getRandomAudioByCategoryAndKeyword(category string, keyword string) (t item) {
|
||||||
_ = db.Find("item", &t, "where category = '"+category+"' and (title like '%"+keyword+"%' or content like '%"+keyword+"%') ORDER BY RANDOM() limit 1")
|
_ = db.Find("item", &t,
|
||||||
|
"WHERE category = ? and (title LIKE ? OR content LIKE ?) ORDER BY RANDOM() limit 1",
|
||||||
|
category, "%"+keyword+"%", "%"+keyword+"%")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
package kfccrazythursday
|
package kfccrazythursday
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/FloatTech/floatbox/binary"
|
|
||||||
"github.com/FloatTech/floatbox/web"
|
"github.com/FloatTech/floatbox/web"
|
||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
@ -11,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
crazyURL = "http://api.jixs.cc/api/wenan-fkxqs/index.php"
|
crazyURL = "https://api.pearktrue.cn/api/kfc/"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -26,6 +25,8 @@ func init() {
|
|||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.SendChain(message.Text(binary.BytesToString(data)))
|
|
||||||
|
// 根据来源API修改返回方式到直接输出文本
|
||||||
|
ctx.SendChain(message.Text(string(data)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ import (
|
|||||||
ctrl "github.com/FloatTech/zbpctrl"
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
imagepool "github.com/FloatTech/zbputils/img/pool"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -68,19 +67,8 @@ func init() {
|
|||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
name := imageurl[strings.LastIndex(imageurl, "/")+1 : len(imageurl)-4]
|
|
||||||
m, err := imagepool.GetImage(name)
|
|
||||||
if err != nil {
|
|
||||||
m.SetFile(imageurl)
|
|
||||||
_, _ = m.Push(ctxext.SendToSelf(ctx), ctxext.GetMessage(ctx))
|
|
||||||
process.SleepAbout1sTo2s()
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
queue <- m.String()
|
|
||||||
} else {
|
|
||||||
queue <- imageurl
|
queue <- imageurl
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
case <-time.After(time.Minute):
|
case <-time.After(time.Minute):
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import (
|
|||||||
const gistraw = "https://gist.githubusercontent.com/%s/%s/raw/%s"
|
const gistraw = "https://gist.githubusercontent.com/%s/%s/raw/%s"
|
||||||
|
|
||||||
func checkNewUser(qq, gid int64, ghun, hash string) (bool, string) {
|
func checkNewUser(qq, gid int64, ghun, hash string) (bool, string) {
|
||||||
if db.CanFind("member", "where ghun="+ghun) {
|
if db.CanFind("member", "WHERE ghun = ?", ghun) {
|
||||||
return false, "该github用户已入群"
|
return false, "该github用户已入群"
|
||||||
}
|
}
|
||||||
gidsum := md5.Sum(helper.StringToBytes(strconv.FormatInt(gid, 10)))
|
gidsum := md5.Sum(helper.StringToBytes(strconv.FormatInt(gid, 10)))
|
||||||
|
|||||||
@ -50,6 +50,7 @@ const (
|
|||||||
"- 列出所有提醒\n" +
|
"- 列出所有提醒\n" +
|
||||||
"- 翻牌\n" +
|
"- 翻牌\n" +
|
||||||
"- 赞我\n" +
|
"- 赞我\n" +
|
||||||
|
"- 群签到\n" +
|
||||||
"- 对信息回复: 回应表情 [表情]\n" +
|
"- 对信息回复: 回应表情 [表情]\n" +
|
||||||
"- 设置欢迎语XXX 可选添加 [{at}] [{nickname}] [{avatar}] [{uid}] [{gid}] [{groupname}]\n" +
|
"- 设置欢迎语XXX 可选添加 [{at}] [{nickname}] [{avatar}] [{uid}] [{gid}] [{groupname}]\n" +
|
||||||
"- 测试欢迎语\n" +
|
"- 测试欢迎语\n" +
|
||||||
@ -63,7 +64,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
db = &sql.Sqlite{}
|
db sql.Sqlite
|
||||||
clock timer.Clock
|
clock timer.Clock
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -76,12 +77,12 @@ func init() { // 插件主体
|
|||||||
})
|
})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
db.DBPath = engine.DataFolder() + "config.db"
|
db = sql.New(engine.DataFolder() + "config.db")
|
||||||
err := db.Open(time.Hour)
|
err := db.Open(time.Hour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
clock = timer.NewClock(db)
|
clock = timer.NewClock(&db)
|
||||||
err = db.Create("welcome", &welcome{})
|
err = db.Create("welcome", &welcome{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -156,10 +157,11 @@ func init() { // 插件主体
|
|||||||
ctx.SendChain(message.Text("全员自闭结束~"))
|
ctx.SendChain(message.Text("全员自闭结束~"))
|
||||||
})
|
})
|
||||||
// 禁言
|
// 禁言
|
||||||
engine.OnRegex(`^禁言.*?(\d+).*?\s(\d+)(.*)`, zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
engine.OnMessage(zero.NewPattern(nil).Text("^禁言").At().Text("(\\d+)\\s*(.*)").AsRule(), zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
duration := math.Str2Int64(ctx.State["regex_matched"].([]string)[2])
|
parsed := ctx.State[zero.KeyPattern].([]zero.PatternParsed)
|
||||||
switch ctx.State["regex_matched"].([]string)[3] {
|
duration := math.Str2Int64(parsed[2].Text()[1])
|
||||||
|
switch parsed[2].Text()[2] {
|
||||||
case "分钟":
|
case "分钟":
|
||||||
//
|
//
|
||||||
case "小时":
|
case "小时":
|
||||||
@ -173,7 +175,7 @@ func init() { // 插件主体
|
|||||||
duration = 43199 // qq禁言最大时长为一个月
|
duration = 43199 // qq禁言最大时长为一个月
|
||||||
}
|
}
|
||||||
ctx.SetThisGroupBan(
|
ctx.SetThisGroupBan(
|
||||||
math.Str2Int64(ctx.State["regex_matched"].([]string)[1]), // 要禁言的人的qq
|
math.Str2Int64(parsed[1].At()), // 要禁言的人的qq
|
||||||
duration*60, // 要禁言的时间(分钟)
|
duration*60, // 要禁言的时间(分钟)
|
||||||
)
|
)
|
||||||
ctx.SendChain(message.Text("小黑屋收留成功~"))
|
ctx.SendChain(message.Text("小黑屋收留成功~"))
|
||||||
@ -404,6 +406,12 @@ func init() { // 插件主体
|
|||||||
ctx.SendLike(ctx.Event.UserID, 10)
|
ctx.SendLike(ctx.Event.UserID, 10)
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("给你赞了10下哦,记得回我~"))
|
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("给你赞了10下哦,记得回我~"))
|
||||||
})
|
})
|
||||||
|
// 群签到
|
||||||
|
engine.OnFullMatch("群签到", zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||||
|
Handle(func(ctx *zero.Ctx) {
|
||||||
|
ctx.SetGroupSign(ctx.Event.GroupID)
|
||||||
|
ctx.SendChain(message.Text("群签到成功,可在手机端输入框中的打卡查看"))
|
||||||
|
})
|
||||||
facere := regexp.MustCompile(`\[CQ:face,id=(\d+)\]`)
|
facere := regexp.MustCompile(`\[CQ:face,id=(\d+)\]`)
|
||||||
// 给消息回应表情
|
// 给消息回应表情
|
||||||
engine.OnRegex(`^\[CQ:reply,id=(-?\d+)\].*回应表情\s*(.+)\s*$`, zero.AdminPermission, zero.OnlyGroup).SetBlock(true).
|
engine.OnRegex(`^\[CQ:reply,id=(-?\d+)\].*回应表情\s*(.+)\s*$`, zero.AdminPermission, zero.OnlyGroup).SetBlock(true).
|
||||||
@ -442,7 +450,7 @@ func init() { // 插件主体
|
|||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
if ctx.Event.NoticeType == "group_increase" && ctx.Event.SelfID != ctx.Event.UserID {
|
if ctx.Event.NoticeType == "group_increase" && ctx.Event.SelfID != ctx.Event.UserID {
|
||||||
var w welcome
|
var w welcome
|
||||||
err := db.Find("welcome", &w, "where gid = "+strconv.FormatInt(ctx.Event.GroupID, 10))
|
err := db.Find("welcome", &w, "WHERE gid = ?", ctx.Event.GroupID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ctx.SendGroupMessage(ctx.Event.GroupID, message.ParseMessageFromString(welcometocq(ctx, w.Msg)))
|
ctx.SendGroupMessage(ctx.Event.GroupID, message.ParseMessageFromString(welcometocq(ctx, w.Msg)))
|
||||||
} else {
|
} else {
|
||||||
@ -494,7 +502,7 @@ func init() { // 插件主体
|
|||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
if ctx.Event.NoticeType == "group_decrease" {
|
if ctx.Event.NoticeType == "group_decrease" {
|
||||||
var w welcome
|
var w welcome
|
||||||
err := db.Find("farewell", &w, "where gid = "+strconv.FormatInt(ctx.Event.GroupID, 10))
|
err := db.Find("farewell", &w, "WHERE gid = ?", ctx.Event.GroupID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
collectsend(ctx, message.ParseMessageFromString(welcometocq(ctx, w.Msg))...)
|
collectsend(ctx, message.ParseMessageFromString(welcometocq(ctx, w.Msg))...)
|
||||||
} else {
|
} else {
|
||||||
@ -523,7 +531,7 @@ func init() { // 插件主体
|
|||||||
engine.OnFullMatch("测试欢迎语", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
engine.OnFullMatch("测试欢迎语", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
var w welcome
|
var w welcome
|
||||||
err := db.Find("welcome", &w, "where gid = "+strconv.FormatInt(ctx.Event.GroupID, 10))
|
err := db.Find("welcome", &w, "WHERE gid = ?", ctx.Event.GroupID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ctx.SendGroupMessage(ctx.Event.GroupID, message.ParseMessageFromString(welcometocq(ctx, w.Msg)))
|
ctx.SendGroupMessage(ctx.Event.GroupID, message.ParseMessageFromString(welcometocq(ctx, w.Msg)))
|
||||||
} else {
|
} else {
|
||||||
@ -550,7 +558,7 @@ func init() { // 插件主体
|
|||||||
engine.OnFullMatch("测试告别辞", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
engine.OnFullMatch("测试告别辞", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
var w welcome
|
var w welcome
|
||||||
err := db.Find("farewell", &w, "where gid = "+strconv.FormatInt(ctx.Event.GroupID, 10))
|
err := db.Find("farewell", &w, "WHERE gid = ?", ctx.Event.GroupID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ctx.SendGroupMessage(ctx.Event.GroupID, message.ParseMessageFromString(welcometocq(ctx, w.Msg)))
|
ctx.SendGroupMessage(ctx.Event.GroupID, message.ParseMessageFromString(welcometocq(ctx, w.Msg)))
|
||||||
} else {
|
} else {
|
||||||
@ -649,7 +657,7 @@ func init() { // 插件主体
|
|||||||
if rsp.RetCode == 0 {
|
if rsp.RetCode == 0 {
|
||||||
ctx.SendChain(message.Text(option, "成功"))
|
ctx.SendChain(message.Text(option, "成功"))
|
||||||
} else {
|
} else {
|
||||||
ctx.SendChain(message.Text(option, "失败, 信息: ", rsp.Msg, "解释: ", rsp.Wording))
|
ctx.SendChain(message.Text(option, "失败, 信息: ", rsp.Message, "解释: ", rsp.Wording))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
engine.OnCommand("精华列表", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
engine.OnCommand("精华列表", zero.OnlyGroup, zero.AdminPermission).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||||
@ -698,7 +706,7 @@ func init() { // 插件主体
|
|||||||
if rsp.RetCode == 0 {
|
if rsp.RetCode == 0 {
|
||||||
ctx.SendChain(message.Text("取消成功"))
|
ctx.SendChain(message.Text("取消成功"))
|
||||||
} else {
|
} else {
|
||||||
ctx.SendChain(message.Text("取消失败, 信息: ", rsp.Msg, "解释: ", rsp.Wording))
|
ctx.SendChain(message.Text("取消失败, 信息: ", rsp.Message, "解释: ", rsp.Wording))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,17 +9,21 @@ import (
|
|||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
var slowsenders = syncx.Map[int64, *syncx.Lazy[*slowdo.Job[*zero.Ctx, message.MessageSegment]]]{}
|
var slowsenders = syncx.Map[int64, *syncx.Lazy[*slowdo.Job[*zero.Ctx, message.Segment]]]{}
|
||||||
|
|
||||||
func collectsend(ctx *zero.Ctx, msgs ...message.MessageSegment) {
|
func collectsend(ctx *zero.Ctx, msgs ...message.Segment) {
|
||||||
id := ctx.Event.GroupID
|
id := ctx.Event.GroupID
|
||||||
if id == 0 {
|
if id == 0 {
|
||||||
// only support group
|
// only support group
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lazy, _ := slowsenders.LoadOrStore(id, &syncx.Lazy[*slowdo.Job[*zero.Ctx, message.MessageSegment]]{
|
lazy, _ := slowsenders.LoadOrStore(id, &syncx.Lazy[*slowdo.Job[*zero.Ctx, message.Segment]]{
|
||||||
Init: func() *slowdo.Job[*zero.Ctx, message.MessageSegment] {
|
Init: func() *slowdo.Job[*zero.Ctx, message.Segment] {
|
||||||
x, err := slowdo.NewJob(time.Second*5, ctx, func(ctx *zero.Ctx, msg []message.MessageSegment) {
|
x, err := slowdo.NewJob(time.Second*5, ctx, func(ctx *zero.Ctx, msg []message.Segment) {
|
||||||
|
if len(msg) == 1 {
|
||||||
|
ctx.Send(msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
m := make(message.Message, len(msg))
|
m := make(message.Message, len(msg))
|
||||||
for i, item := range msg {
|
for i, item := range msg {
|
||||||
m[i] = message.CustomNode(
|
m[i] = message.CustomNode(
|
||||||
|
|||||||
@ -22,7 +22,7 @@ func (t *Timer) InsertInto(db *sql.Sqlite) error {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
func getTimerFrom(db *sql.Sqlite, id uint32) (t Timer, err error) {
|
func getTimerFrom(db *sql.Sqlite, id uint32) (t Timer, err error) {
|
||||||
err = db.Find("timer", &t, "where id = "+strconv.Itoa(int(id)))
|
err = db.Find("timer", &t, "WHERE id = "+strconv.Itoa(int(id)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
package timer
|
package timer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -29,7 +28,7 @@ type Clock struct {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// @全体成员
|
// @全体成员
|
||||||
atall = message.MessageSegment{
|
atall = message.Segment{
|
||||||
Type: "at",
|
Type: "at",
|
||||||
Data: map[string]string{
|
Data: map[string]string{
|
||||||
"qq": "all",
|
"qq": "all",
|
||||||
@ -133,7 +132,7 @@ func (c *Clock) CancelTimer(key uint32) bool {
|
|||||||
}
|
}
|
||||||
c.timersmu.Lock()
|
c.timersmu.Lock()
|
||||||
delete(*c.timers, key) // 避免重复取消
|
delete(*c.timers, key) // 避免重复取消
|
||||||
e := c.db.Del("timer", "where id = "+strconv.Itoa(int(key)))
|
e := c.db.Del("timer", "WHERE id = ?", key)
|
||||||
c.timersmu.Unlock()
|
c.timersmu.Unlock()
|
||||||
return e == nil
|
return e == nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,8 +25,8 @@ func TestNextWakeTime(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClock(t *testing.T) {
|
func TestClock(t *testing.T) {
|
||||||
db := &sql.Sqlite{DBPath: "test.db"}
|
db := sql.New("test.db")
|
||||||
c := NewClock(db)
|
c := NewClock(&db)
|
||||||
c.AddTimerIntoDB(GetFilledTimer([]string{"", "12", "-1", "12", "0", "", "test"}, 0, 0, false))
|
c.AddTimerIntoDB(GetFilledTimer([]string{"", "12", "-1", "12", "0", "", "test"}, 0, 0, false))
|
||||||
t.Log(c.ListTimers(0))
|
t.Log(c.ListTimers(0))
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
|||||||
@ -129,12 +129,12 @@ func init() {
|
|||||||
fishNumber *= 3
|
fishNumber *= 3
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fishNmaes, err := dbdata.pickFishFor(uid, fishNumber)
|
fishNames, err := dbdata.pickFishFor(uid, fishNumber*3)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("[ERROR at fish.go.5.1]:", err))
|
ctx.SendChain(message.Text("[ERROR at fish.go.5.1]:", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(fishNmaes) == 0 {
|
if len(fishNames) == 0 {
|
||||||
equipInfo.Durable = 0
|
equipInfo.Durable = 0
|
||||||
err = dbdata.updateUserEquip(equipInfo)
|
err = dbdata.updateUserEquip(equipInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -143,14 +143,14 @@ func init() {
|
|||||||
ctx.SendChain(message.Text("美西螈因为没吃到鱼,钓鱼时一直没回来,你失去了美西螈"))
|
ctx.SendChain(message.Text("美西螈因为没吃到鱼,钓鱼时一直没回来,你失去了美西螈"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg = "(美西螈吃掉了"
|
msg = "(美西螈掉落翻5倍,吃3倍鱼:\n吃掉了:"
|
||||||
fishNumber = 0
|
fishNumber = 0
|
||||||
for name, number := range fishNmaes {
|
for name, number := range fishNames {
|
||||||
fishNumber += number
|
fishNumber += number
|
||||||
msg += strconv.Itoa(number) + name + " "
|
msg += strconv.Itoa(number) + name + " "
|
||||||
}
|
}
|
||||||
msg += ")"
|
msg += ")"
|
||||||
fishNumber /= 2
|
fishNumber /= 3
|
||||||
}
|
}
|
||||||
waitTime := 120 / (equipInfo.Induce + 1)
|
waitTime := 120 / (equipInfo.Induce + 1)
|
||||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你开始去钓鱼了,请耐心等待鱼上钩(预计要", time.Second*time.Duration(waitTime), ")"))
|
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text("你开始去钓鱼了,请耐心等待鱼上钩(预计要", time.Second*time.Duration(waitTime), ")"))
|
||||||
@ -267,8 +267,8 @@ func init() {
|
|||||||
thingName = "金竿"
|
thingName = "金竿"
|
||||||
case dice >= probabilities["钻石竿"].Min && dice < probabilities["钻石竿"].Max:
|
case dice >= probabilities["钻石竿"].Min && dice < probabilities["钻石竿"].Max:
|
||||||
thingName = "钻石竿"
|
thingName = "钻石竿"
|
||||||
case dice >= probabilities["下界合金竿竿竿"].Min && dice < probabilities["下界合金竿竿竿"].Max:
|
case dice >= probabilities["下界合金竿"].Min && dice < probabilities["下界合金竿"].Max:
|
||||||
thingName = "下界合金竿竿竿"
|
thingName = "下界合金竿"
|
||||||
default:
|
default:
|
||||||
thingName = "木竿"
|
thingName = "木竿"
|
||||||
}
|
}
|
||||||
@ -323,7 +323,7 @@ func init() {
|
|||||||
newThing = thingInfo[0]
|
newThing = thingInfo[0]
|
||||||
}
|
}
|
||||||
if equipInfo.Equip == "美西螈" && thingName != "美西螈" {
|
if equipInfo.Equip == "美西螈" && thingName != "美西螈" {
|
||||||
number += 2
|
number += 4
|
||||||
}
|
}
|
||||||
newThing.Number += number
|
newThing.Number += number
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -20,15 +21,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type fishdb struct {
|
type fishdb struct {
|
||||||
db *sql.Sqlite
|
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
db sql.Sqlite
|
||||||
}
|
}
|
||||||
|
|
||||||
// FishLimit 钓鱼次数上限
|
// FishLimit 钓鱼次数上限
|
||||||
const FishLimit = 50
|
const FishLimit = 50
|
||||||
|
|
||||||
// version 规则版本号
|
// version 规则版本号
|
||||||
const version = "5.5.8"
|
const version = "5.6.2"
|
||||||
|
|
||||||
// 各物品信息
|
// 各物品信息
|
||||||
type jsonInfo struct {
|
type jsonInfo struct {
|
||||||
@ -101,7 +102,7 @@ type buffInfo struct {
|
|||||||
Coupon int `db:"Buff1"` // 优惠卷
|
Coupon int `db:"Buff1"` // 优惠卷
|
||||||
SalesPole int `db:"Buff2"` // 卖鱼竿上限
|
SalesPole int `db:"Buff2"` // 卖鱼竿上限
|
||||||
BuyTing int `db:"Buff3"` // 购买上限
|
BuyTing int `db:"Buff3"` // 购买上限
|
||||||
SalesFish int `db:"Buff4"` // 卖鱼次数
|
Buff4 int `db:"Buff4"` // 暂定
|
||||||
Buff5 int `db:"Buff5"` // 暂定
|
Buff5 int `db:"Buff5"` // 暂定
|
||||||
Buff6 int `db:"Buff6"` // 暂定
|
Buff6 int `db:"Buff6"` // 暂定
|
||||||
Buff7 int `db:"Buff7"` // 暂定
|
Buff7 int `db:"Buff7"` // 暂定
|
||||||
@ -121,39 +122,31 @@ var (
|
|||||||
durationList = make(map[string]int, 50) // 装备耐久分布
|
durationList = make(map[string]int, 50) // 装备耐久分布
|
||||||
discountList = make(map[string]int, 50) // 价格波动信息
|
discountList = make(map[string]int, 50) // 价格波动信息
|
||||||
enchantLevel = []string{"0", "Ⅰ", "Ⅱ", "Ⅲ"}
|
enchantLevel = []string{"0", "Ⅰ", "Ⅱ", "Ⅲ"}
|
||||||
dbdata = &fishdb{
|
dbdata fishdb
|
||||||
db: &sql.Sqlite{},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
DisableOnDefault: false,
|
DisableOnDefault: false,
|
||||||
Brief: "钓鱼",
|
Brief: "钓鱼",
|
||||||
Help: "一款钓鱼模拟器\n----------指令----------\n" +
|
Help: "一款钓鱼模拟器,规则:V" + version +
|
||||||
"- 钓鱼看板/钓鱼商店\n- 购买xxx\n- 购买xxx [数量]\n- 出售xxx\n- 出售xxx [数量]\n- 出售所有垃圾\n" +
|
"\n----------指令----------\n" +
|
||||||
"- 钓鱼背包\n- 装备[xx竿|三叉戟|美西螈]\n- 附魔[诱钓|海之眷顾]\n- 修复鱼竿\n- 合成[xx竿|三叉戟]\n- 消除[绑定|宝藏]诅咒\n- 消除[绑定|宝藏]诅咒 [数量]\n" +
|
"- 钓鱼背包\n" +
|
||||||
"- 进行钓鱼\n- 进行n次钓鱼\n- 当前装备概率明细\n" +
|
"- 进行钓鱼 / 进行n次钓鱼\n" +
|
||||||
"规则V" + version + ":\n" +
|
"- 修复鱼竿\n" +
|
||||||
"1.每日的商店价格是波动的!!如何最大化收益自己考虑一下喔\n" +
|
"- 钓鱼商店 / 钓鱼看板\n" +
|
||||||
"2.装备信息:\n-> 木竿 : 耐久上限:30 均价:100 上钩概率:0.7%\n-> 铁竿 : 耐久上限:50 均价:300 上钩概率:0.2%\n-> 金竿 : 耐久上限:70 均价700 上钩概率:0.06%\n" +
|
"- 购买xxx / 购买xxx [数量]\n- 出售xxx / 出售xxx [数量]\n" +
|
||||||
"-> 钻石竿 : 耐久上限:100 均价1500 上钩概率:0.03%\n-> 下界合金竿 : 耐久上限:150 均价3100 上钩概率:0.01%\n-> 三叉戟 : 可使1次钓鱼视为3次钓鱼. 耐久上限:300 均价4000 只能合成、修复和交易\n" +
|
"- 消除[绑定|宝藏]诅咒 / 消除[绑定|宝藏]诅咒 [数量]\n" +
|
||||||
"3.附魔书信息:\n-> 诱钓 : 减少上钩时间. 均价:1000, 上钩概率:0.25%\n-> 海之眷顾 : 增加宝藏上钩概率. 均价:2500, 上钩概率:0.10%\n" +
|
"- 装备[xx竿|三叉戟|美西螈]\n" +
|
||||||
"4.稀有物品:\n-> 唱片 : 出售物品时使用该物品使价格翻倍. 均价:3000, 上钩概率:0.01%\n" +
|
"- 附魔[诱钓|海之眷顾]\n" +
|
||||||
"-> 美西螈 : 可装备,获得隐形[钓鱼佬]buff,并让钓到除鱼竿和美西螈外的物品数量变成3,无耐久上限.不可修复/附魔,每次钓鱼消耗两任意鱼类物品. 均价:3000, 上钩概率:0.01%\n" +
|
"- 合成[xx竿|三叉戟]\n" +
|
||||||
"-> 海豚 : 使空竿概率变成垃圾概率. 均价:1000, 上钩概率:0.19%\n" +
|
"- 出售所有垃圾\n" +
|
||||||
"-> 宝藏诅咒 : 无法交易,每一层就会增加购买时10%价格和减少出售时10%价格(超过10层会变为倒贴钱). 上钩概率:0.25%\n-> 净化书 : 用于消除宝藏诅咒. 均价:5000, 上钩概率:0.19%\n" +
|
"- 当前装备概率明细\n" +
|
||||||
"5.鱼类信息:\n-> 鳕鱼 : 均价:10 上钩概率:0.69%\n-> 鲑鱼 : 均价:50 上钩概率:0.2%\n-> 热带鱼 : 均价:100 上钩概率:0.06%\n-> 河豚 : 均价:300 上钩概率:0.03%\n-> 鹦鹉螺 : 均价:500 上钩概率:0.01%\n-> 墨鱼 : 均价:500 上钩概率:0.01%\n" +
|
"- 查看钓鱼规则\n",
|
||||||
"6.垃圾:\n-> 均价:10 上钩概率:30%\n" +
|
|
||||||
"7.物品BUFF:\n-> 钓鱼佬 : 当背包名字含有'鱼'的物品数量超过100时激活,钓到物品概率提高至90%\n-> 修复大师 : 当背包鱼竿数量超过10时激活,修复物品时耐久百分百继承\n" +
|
|
||||||
"8.合成:\n-> 铁竿 : 3x木竿\n-> 金竿 : 3x铁竿\n-> 钻石竿 : 3x金竿\n-> 下界合金竿 : 3x钻石竿\n-> 三叉戟 : 3x下界合金竿\n注:合成成功率90%(包括梭哈),合成鱼竿的附魔等级=(附魔等级合/合成鱼竿数量)\n" +
|
|
||||||
"9.杂项:\n-> 无装备的情况下,每人最多可以购买3次100块钱的鱼竿\n-> 默认状态钓鱼上钩概率为60%(理论值!!!)\n-> 附魔的鱼竿会因附魔变得昂贵,每个附魔最高3级\n-> 三叉戟不算鱼竿,修复时可直接满耐久\n" +
|
|
||||||
"-> 鱼竿数量大于50的不能买东西;\n 鱼竿数量大于30的不能钓鱼;\n 每购/售10次鱼竿获得1层宝藏诅咒;\n 每购买20次物品将获得3次价格减半福利;\n 每钓鱼75次获得1本净化书;\n" +
|
|
||||||
" 每天最多只可出售5个鱼竿和购买15次物品;鱼类交易每天最多100条.",
|
|
||||||
PublicDataFolder: "McFish",
|
PublicDataFolder: "McFish",
|
||||||
}).ApplySingle(ctxext.DefaultSingle)
|
}).ApplySingle(ctxext.DefaultSingle)
|
||||||
getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
getdb = fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||||
dbdata.db.DBPath = engine.DataFolder() + "fishdata.db"
|
dbdata.db = sql.New(engine.DataFolder() + "fishdata.db")
|
||||||
err := dbdata.db.Open(time.Hour * 24)
|
err := dbdata.db.Open(time.Hour * 24)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("[ERROR at main.go.1]:", err))
|
ctx.SendChain(message.Text("[ERROR at main.go.1]:", err))
|
||||||
@ -245,7 +238,7 @@ func (sql *fishdb) updateFishInfo(uid int64, number int) (residue int, err error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
_ = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10))
|
_ = sql.db.Find("fishState", &userInfo, "WHERE ID = ?", uid)
|
||||||
if time.Unix(userInfo.Duration, 0).Day() != time.Now().Day() {
|
if time.Unix(userInfo.Duration, 0).Day() != time.Now().Day() {
|
||||||
userInfo.Fish = 0
|
userInfo.Fish = 0
|
||||||
userInfo.Duration = time.Now().Unix()
|
userInfo.Duration = time.Now().Unix()
|
||||||
@ -278,7 +271,7 @@ func (sql *fishdb) updateCurseFor(uid int64, info string, number int) (err error
|
|||||||
changeCheck := false
|
changeCheck := false
|
||||||
add := 0
|
add := 0
|
||||||
buffName := "宝藏诅咒"
|
buffName := "宝藏诅咒"
|
||||||
_ = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10))
|
_ = sql.db.Find("fishState", &userInfo, "WHERE ID = ?", uid)
|
||||||
if info == "fish" {
|
if info == "fish" {
|
||||||
userInfo.Bless += number
|
userInfo.Bless += number
|
||||||
for userInfo.Bless >= 75 {
|
for userInfo.Bless >= 75 {
|
||||||
@ -306,7 +299,7 @@ func (sql *fishdb) updateCurseFor(uid int64, info string, number int) (err error
|
|||||||
Name: buffName,
|
Name: buffName,
|
||||||
Type: "treasure",
|
Type: "treasure",
|
||||||
}
|
}
|
||||||
_ = sql.db.Find(table, &thing, "where Name = '"+buffName+"'")
|
_ = sql.db.Find(table, &thing, "WHERE Name = ?", buffName)
|
||||||
thing.Number += add
|
thing.Number += add
|
||||||
return sql.db.Insert(table, &thing)
|
return sql.db.Insert(table, &thing)
|
||||||
}
|
}
|
||||||
@ -325,10 +318,10 @@ func (sql *fishdb) checkEquipFor(uid int64) (ok bool, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if !sql.db.CanFind("fishState", "where ID = "+strconv.FormatInt(uid, 10)) {
|
if !sql.db.CanFind("fishState", "WHERE ID = ?", uid) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
err = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10))
|
err = sql.db.Find("fishState", &userInfo, "WHERE ID = ?", uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
@ -346,10 +339,7 @@ func (sql *fishdb) setEquipFor(uid int64) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_ = sql.db.Find("fishState", &userInfo, "where ID = "+strconv.FormatInt(uid, 10))
|
_ = sql.db.Find("fishState", &userInfo, "WHERE ID = ?", uid)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
userInfo.Equip++
|
userInfo.Equip++
|
||||||
return sql.db.Insert("fishState", &userInfo)
|
return sql.db.Insert("fishState", &userInfo)
|
||||||
}
|
}
|
||||||
@ -362,10 +352,10 @@ func (sql *fishdb) getUserEquip(uid int64) (userInfo equip, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !sql.db.CanFind("equips", "where ID = "+strconv.FormatInt(uid, 10)) {
|
if !sql.db.CanFind("equips", "WHERE ID = ?", uid) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = sql.db.Find("equips", &userInfo, "where ID = "+strconv.FormatInt(uid, 10))
|
err = sql.db.Find("equips", &userInfo, "WHERE ID = ?", uid)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,7 +368,7 @@ func (sql *fishdb) updateUserEquip(userInfo equip) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if userInfo.Durable == 0 {
|
if userInfo.Durable == 0 {
|
||||||
return sql.db.Del("equips", "where ID = "+strconv.FormatInt(userInfo.ID, 10))
|
return sql.db.Del("equips", "WHERE ID = ?", userInfo.ID)
|
||||||
}
|
}
|
||||||
return sql.db.Insert("equips", &userInfo)
|
return sql.db.Insert("equips", &userInfo)
|
||||||
}
|
}
|
||||||
@ -400,13 +390,13 @@ func (sql *fishdb) pickFishFor(uid int64, number int) (fishNames map[string]int,
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !sql.db.CanFind(name, "where Type is 'fish'") {
|
if !sql.db.CanFind(name, "WHERE Type = 'fish'") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fishInfo := article{}
|
fishInfo := article{}
|
||||||
k := 0
|
k := 0
|
||||||
for i := number * 2; i > 0 && k < len(fishList); {
|
for i := number; i > 0 && k < len(fishList); {
|
||||||
_ = sql.db.Find(name, &fishInfo, "where Name is '"+fishList[k]+"'")
|
_ = sql.db.Find(name, &fishInfo, "WHERE Name = ?", fishList[k])
|
||||||
if fishInfo.Number <= 0 {
|
if fishInfo.Number <= 0 {
|
||||||
k++
|
k++
|
||||||
continue
|
continue
|
||||||
@ -422,7 +412,7 @@ func (sql *fishdb) pickFishFor(uid int64, number int) (fishNames map[string]int,
|
|||||||
i = 0
|
i = 0
|
||||||
}
|
}
|
||||||
if fishInfo.Number <= 0 {
|
if fishInfo.Number <= 0 {
|
||||||
err = sql.db.Del(name, "where Duration = "+strconv.FormatInt(fishInfo.Duration, 10))
|
err = sql.db.Del(name, "WHERE Duration = ?", fishInfo.Duration)
|
||||||
} else {
|
} else {
|
||||||
err = sql.db.Insert(name, &fishInfo)
|
err = sql.db.Insert(name, &fishInfo)
|
||||||
}
|
}
|
||||||
@ -477,13 +467,13 @@ func (sql *fishdb) getUserThingInfo(uid int64, thing string) (thingInfos []artic
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !sql.db.CanFind(name, "where Name = '"+thing+"'") {
|
if !sql.db.CanFind(name, "WHERE Name = ?", thing) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = sql.db.FindFor(name, &userInfo, "where Name = '"+thing+"'", func() error {
|
err = sql.db.FindFor(name, &userInfo, "WHERE Name = ?", func() error {
|
||||||
thingInfos = append(thingInfos, userInfo)
|
thingInfos = append(thingInfos, userInfo)
|
||||||
return nil
|
return nil
|
||||||
})
|
}, thing)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,7 +487,7 @@ func (sql *fishdb) updateUserThingInfo(uid int64, userInfo article) (err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if userInfo.Number == 0 {
|
if userInfo.Number == 0 {
|
||||||
return sql.db.Del(name, "where Duration = "+strconv.FormatInt(userInfo.Duration, 10))
|
return sql.db.Del(name, "WHERE Duration = ?", userInfo.Duration)
|
||||||
}
|
}
|
||||||
return sql.db.Insert(name, &userInfo)
|
return sql.db.Insert(name, &userInfo)
|
||||||
}
|
}
|
||||||
@ -519,14 +509,14 @@ func (sql *fishdb) getNumberFor(uid int64, thing string) (number int, err error)
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !sql.db.CanFind(name, "where Name glob '*"+thing+"*'") {
|
if !sql.db.CanFind(name, "WHERE Name glob ?", "*"+thing+"*") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
info := article{}
|
info := article{}
|
||||||
err = sql.db.FindFor(name, &info, "where Name glob '*"+thing+"*'", func() error {
|
err = sql.db.FindFor(name, &info, "WHERE Name glob ?", func() error {
|
||||||
number += info.Number
|
number += info.Number
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "*"+thing+"*")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,13 +530,13 @@ func (sql *fishdb) getUserTypeInfo(uid int64, thingType string) (thingInfos []ar
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !sql.db.CanFind(name, "where Type = '"+thingType+"'") {
|
if !sql.db.CanFind(name, "WHERE Type = ?", thingType) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = sql.db.FindFor(name, &userInfo, "where Type = '"+thingType+"'", func() error {
|
err = sql.db.FindFor(name, &userInfo, "WHERE Type = ?", func() error {
|
||||||
thingInfos = append(thingInfos, userInfo)
|
thingInfos = append(thingInfos, userInfo)
|
||||||
return nil
|
return nil
|
||||||
})
|
}, thingType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,7 +557,7 @@ func (sql *fishdb) refreshStroeInfo() (ok bool, err error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
lastTime := storeDiscount{}
|
lastTime := storeDiscount{}
|
||||||
_ = sql.db.Find("stroeDiscount", &lastTime, "where Name = 'lastTime'")
|
_ = sql.db.Find("stroeDiscount", &lastTime, "WHERE Name = 'lastTime'")
|
||||||
refresh := false
|
refresh := false
|
||||||
timeNow := time.Now().Day()
|
timeNow := time.Now().Day()
|
||||||
if timeNow != lastTime.Discount {
|
if timeNow != lastTime.Discount {
|
||||||
@ -591,17 +581,17 @@ func (sql *fishdb) refreshStroeInfo() (ok bool, err error) {
|
|||||||
Discount: thingDiscount,
|
Discount: thingDiscount,
|
||||||
}
|
}
|
||||||
thingInfo := store{}
|
thingInfo := store{}
|
||||||
_ = sql.db.Find("store", &thingInfo, "where Name = '"+name+"'")
|
_ = sql.db.Find("store", &thingInfo, "WHERE Name = ?", name)
|
||||||
if thingInfo.Number > 150 {
|
if thingInfo.Number > 150 {
|
||||||
// 通货膨胀
|
// 控制价格浮动区间: -10%到10%
|
||||||
thing.Discount = (1000 - 5*(thingInfo.Number-150)) / 10
|
thing.Discount = 90 + rand.Intn(20)
|
||||||
}
|
}
|
||||||
err = sql.db.Insert("stroeDiscount", &thing)
|
err = sql.db.Insert("stroeDiscount", &thing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
_ = sql.db.Find("stroeDiscount", &thing, "where Name = '"+name+"'")
|
_ = sql.db.Find("stroeDiscount", &thing, "WHERE Name = ?", name)
|
||||||
}
|
}
|
||||||
if thing.Discount != 0 {
|
if thing.Discount != 0 {
|
||||||
discountList[name] = thing.Discount
|
discountList[name] = thing.Discount
|
||||||
@ -610,15 +600,15 @@ func (sql *fishdb) refreshStroeInfo() (ok bool, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
thing := store{}
|
thing := store{}
|
||||||
oldThing := []store{}
|
var oldThing []store
|
||||||
_ = sql.db.FindFor("stroeDiscount", &thing, "where type = 'pole'", func() error {
|
_ = sql.db.FindFor("stroeDiscount", &thing, "WHERE type = 'pole'", func() error {
|
||||||
if time.Since(time.Unix(thing.Duration, 0)) > 24 {
|
if time.Since(time.Unix(thing.Duration, 0)) > 24 {
|
||||||
oldThing = append(oldThing, thing)
|
oldThing = append(oldThing, thing)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
for _, info := range oldThing {
|
for _, info := range oldThing {
|
||||||
_ = sql.db.Del("stroeDiscount", "where Duration = "+strconv.FormatInt(info.Duration, 10))
|
_ = sql.db.Del("stroeDiscount", "WHERE Duration = ?", info.Duration)
|
||||||
}
|
}
|
||||||
if refresh {
|
if refresh {
|
||||||
// 每天调控1种鱼
|
// 每天调控1种鱼
|
||||||
@ -629,21 +619,25 @@ func (sql *fishdb) refreshStroeInfo() (ok bool, err error) {
|
|||||||
Type: "fish",
|
Type: "fish",
|
||||||
Price: priceList[fish] * discountList[fish] / 100,
|
Price: priceList[fish] * discountList[fish] / 100,
|
||||||
}
|
}
|
||||||
_ = sql.db.Find("store", &thingInfo, "where Name = '"+fish+"'")
|
_ = sql.db.Find("store", &thingInfo, "WHERE Name = ?", fish)
|
||||||
thingInfo.Number += (100 - discountList[fish])
|
thingInfo.Number += 100 - discountList[fish]
|
||||||
if thingInfo.Number < 1 {
|
if thingInfo.Number < 1 {
|
||||||
thingInfo.Number = 100
|
thingInfo.Number = 100
|
||||||
}
|
}
|
||||||
_ = sql.db.Insert("store", &thingInfo)
|
_ = sql.db.Insert("store", &thingInfo)
|
||||||
// 每天上架20本净化书
|
// 每天上架1木竿
|
||||||
thingInfo = store{
|
thingInfo = store{
|
||||||
Duration: time.Now().Unix(),
|
Duration: time.Now().Unix(),
|
||||||
Name: "净化书",
|
Name: "初始木竿",
|
||||||
Type: "article",
|
Type: "pole",
|
||||||
Price: priceList["净化书"] * discountList["净化书"] / 100,
|
Price: priceList["木竿"] + priceList["木竿"]*discountList["木竿"]/100,
|
||||||
|
Other: "30/0/0/0",
|
||||||
|
}
|
||||||
|
_ = sql.db.Find("store", &thingInfo, "WHERE Name = '初始木竿'")
|
||||||
|
thingInfo.Number++
|
||||||
|
if thingInfo.Number > 5 {
|
||||||
|
thingInfo.Number = 1
|
||||||
}
|
}
|
||||||
_ = sql.db.Find("store", &thingInfo, "where Name = '净化书'")
|
|
||||||
thingInfo.Number = 20
|
|
||||||
_ = sql.db.Insert("store", &thingInfo)
|
_ = sql.db.Insert("store", &thingInfo)
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
@ -688,13 +682,13 @@ func (sql *fishdb) getStoreThingInfo(thing string) (thingInfos []store, err erro
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !sql.db.CanFind("store", "where Name = '"+thing+"'") {
|
if !sql.db.CanFind("store", "WHERE Name = ?", thing) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = sql.db.FindFor("store", &thingInfo, "where Name = '"+thing+"'", func() error {
|
err = sql.db.FindFor("store", &thingInfo, "WHERE Name = ?", func() error {
|
||||||
thingInfos = append(thingInfos, thingInfo)
|
thingInfos = append(thingInfos, thingInfo)
|
||||||
return nil
|
return nil
|
||||||
})
|
}, thing)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,10 +707,10 @@ func (sql *fishdb) checkStoreFor(thing store, number int) (ok bool, err error) {
|
|||||||
if count == 0 {
|
if count == 0 {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
if !sql.db.CanFind("store", "where Duration = "+strconv.FormatInt(thing.Duration, 10)) {
|
if !sql.db.CanFind("store", "WHERE Duration = ?", thing.Duration) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
err = sql.db.Find("store", &thing, "where Duration = "+strconv.FormatInt(thing.Duration, 10))
|
err = sql.db.Find("store", &thing, "WHERE Duration = ?", thing.Duration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -735,7 +729,7 @@ func (sql *fishdb) updateStoreInfo(thingInfo store) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if thingInfo.Number == 0 {
|
if thingInfo.Number == 0 {
|
||||||
return sql.db.Del("store", "where Duration = "+strconv.FormatInt(thingInfo.Duration, 10))
|
return sql.db.Del("store", "WHERE Duration = ?", thingInfo.Duration)
|
||||||
}
|
}
|
||||||
return sql.db.Insert("store", &thingInfo)
|
return sql.db.Insert("store", &thingInfo)
|
||||||
}
|
}
|
||||||
@ -749,7 +743,7 @@ func (sql *fishdb) updateBuyTimeFor(uid int64, add int) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_ = sql.db.Find("buff", &userInfo, "where ID = "+strconv.FormatInt(uid, 10))
|
_ = sql.db.Find("buff", &userInfo, "WHERE ID = ?", uid)
|
||||||
userInfo.BuyTimes += add
|
userInfo.BuyTimes += add
|
||||||
if userInfo.BuyTimes > 20 {
|
if userInfo.BuyTimes > 20 {
|
||||||
userInfo.BuyTimes -= 20
|
userInfo.BuyTimes -= 20
|
||||||
@ -768,7 +762,7 @@ func (sql *fishdb) useCouponAt(uid int64, times int) (int, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return useTimes, err
|
return useTimes, err
|
||||||
}
|
}
|
||||||
_ = sql.db.Find("buff", &userInfo, "where ID = "+strconv.FormatInt(uid, 10))
|
_ = sql.db.Find("buff", &userInfo, "WHERE ID = ?", uid)
|
||||||
if userInfo.Coupon > 0 {
|
if userInfo.Coupon > 0 {
|
||||||
useTimes = math.Min(userInfo.Coupon, times)
|
useTimes = math.Min(userInfo.Coupon, times)
|
||||||
userInfo.Coupon -= useTimes
|
userInfo.Coupon -= useTimes
|
||||||
@ -776,64 +770,66 @@ func (sql *fishdb) useCouponAt(uid int64, times int) (int, error) {
|
|||||||
return useTimes, sql.db.Insert("buff", &userInfo)
|
return useTimes, sql.db.Insert("buff", &userInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测卖鱼竿上限
|
// 买卖上限检测
|
||||||
func (sql *fishdb) checkCanSalesFor(uid int64, sales bool) (int, error) {
|
func (sql *fishdb) checkCanSalesFor(uid int64, saleName string, salesNum int) (int, error) {
|
||||||
residue := 0
|
|
||||||
sql.Lock()
|
sql.Lock()
|
||||||
defer sql.Unlock()
|
defer sql.Unlock()
|
||||||
userInfo := buffInfo{ID: uid}
|
userInfo := buffInfo{ID: uid}
|
||||||
err := sql.db.Create("buff", &userInfo)
|
err := sql.db.Create("buff", &userInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return residue, err
|
return salesNum, err
|
||||||
}
|
}
|
||||||
_ = sql.db.Find("buff", &userInfo, "where ID = "+strconv.FormatInt(uid, 10))
|
_ = sql.db.Find("buff", &userInfo, "WHERE ID = ?", uid)
|
||||||
if time.Now().Day() != time.Unix(userInfo.Duration, 0).Day() {
|
if time.Now().Day() != time.Unix(userInfo.Duration, 0).Day() {
|
||||||
userInfo.Duration = time.Now().Unix()
|
userInfo.Duration = time.Now().Unix()
|
||||||
userInfo.SalesPole = 0
|
userInfo.SalesPole = 0
|
||||||
userInfo.BuyTing = 0
|
userInfo.BuyTing = 0
|
||||||
|
err := sql.db.Insert("buff", &userInfo)
|
||||||
|
if err != nil {
|
||||||
|
return salesNum, err
|
||||||
}
|
}
|
||||||
if sales && userInfo.SalesPole < 5 {
|
|
||||||
residue = 5 - userInfo.SalesPole
|
|
||||||
userInfo.SalesPole++
|
|
||||||
} else if userInfo.BuyTing < 15 {
|
|
||||||
residue = 15 - userInfo.BuyTing
|
|
||||||
userInfo.BuyTing++
|
|
||||||
}
|
}
|
||||||
return residue, sql.db.Insert("buff", &userInfo)
|
if strings.Contains(saleName, "竿") {
|
||||||
|
if userInfo.SalesPole >= 10 {
|
||||||
|
salesNum = -1
|
||||||
|
}
|
||||||
|
} else if !checkIsWaste(saleName) {
|
||||||
|
maxSales := 30 - userInfo.BuyTing
|
||||||
|
if maxSales < 0 {
|
||||||
|
salesNum = 0
|
||||||
|
}
|
||||||
|
if salesNum > maxSales {
|
||||||
|
salesNum = maxSales
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测物品是否是鱼
|
return salesNum, err
|
||||||
func checkIsFish(thing string) bool {
|
}
|
||||||
for _, v := range fishList {
|
|
||||||
|
// 更新买卖鱼上限,假定sales变量已经在 checkCanSalesFor 进行了防护
|
||||||
|
func (sql *fishdb) updateCanSalesFor(uid int64, saleName string, sales int) error {
|
||||||
|
sql.Lock()
|
||||||
|
defer sql.Unlock()
|
||||||
|
userInfo := buffInfo{ID: uid}
|
||||||
|
err := sql.db.Create("buff", &userInfo)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = sql.db.Find("buff", &userInfo, "WHERE ID = ?", uid)
|
||||||
|
if strings.Contains(saleName, "竿") {
|
||||||
|
userInfo.SalesPole++
|
||||||
|
} else if !checkIsWaste(saleName) {
|
||||||
|
userInfo.BuyTing += sales
|
||||||
|
}
|
||||||
|
return sql.db.Insert("buff", &userInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测物品是否是垃圾
|
||||||
|
func checkIsWaste(thing string) bool {
|
||||||
|
for _, v := range wasteList {
|
||||||
if v == thing {
|
if v == thing {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测买卖鱼上限
|
|
||||||
func (sql *fishdb) checkCanSalesFishFor(uid int64, sales int) (int, error) {
|
|
||||||
residue := 0
|
|
||||||
sql.Lock()
|
|
||||||
defer sql.Unlock()
|
|
||||||
userInfo := buffInfo{ID: uid}
|
|
||||||
err := sql.db.Create("buff", &userInfo)
|
|
||||||
if err != nil {
|
|
||||||
return residue, err
|
|
||||||
}
|
|
||||||
_ = sql.db.Find("buff", &userInfo, "where ID = "+strconv.FormatInt(uid, 10))
|
|
||||||
if time.Now().Day() != time.Unix(userInfo.Duration, 0).Day() {
|
|
||||||
userInfo.Duration = time.Now().Unix()
|
|
||||||
userInfo.SalesFish = 0
|
|
||||||
}
|
|
||||||
maxSales := 100 - userInfo.SalesFish
|
|
||||||
if maxSales < 0 {
|
|
||||||
maxSales = 0
|
|
||||||
}
|
|
||||||
if sales > maxSales {
|
|
||||||
sales = maxSales
|
|
||||||
}
|
|
||||||
userInfo.SalesFish += sales
|
|
||||||
return sales, sql.db.Insert("buff", &userInfo)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -42,9 +42,9 @@ func init() {
|
|||||||
}
|
}
|
||||||
ctx.SendChain(message.ImageBytes(pic))
|
ctx.SendChain(message.ImageBytes(pic))
|
||||||
})
|
})
|
||||||
engine.OnRegex(`^消除绑定诅咒(\d*)$`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
engine.OnRegex(`^消除(绑定|宝藏)诅咒(\d*)$`, getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||||
uid := ctx.Event.UserID
|
uid := ctx.Event.UserID
|
||||||
number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[1])
|
number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[2])
|
||||||
if number == 0 {
|
if number == 0 {
|
||||||
number = 1
|
number = 1
|
||||||
}
|
}
|
||||||
@ -171,6 +171,31 @@ func init() {
|
|||||||
msg = append(msg, message.Text("-----------"))
|
msg = append(msg, message.Text("-----------"))
|
||||||
ctx.Send(msg)
|
ctx.Send(msg)
|
||||||
})
|
})
|
||||||
|
engine.OnFullMatch("查看钓鱼规则", getdb).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||||
|
msg := "一款钓鱼模拟器\n----------指令----------\n" +
|
||||||
|
"- 钓鱼看板/钓鱼商店\n- 购买xxx\n- 购买xxx [数量]\n- 出售xxx\n- 出售xxx [数量]\n- 出售所有垃圾\n" +
|
||||||
|
"- 钓鱼背包\n- 装备[xx竿|三叉戟|美西螈]\n- 附魔[诱钓|海之眷顾]\n- 修复鱼竿\n- 合成[xx竿|三叉戟]\n- 消除[绑定|宝藏]诅咒\n- 消除[绑定|宝藏]诅咒 [数量]\n" +
|
||||||
|
"- 进行钓鱼\n- 进行n次钓鱼\n- " +
|
||||||
|
"当前装备概率明细\n" +
|
||||||
|
"规则V" + version + ":\n" +
|
||||||
|
"1.每日的商店价格是波动的!!如何最大化收益自己考虑一下喔\n" +
|
||||||
|
"2.装备信息:\n-> 木竿 : 耐久上限:30 均价:100 上钩概率:0.7%\n-> 铁竿 : 耐久上限:50 均价:300 上钩概率:0.2%\n-> 金竿 : 耐久上限:70 均价700 上钩概率:0.06%\n" +
|
||||||
|
"-> 钻石竿 : 耐久上限:100 均价1500 上钩概率:0.03%\n-> 下界合金竿 : 耐久上限:150 均价3100 上钩概率:0.01%\n-> 三叉戟 : 可使1次钓鱼视为3次钓鱼. 耐久上限:300 均价4000 只能合成、修复和交易\n" +
|
||||||
|
"3.附魔书信息:\n-> 诱钓 : 减少上钩时间. 均价:1000, 上钩概率:0.25%\n-> 海之眷顾 : 增加宝藏上钩概率. 均价:2500, 上钩概率:0.10%\n" +
|
||||||
|
"4.稀有物品:\n-> 唱片 : 出售物品时使用该物品使价格翻倍. 均价:3000, 上钩概率:0.01%\n" +
|
||||||
|
"-> 美西螈 : 可装备,获得隐形[钓鱼佬]buff,并让钓到除鱼竿和美西螈外的物品数量变成5,无耐久上限.不可修复/附魔,每次钓鱼消耗3条鱼. 均价:3000, 上钩概率:0.01%\n" +
|
||||||
|
"-> 海豚 : 使空竿概率变成垃圾概率. 均价:1000, 上钩概率:0.19%\n" +
|
||||||
|
"-> 宝藏诅咒 : 无法交易,每一层就会增加购买时10%价格和减少出售时10%价格(超过10层会变为倒贴钱). 上钩概率:0.25%\n-> 净化书 : 用于消除宝藏诅咒. 均价:5000, 上钩概率:0.19%\n" +
|
||||||
|
"5.鱼类信息:\n-> 鳕鱼 : 均价:10 上钩概率:0.69%\n-> 鲑鱼 : 均价:50 上钩概率:0.2%\n-> 热带鱼 : 均价:100 上钩概率:0.06%\n-> 河豚 : 均价:300 上钩概率:0.03%\n-> 鹦鹉螺 : 均价:500 上钩概率:0.01%\n-> 墨鱼 : 均价:500 上钩概率:0.01%\n" +
|
||||||
|
"6.垃圾:\n-> 均价:10 上钩概率:30%\n" +
|
||||||
|
"7.物品BUFF:\n-> 钓鱼佬 : 当背包名字含有'鱼'的物品数量超过100时激活,钓到物品概率提高至90%\n-> 修复大师 : 当背包鱼竿数量超过10时激活,修复物品时耐久百分百继承\n" +
|
||||||
|
"8.合成:\n-> 铁竿 : 3x木竿\n-> 金竿 : 3x铁竿\n-> 钻石竿 : 3x金竿\n-> 下界合金竿 : 3x钻石竿\n-> 三叉戟 : 3x下界合金竿\n注:合成成功率90%(包括梭哈),合成鱼竿的附魔等级=(附魔等级合/合成鱼竿数量)\n" +
|
||||||
|
"9.杂项:\n-> 无装备的情况下,每人最多可以购买3次100块钱的鱼竿,商店每日会上架1木竿\n-> 默认状态钓鱼上钩概率为60%(理论值!!!)\n-> 附魔的鱼竿会因附魔变得昂贵,每个附魔最高3级\n-> 三叉戟不算鱼竿,修复时可直接满耐久\n" +
|
||||||
|
"-> 鱼竿数量大于50的不能买东西;\n 鱼竿数量大于30的不能钓鱼;\n 每购/售10次鱼竿获得1层宝藏诅咒;\n 每购买20次物品将获得3次价格减半福利;\n 每钓鱼75次获得1本净化书;\n" +
|
||||||
|
" 每天可交易鱼竿10个,购买物品30件(垃圾除外)."
|
||||||
|
|
||||||
|
ctx.Send(msg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func drawPackImage(uid int64, equipInfo equip, articles []article) (imagePicByte []byte, err error) {
|
func drawPackImage(uid int64, equipInfo equip, articles []article) (imagePicByte []byte, err error) {
|
||||||
|
|||||||
@ -70,33 +70,24 @@ func init() {
|
|||||||
engine.OnRegex(`^出售(`+strings.Join(thingList, "|")+`)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(limitSet).Handle(func(ctx *zero.Ctx) {
|
engine.OnRegex(`^出售(`+strings.Join(thingList, "|")+`)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(limitSet).Handle(func(ctx *zero.Ctx) {
|
||||||
uid := ctx.Event.UserID
|
uid := ctx.Event.UserID
|
||||||
thingName := ctx.State["regex_matched"].([]string)[1]
|
thingName := ctx.State["regex_matched"].([]string)[1]
|
||||||
if strings.Contains(thingName, "竿") {
|
|
||||||
times, err := dbdata.checkCanSalesFor(uid, true)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("[ERROR at store.go.75]:", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if times <= 0 {
|
|
||||||
ctx.SendChain(message.Text("出售次数已达到上限,明天再来售卖吧"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[2])
|
number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[2])
|
||||||
if number == 0 || strings.Contains(thingName, "竿") {
|
if number == 0 || strings.Contains(thingName, "竿") {
|
||||||
number = 1
|
number = 1
|
||||||
}
|
}
|
||||||
if checkIsFish(thingName) {
|
|
||||||
residue, err := dbdata.checkCanSalesFishFor(uid, number)
|
// 检测物品交易次数
|
||||||
|
if strings.Contains(thingName, "竿") {
|
||||||
|
number, err := dbdata.checkCanSalesFor(uid, thingName, number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("[ERROR]:", err))
|
ctx.SendChain(message.Text("[ERROR,查询购买资质失败]:", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if residue <= 0 {
|
if number <= 0 {
|
||||||
ctx.SendChain(message.Text("今天你已经超出了鱼交易数量上限,明天再来买鱼吧"))
|
ctx.SendChain(message.Text("一天只能交易10把鱼竿,明天再来售卖吧"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
number = residue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
articles, err := dbdata.getUserThingInfo(uid, thingName)
|
articles, err := dbdata.getUserThingInfo(uid, thingName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("[ERROR at store.go.5]:", err))
|
ctx.SendChain(message.Text("[ERROR at store.go.5]:", err))
|
||||||
@ -318,7 +309,13 @@ func init() {
|
|||||||
logrus.Warnln(err)
|
logrus.Warnln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("出售成功,你赚到了", pice*number, msg)))
|
// 更新交易限制
|
||||||
|
err = dbdata.updateCanSalesFor(uid, thingName, number)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("[ERROR,记录鱼类交易数量失败,此次交易不记录]:", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("成功出售", thingName, ":", number, "个", ",你赚到了", pice*number, msg)))
|
||||||
})
|
})
|
||||||
engine.OnRegex(`^出售所有垃圾`, getdb, refreshFish).SetBlock(true).Limit(limitSet).Handle(func(ctx *zero.Ctx) {
|
engine.OnRegex(`^出售所有垃圾`, getdb, refreshFish).SetBlock(true).Limit(limitSet).Handle(func(ctx *zero.Ctx) {
|
||||||
uid := ctx.Event.UserID
|
uid := ctx.Event.UserID
|
||||||
@ -396,8 +393,14 @@ func init() {
|
|||||||
}
|
}
|
||||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("出售成功,你赚到了", pice, msg)))
|
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("出售成功,你赚到了", pice, msg)))
|
||||||
})
|
})
|
||||||
engine.OnRegex(`^购买(`+strings.Join(thingList, "|")+`)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(limitSet).Handle(func(ctx *zero.Ctx) {
|
engine.OnRegex(`^购买(`+strings.Join(thingList, "|")+`|初始木竿)\s*(\d*)$`, getdb, refreshFish).SetBlock(true).Limit(limitSet).Handle(func(ctx *zero.Ctx) {
|
||||||
uid := ctx.Event.UserID
|
uid := ctx.Event.UserID
|
||||||
|
thingName := ctx.State["regex_matched"].([]string)[1]
|
||||||
|
number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[2])
|
||||||
|
if number == 0 || strings.Contains(thingName, "竿") {
|
||||||
|
number = 1
|
||||||
|
}
|
||||||
|
|
||||||
numberOfPole, err := dbdata.getNumberFor(uid, "竿")
|
numberOfPole, err := dbdata.getNumberFor(uid, "竿")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("[ERROR at store.go.9.3]:", err))
|
ctx.SendChain(message.Text("[ERROR at store.go.9.3]:", err))
|
||||||
@ -407,32 +410,24 @@ func init() {
|
|||||||
ctx.SendChain(message.Text("你有", numberOfPole, "支鱼竿,大于50支的玩家不允许购买东西"))
|
ctx.SendChain(message.Text("你有", numberOfPole, "支鱼竿,大于50支的玩家不允许购买东西"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
buytimes, err := dbdata.checkCanSalesFor(uid, false)
|
|
||||||
|
// 检测物品交易次数
|
||||||
|
number, err = dbdata.checkCanSalesFor(uid, thingName, number)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("[ERROR at store.go.75]:", err))
|
ctx.SendChain(message.Text("[ERROR at store.go.75]:", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if buytimes <= 0 {
|
if number <= 0 {
|
||||||
ctx.SendChain(message.Text("购买次数已达到上限,明天再来购买吧"))
|
var msg string
|
||||||
|
if strings.Contains(thingName, "竿") {
|
||||||
|
msg = "一天只能交易10把鱼竿,明天再来购买吧"
|
||||||
|
} else {
|
||||||
|
msg = "一天只能购买30次物品,明天再来吧~"
|
||||||
|
}
|
||||||
|
ctx.SendChain(message.Text(msg))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
thingName := ctx.State["regex_matched"].([]string)[1]
|
|
||||||
number, _ := strconv.Atoi(ctx.State["regex_matched"].([]string)[2])
|
|
||||||
if number == 0 {
|
|
||||||
number = 1
|
|
||||||
}
|
|
||||||
if checkIsFish(thingName) {
|
|
||||||
residue, err := dbdata.checkCanSalesFishFor(uid, number)
|
|
||||||
if err != nil {
|
|
||||||
ctx.SendChain(message.Text("[ERROR]:", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if residue <= 0 {
|
|
||||||
ctx.SendChain(message.Text("今天你已经超出了鱼交易数量上限,明天再来买鱼吧"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
number = residue
|
|
||||||
}
|
|
||||||
thingInfos, err := dbdata.getStoreThingInfo(thingName)
|
thingInfos, err := dbdata.getStoreThingInfo(thingName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("[ERROR at store.go.11]:", err))
|
ctx.SendChain(message.Text("[ERROR at store.go.11]:", err))
|
||||||
@ -477,6 +472,9 @@ func init() {
|
|||||||
thingPice := (priceList[info.Name] - (durationList[info.Name] - durable) - maintenance*2 +
|
thingPice := (priceList[info.Name] - (durationList[info.Name] - durable) - maintenance*2 +
|
||||||
induceLevel*600*discountList["诱钓"]/100 +
|
induceLevel*600*discountList["诱钓"]/100 +
|
||||||
favorLevel*1800*discountList["海之眷顾"]/100) * discountList[info.Name] / 100
|
favorLevel*1800*discountList["海之眷顾"]/100) * discountList[info.Name] / 100
|
||||||
|
if strings.Contains(thingName, "初始木竿") {
|
||||||
|
thingPice = priceList["木竿"] + priceList["木竿"]*discountList["木竿"]/100
|
||||||
|
}
|
||||||
pice = append(pice, thingPice)
|
pice = append(pice, thingPice)
|
||||||
} else {
|
} else {
|
||||||
thingPice := priceList[info.Name] * discountList[info.Name] / 100
|
thingPice := priceList[info.Name] * discountList[info.Name] / 100
|
||||||
@ -623,6 +621,9 @@ func init() {
|
|||||||
Number: 1,
|
Number: 1,
|
||||||
Other: thing.Other,
|
Other: thing.Other,
|
||||||
}
|
}
|
||||||
|
if thingName == "初始木竿" {
|
||||||
|
newCommodity.Name = "木竿"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
things, err1 := dbdata.getUserThingInfo(uid, thingName)
|
things, err1 := dbdata.getUserThingInfo(uid, thingName)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
@ -650,6 +651,11 @@ func init() {
|
|||||||
logrus.Warnln(err)
|
logrus.Warnln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 更新交易限制
|
||||||
|
err = dbdata.updateCanSalesFor(uid, thingName, number)
|
||||||
|
if err != nil {
|
||||||
|
ctx.SendChain(message.Text("[ERROR,记录鱼类交易数量失败,此次交易不记录]:", err))
|
||||||
|
}
|
||||||
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你用", price, "购买了", number, thingName)))
|
ctx.Send(message.ReplyWithMessage(ctx.Event.MessageID, message.Text("你用", price, "购买了", number, thingName)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -794,6 +800,9 @@ func drawStroeInfoImage(stroeInfo []store) (picImage image.Image, err error) {
|
|||||||
induceLevel, _ := strconv.Atoi(poleInfo[2])
|
induceLevel, _ := strconv.Atoi(poleInfo[2])
|
||||||
favorLevel, _ := strconv.Atoi(poleInfo[3])
|
favorLevel, _ := strconv.Atoi(poleInfo[3])
|
||||||
pice = (priceList[info.Name] - (durationList[info.Name] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discountList[info.Name] / 100
|
pice = (priceList[info.Name] - (durationList[info.Name] - durable) - maintenance*2 + induceLevel*600 + favorLevel*1800) * discountList[info.Name] / 100
|
||||||
|
if strings.Contains(name, "初始木竿") {
|
||||||
|
pice = priceList["木竿"] + priceList["木竿"]*discountList["木竿"]/100
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pice = priceList[info.Name] * discountList[info.Name] / 100
|
pice = priceList[info.Name] * discountList[info.Name] / 100
|
||||||
}
|
}
|
||||||
|
|||||||
@ -229,7 +229,7 @@ func init() {
|
|||||||
return path.Ext(ctx.Event.File.Name) == ".mid"
|
return path.Ext(ctx.Event.File.Name) == ".mid"
|
||||||
}).SetBlock(false).Limit(ctxext.LimitByGroup).
|
}).SetBlock(false).Limit(ctxext.LimitByGroup).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
fileURL := ctx.GetThisGroupFileUrl(ctx.Event.File.BusID, ctx.Event.File.ID)
|
fileURL := ctx.GetThisGroupFileURL(ctx.Event.File.BusID, ctx.Event.File.ID)
|
||||||
data, err := web.GetData(fileURL)
|
data, err := web.GetData(fileURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
@ -242,12 +242,12 @@ func init() {
|
|||||||
}
|
}
|
||||||
for i := 0; i < int(s.NumTracks()); i++ {
|
for i := 0; i < int(s.NumTracks()); i++ {
|
||||||
midStr := mid2txt(data, i)
|
midStr := mid2txt(data, i)
|
||||||
|
fileName := strings.ReplaceAll(cachePath+"/"+ctx.Event.File.Name, ".mid", fmt.Sprintf("-%d.txt", i))
|
||||||
|
err := os.WriteFile(fileName, binary.StringToBytes(midStr), 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fileName := strings.ReplaceAll(cachePath+"/"+ctx.Event.File.Name, ".mid", fmt.Sprintf("-%d.txt", i))
|
|
||||||
_ = os.WriteFile(fileName, binary.StringToBytes(midStr), 0666)
|
|
||||||
ctx.UploadThisGroupFile(file.BOTPATH+"/"+fileName, filepath.Base(fileName), "")
|
ctx.UploadThisGroupFile(file.BOTPATH+"/"+fileName, filepath.Base(fileName), "")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -255,7 +255,7 @@ func init() {
|
|||||||
return path.Ext(ctx.Event.File.Name) == ".txt" && strings.Contains(ctx.Event.File.Name, "midi制作")
|
return path.Ext(ctx.Event.File.Name) == ".txt" && strings.Contains(ctx.Event.File.Name, "midi制作")
|
||||||
}).SetBlock(false).Limit(ctxext.LimitByGroup).
|
}).SetBlock(false).Limit(ctxext.LimitByGroup).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
fileURL := ctx.GetThisGroupFileUrl(ctx.Event.File.BusID, ctx.Event.File.ID)
|
fileURL := ctx.GetThisGroupFileURL(ctx.Event.File.BusID, ctx.Event.File.ID)
|
||||||
data, err := web.GetData(fileURL)
|
data, err := web.GetData(fileURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR: ", err))
|
ctx.SendChain(message.Text("ERROR: ", err))
|
||||||
|
|||||||
301
plugin/minecraftobserver/minecraftobserver.go
Normal file
301
plugin/minecraftobserver/minecraftobserver.go
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
// Package minecraftobserver 通过mc服务器地址获取服务器状态信息并绘制图片发送到QQ群
|
||||||
|
package minecraftobserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ctrl "github.com/FloatTech/zbpctrl"
|
||||||
|
"github.com/FloatTech/zbputils/control"
|
||||||
|
zbpCtxExt "github.com/FloatTech/zbputils/ctxext"
|
||||||
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
name = "minecraftobserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// 注册插件
|
||||||
|
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||||
|
// 默认不启动
|
||||||
|
DisableOnDefault: false,
|
||||||
|
Brief: "Minecraft服务器状态查询/订阅",
|
||||||
|
// 详细帮助
|
||||||
|
Help: "- mc服务器状态 [服务器IP/URI]\n" +
|
||||||
|
"- mc服务器添加订阅 [服务器IP/URI]\n" +
|
||||||
|
"- mc服务器取消订阅 [服务器IP/URI]\n" +
|
||||||
|
"- mc服务器订阅拉取 (需要插件定时任务配合使用,全局只需要设置一个)" +
|
||||||
|
"-----------------------\n" +
|
||||||
|
"使用job插件设置定时, 例:" +
|
||||||
|
"记录在\"@every 1m\"触发的指令\n" +
|
||||||
|
"(机器人回答:您的下一条指令将被记录,在@@every 1m时触发)" +
|
||||||
|
"mc服务器订阅拉取",
|
||||||
|
// 插件数据存储路径
|
||||||
|
PrivateDataFolder: name,
|
||||||
|
}).ApplySingle(zbpCtxExt.DefaultSingle)
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// 状态查询
|
||||||
|
engine.OnRegex("^[mM][cC]服务器状态 (.+)$").SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
// 关键词查找
|
||||||
|
addr := ctx.State["regex_matched"].([]string)[1]
|
||||||
|
resp, err := getMinecraftServerStatus(addr)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(message.Text("服务器状态获取失败... 错误信息: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
status := resp.genServerSubscribeSchema(addr, 0)
|
||||||
|
textMsg, iconBase64 := status.generateServerStatusMsg()
|
||||||
|
var msg message.Message
|
||||||
|
if iconBase64 != "" {
|
||||||
|
msg = append(msg, message.Image(iconBase64))
|
||||||
|
}
|
||||||
|
msg = append(msg, message.Text(textMsg))
|
||||||
|
if id := ctx.Send(msg); id.ID() == 0 {
|
||||||
|
// logrus.Errorln(logPrefix + "Send failed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 添加订阅
|
||||||
|
engine.OnRegex(`^[mM][cC]服务器添加订阅\s*(.+)$`, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
// 关键词查找
|
||||||
|
addr := ctx.State["regex_matched"].([]string)[1]
|
||||||
|
status, err := getMinecraftServerStatus(addr)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(message.Text("服务器信息初始化失败,请检查服务器是否可用!\n错误信息: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
targetID, targetType := warpTargetIDAndType(ctx.Event.GroupID, ctx.Event.UserID)
|
||||||
|
err = dbInstance.newSubscribe(addr, targetID, targetType)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(message.Text("订阅添加失败... 错误信息: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 插入数据库(首条,需要更新状态)
|
||||||
|
err = dbInstance.updateServerStatus(status.genServerSubscribeSchema(addr, 0))
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(message.Text("服务器状态更新失败... 错误信息: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if sid := ctx.Send(message.Text(fmt.Sprintf("服务器 %s 订阅添加成功", addr))); sid.ID() == 0 {
|
||||||
|
// logrus.Errorln(logPrefix + "Send failed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 成功后立即发送一次状态
|
||||||
|
textMsg, iconBase64 := status.genServerSubscribeSchema(addr, 0).generateServerStatusMsg()
|
||||||
|
var msg message.Message
|
||||||
|
if iconBase64 != "" {
|
||||||
|
msg = append(msg, message.Image(iconBase64))
|
||||||
|
}
|
||||||
|
msg = append(msg, message.Text(textMsg))
|
||||||
|
if id := ctx.Send(msg); id.ID() == 0 {
|
||||||
|
// logrus.Errorln(logPrefix + "Send failed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 删除
|
||||||
|
engine.OnRegex(`^[mM][cC]服务器取消订阅\s*(.+)$`, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
addr := ctx.State["regex_matched"].([]string)[1]
|
||||||
|
// 通过群组id和服务器地址获取服务器状态
|
||||||
|
targetID, targetType := warpTargetIDAndType(ctx.Event.GroupID, ctx.Event.UserID)
|
||||||
|
err := dbInstance.deleteSubscribe(addr, targetID, targetType)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(message.Text("取消订阅失败...", fmt.Sprintf("错误信息: %v", err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Send(message.Text("取消订阅成功"))
|
||||||
|
})
|
||||||
|
// 查看当前渠道的所有订阅
|
||||||
|
engine.OnRegex(`^[mM][cC]服务器订阅列表$`, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
subList, err := dbInstance.getSubscribesByTarget(warpTargetIDAndType(ctx.Event.GroupID, ctx.Event.UserID))
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(message.Text("获取订阅列表失败... 错误信息: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(subList) == 0 {
|
||||||
|
ctx.Send(message.Text("当前没有订阅哦"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stringBuilder := strings.Builder{}
|
||||||
|
stringBuilder.WriteString("[订阅列表]\n")
|
||||||
|
for _, v := range subList {
|
||||||
|
stringBuilder.WriteString(fmt.Sprintf("服务器地址: %s\n", v.ServerAddr))
|
||||||
|
}
|
||||||
|
if sid := ctx.Send(message.Text(stringBuilder.String())); sid.ID() == 0 {
|
||||||
|
// logrus.Errorln(logPrefix + "Send failed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 查看全局订阅情况(仅限管理员私聊可用)
|
||||||
|
engine.OnRegex(`^[mM][cC]服务器全局订阅列表$`, zero.OnlyPrivate, zero.SuperUserPermission, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
subList, err := dbInstance.getAllSubscribes()
|
||||||
|
if err != nil {
|
||||||
|
ctx.Send(message.Text("获取全局订阅列表失败... 错误信息: ", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(subList) == 0 {
|
||||||
|
ctx.Send(message.Text("当前一个订阅都没有哦"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userID := ctx.Event.UserID
|
||||||
|
userName := ctx.CardOrNickName(userID)
|
||||||
|
msg := make(message.Message, 0)
|
||||||
|
|
||||||
|
// 按照群组or用户分组来定
|
||||||
|
groupSubMap := make(map[int64][]serverSubscribe)
|
||||||
|
userSubMap := make(map[int64][]serverSubscribe)
|
||||||
|
for _, v := range subList {
|
||||||
|
switch v.TargetType {
|
||||||
|
case targetTypeGroup:
|
||||||
|
groupSubMap[v.TargetID] = append(groupSubMap[v.TargetID], v)
|
||||||
|
case targetTypeUser:
|
||||||
|
userSubMap[v.TargetID] = append(userSubMap[v.TargetID], v)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 群
|
||||||
|
for k, v := range groupSubMap {
|
||||||
|
stringBuilder := strings.Builder{}
|
||||||
|
stringBuilder.WriteString(fmt.Sprintf("[群 %d]存在以下订阅:\n", k))
|
||||||
|
for _, sub := range v {
|
||||||
|
stringBuilder.WriteString(fmt.Sprintf("服务器地址: %s\n", sub.ServerAddr))
|
||||||
|
}
|
||||||
|
msg = append(msg, message.CustomNode(userName, userID, stringBuilder.String()))
|
||||||
|
}
|
||||||
|
// 个人
|
||||||
|
for k, v := range userSubMap {
|
||||||
|
stringBuilder := strings.Builder{}
|
||||||
|
stringBuilder.WriteString(fmt.Sprintf("[用户 %d]存在以下订阅:\n", k))
|
||||||
|
for _, sub := range v {
|
||||||
|
stringBuilder.WriteString(fmt.Sprintf("服务器地址: %s\n", sub.ServerAddr))
|
||||||
|
}
|
||||||
|
msg = append(msg, message.CustomNode(userName, userID, stringBuilder.String()))
|
||||||
|
}
|
||||||
|
// 合并发送
|
||||||
|
ctx.SendPrivateForwardMessage(ctx.Event.UserID, msg)
|
||||||
|
})
|
||||||
|
// 状态变更通知,全局触发,逐个服务器检查,检查到变更则逐个发送通知
|
||||||
|
engine.OnRegex(`^[mM][cC]服务器订阅拉取$`, getDB).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||||
|
serverList, err := dbInstance.getAllSubscribes()
|
||||||
|
if err != nil {
|
||||||
|
su := zero.BotConfig.SuperUsers[0]
|
||||||
|
// 如果订阅列表获取失败,通知管理员
|
||||||
|
ctx.SendPrivateMessage(su, message.Text(logPrefix, "获取订阅列表失败..."))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// logrus.Debugln(logPrefix+"global get ", len(serverList), " subscribe(s)")
|
||||||
|
serverMap := make(map[string][]serverSubscribe)
|
||||||
|
for _, v := range serverList {
|
||||||
|
serverMap[v.ServerAddr] = append(serverMap[v.ServerAddr], v)
|
||||||
|
}
|
||||||
|
changedCount := 0
|
||||||
|
for subAddr, oneServerSubList := range serverMap {
|
||||||
|
// 查询当前存储的状态
|
||||||
|
storedStatus, sErr := dbInstance.getServerStatus(subAddr)
|
||||||
|
if sErr != nil {
|
||||||
|
// logrus.Errorln(logPrefix+fmt.Sprintf("getServerStatus ServerAddr(%s) error: ", subAddr), sErr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isChanged, changedNotifyMsg, sErr := singleServerScan(storedStatus)
|
||||||
|
if sErr != nil {
|
||||||
|
// logrus.Errorln(logPrefix+"singleServerScan error: ", sErr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !isChanged {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
changedCount++
|
||||||
|
// 发送变化信息
|
||||||
|
for _, subInfo := range oneServerSubList {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
if subInfo.TargetType == targetTypeUser {
|
||||||
|
ctx.SendPrivateMessage(subInfo.TargetID, changedNotifyMsg)
|
||||||
|
} else if subInfo.TargetType == targetTypeGroup {
|
||||||
|
m, ok := control.Lookup(name)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !m.IsEnabledIn(subInfo.TargetID) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ctx.SendGroupMessage(subInfo.TargetID, changedNotifyMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// singleServerScan 单个服务器状态扫描
|
||||||
|
func singleServerScan(oldSubStatus *serverStatus) (changed bool, notifyMsg message.Message, err error) {
|
||||||
|
notifyMsg = make(message.Message, 0)
|
||||||
|
newSubStatus := &serverStatus{}
|
||||||
|
// 获取服务器状态 & 检查是否需要更新
|
||||||
|
rawServerStatus, err := getMinecraftServerStatus(oldSubStatus.ServerAddr)
|
||||||
|
if err != nil {
|
||||||
|
// logrus.Warnln(logPrefix+"getMinecraftServerStatus error: ", err)
|
||||||
|
err = nil
|
||||||
|
// 计数器没有超限,增加计数器并跳过
|
||||||
|
if cnt, ts := addPingServerUnreachableCounter(oldSubStatus.ServerAddr, time.Now()); cnt < pingServerUnreachableCounterThreshold &&
|
||||||
|
time.Since(ts) < pingServerUnreachableCounterTimeThreshold {
|
||||||
|
// logrus.Warnln(logPrefix+"server ", oldSubStatus.ServerAddr, " unreachable, counter: ", cnt, " ts:", ts)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 不可达计数器已经超限,则更新服务器状态
|
||||||
|
// 深拷贝,设置PingDelay为不可达
|
||||||
|
newSubStatus = oldSubStatus.deepCopy()
|
||||||
|
newSubStatus.PingDelay = pingDelayUnreachable
|
||||||
|
} else {
|
||||||
|
newSubStatus = rawServerStatus.genServerSubscribeSchema(oldSubStatus.ServerAddr, oldSubStatus.ID)
|
||||||
|
}
|
||||||
|
if newSubStatus == nil {
|
||||||
|
// logrus.Errorln(logPrefix + "newSubStatus is nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 检查是否有订阅信息变化
|
||||||
|
if oldSubStatus.isServerStatusSpecChanged(newSubStatus) {
|
||||||
|
// logrus.Warnf(logPrefix+"server subscribe spec changed: (%+v) -> (%+v)", oldSubStatus, newSubStatus)
|
||||||
|
changed = true
|
||||||
|
// 更新数据库
|
||||||
|
err = dbInstance.updateServerStatus(newSubStatus)
|
||||||
|
if err != nil {
|
||||||
|
// logrus.Errorln(logPrefix+"updateServerSubscribeStatus error: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 纯文本信息
|
||||||
|
notifyMsg = append(notifyMsg, message.Text(formatSubStatusChangeText(oldSubStatus, newSubStatus)))
|
||||||
|
// 如果有图标变更
|
||||||
|
if oldSubStatus.FaviconMD5 != newSubStatus.FaviconMD5 {
|
||||||
|
// 有图标变更
|
||||||
|
notifyMsg = append(notifyMsg, message.Text("\n-----[图标变更]-----\n"))
|
||||||
|
// 旧图标
|
||||||
|
notifyMsg = append(notifyMsg, message.Text("[旧]\n"))
|
||||||
|
if oldSubStatus.FaviconRaw != "" {
|
||||||
|
notifyMsg = append(notifyMsg, message.Image(oldSubStatus.FaviconRaw.toBase64String()))
|
||||||
|
} else {
|
||||||
|
notifyMsg = append(notifyMsg, message.Text("(空)\n"))
|
||||||
|
}
|
||||||
|
// 新图标
|
||||||
|
notifyMsg = append(notifyMsg, message.Text("[新]\n"))
|
||||||
|
if newSubStatus.FaviconRaw != "" {
|
||||||
|
notifyMsg = append(notifyMsg, message.Image(newSubStatus.FaviconRaw.toBase64String()))
|
||||||
|
} else {
|
||||||
|
notifyMsg = append(notifyMsg, message.Text("(空)\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifyMsg = append(notifyMsg, message.Text("\n-------最新状态-------\n"))
|
||||||
|
// 服务状态
|
||||||
|
textMsg, iconBase64 := newSubStatus.generateServerStatusMsg()
|
||||||
|
if iconBase64 != "" {
|
||||||
|
notifyMsg = append(notifyMsg, message.Image(iconBase64))
|
||||||
|
}
|
||||||
|
notifyMsg = append(notifyMsg, message.Text(textMsg))
|
||||||
|
}
|
||||||
|
// 逻辑到达这里,说明状态已经变更 or 无变更且服务器可达,重置不可达计数器
|
||||||
|
resetPingServerUnreachableCounter(oldSubStatus.ServerAddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
127
plugin/minecraftobserver/minecraftobserver_test.go
Normal file
127
plugin/minecraftobserver/minecraftobserver_test.go
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
package minecraftobserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_singleServerScan(t *testing.T) {
|
||||||
|
initErr := initializeDB("data/minecraftobserver/" + dbPath)
|
||||||
|
if initErr != nil {
|
||||||
|
t.Fatalf("initializeDB() error = %v", initErr)
|
||||||
|
}
|
||||||
|
if dbInstance == nil {
|
||||||
|
t.Fatalf("initializeDB() got = %v, want not nil", dbInstance)
|
||||||
|
}
|
||||||
|
t.Run("状态变更", func(t *testing.T) {
|
||||||
|
cleanTestData(t)
|
||||||
|
newSS1 := &serverStatus{
|
||||||
|
ServerAddr: "cn.nekoland.top",
|
||||||
|
Description: "测试服务器",
|
||||||
|
Players: "1/20",
|
||||||
|
Version: "1.16.5",
|
||||||
|
FaviconMD5: "",
|
||||||
|
}
|
||||||
|
err := dbInstance.updateServerStatus(newSS1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("upsertServerStatus() error = %v", err)
|
||||||
|
}
|
||||||
|
err = dbInstance.newSubscribe("cn.nekoland.top", 123456, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("getServerSubscribeByTargetGroupAndAddr() error = %v", err)
|
||||||
|
}
|
||||||
|
changed, msg, err := singleServerScan(newSS1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("singleServerScan() error = %v", err)
|
||||||
|
}
|
||||||
|
if !changed {
|
||||||
|
t.Fatalf("singleServerScan() got = %v, want true", changed)
|
||||||
|
}
|
||||||
|
if len(msg) == 0 {
|
||||||
|
t.Fatalf("singleServerScan() got = %v, want not empty", msg)
|
||||||
|
}
|
||||||
|
fmt.Printf("msg: %v\n", msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("可达 -> 不可达", func(t *testing.T) {
|
||||||
|
cleanTestData(t)
|
||||||
|
newSS1 := &serverStatus{
|
||||||
|
ServerAddr: "dx.123213213123123.net",
|
||||||
|
Description: "测试服务器",
|
||||||
|
Players: "1/20",
|
||||||
|
Version: "1.16.5",
|
||||||
|
FaviconMD5: "",
|
||||||
|
PingDelay: 123,
|
||||||
|
}
|
||||||
|
err := dbInstance.updateServerStatus(newSS1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("upsertServerStatus() error = %v", err)
|
||||||
|
}
|
||||||
|
err = dbInstance.newSubscribe("dx.123213213123123.net", 123456, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("getServerSubscribeByTargetGroupAndAddr() error = %v", err)
|
||||||
|
}
|
||||||
|
var msg message.Message
|
||||||
|
changed, _, err := singleServerScan(newSS1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("singleServerScan() error = %v", err)
|
||||||
|
}
|
||||||
|
if changed {
|
||||||
|
t.Fatalf("singleServerScan() got = %v, want false", changed)
|
||||||
|
}
|
||||||
|
// 第二次
|
||||||
|
changed, _, err = singleServerScan(newSS1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("singleServerScan() error = %v", err)
|
||||||
|
}
|
||||||
|
if changed {
|
||||||
|
t.Fatalf("singleServerScan() got = %v, want false", changed)
|
||||||
|
}
|
||||||
|
// 第三次
|
||||||
|
changed, msg, err = singleServerScan(newSS1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("singleServerScan() error = %v", err)
|
||||||
|
}
|
||||||
|
if !changed {
|
||||||
|
t.Fatalf("singleServerScan() got = %v, want true", changed)
|
||||||
|
}
|
||||||
|
if len(msg) == 0 {
|
||||||
|
t.Fatalf("singleServerScan() got = %v, want not empty", msg)
|
||||||
|
}
|
||||||
|
fmt.Printf("msg: %v\n", msg)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("不可达 -> 可达", func(t *testing.T) {
|
||||||
|
cleanTestData(t)
|
||||||
|
newSS1 := &serverStatus{
|
||||||
|
ServerAddr: "cn.nekoland.top",
|
||||||
|
Description: "测试服务器",
|
||||||
|
Players: "1/20",
|
||||||
|
Version: "1.16.5",
|
||||||
|
FaviconMD5: "",
|
||||||
|
PingDelay: pingDelayUnreachable,
|
||||||
|
}
|
||||||
|
err := dbInstance.updateServerStatus(newSS1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("upsertServerStatus() error = %v", err)
|
||||||
|
}
|
||||||
|
err = dbInstance.newSubscribe("cn.nekoland.top", 123456, 1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("newSubscribe() error = %v", err)
|
||||||
|
}
|
||||||
|
changed, msg, err := singleServerScan(newSS1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("singleServerScan() error = %v", err)
|
||||||
|
}
|
||||||
|
if !changed {
|
||||||
|
t.Fatalf("singleServerScan() got = %v, want true", changed)
|
||||||
|
}
|
||||||
|
if len(msg) == 0 {
|
||||||
|
t.Fatalf("singleServerScan() got = %v, want not empty", msg)
|
||||||
|
}
|
||||||
|
fmt.Printf("msg: %v\n", msg)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
253
plugin/minecraftobserver/model.go
Normal file
253
plugin/minecraftobserver/model.go
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
package minecraftobserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Tnze/go-mc/chat"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
// DB Schema
|
||||||
|
|
||||||
|
// serverStatus 服务器状态
|
||||||
|
type serverStatus struct {
|
||||||
|
// ID 主键
|
||||||
|
ID int64 `json:"id" gorm:"column:id;primary_key:pk_id;auto_increment;default:0"`
|
||||||
|
// 服务器地址
|
||||||
|
ServerAddr string `json:"server_addr" gorm:"column:server_addr;default:'';unique_index:udx_server_addr"`
|
||||||
|
// 服务器描述
|
||||||
|
Description string `json:"description" gorm:"column:description;default:null;type:CLOB"`
|
||||||
|
// 在线玩家
|
||||||
|
Players string `json:"players" gorm:"column:players;default:''"`
|
||||||
|
// 版本
|
||||||
|
Version string `json:"version" gorm:"column:version;default:''"`
|
||||||
|
// FaviconMD5 Favicon MD5
|
||||||
|
FaviconMD5 string `json:"favicon_md5" gorm:"column:favicon_md5;default:''"`
|
||||||
|
// FaviconRaw 原始数据
|
||||||
|
FaviconRaw icon `json:"favicon_raw" gorm:"column:favicon_raw;default:null;type:CLOB"`
|
||||||
|
// 延迟,不可达时为-1
|
||||||
|
PingDelay int64 `json:"ping_delay" gorm:"column:ping_delay;default:-1"`
|
||||||
|
// 更新时间
|
||||||
|
LastUpdate int64 `json:"last_update" gorm:"column:last_update;default:0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// serverSubscribe 订阅信息
|
||||||
|
type serverSubscribe struct {
|
||||||
|
// ID 主键
|
||||||
|
ID int64 `json:"id" gorm:"column:id;primary_key:pk_id;auto_increment;default:0"`
|
||||||
|
// 服务器地址
|
||||||
|
ServerAddr string `json:"server_addr" gorm:"column:server_addr;default:'';unique_index:udx_ait"`
|
||||||
|
// 推送目标id
|
||||||
|
TargetID int64 `json:"target_id" gorm:"column:target_id;default:0;unique_index:udx_ait"`
|
||||||
|
// 类型 1:群组 2:个人
|
||||||
|
TargetType int64 `json:"target_type" gorm:"column:target_type;default:0;unique_index:udx_ait"`
|
||||||
|
// 更新时间
|
||||||
|
LastUpdate int64 `json:"last_update" gorm:"column:last_update;default:0"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// pingDelayUnreachable 不可达
|
||||||
|
pingDelayUnreachable = -1
|
||||||
|
)
|
||||||
|
|
||||||
|
// isServerStatusSpecChanged 检查是否有状态变化
|
||||||
|
func (ss *serverStatus) isServerStatusSpecChanged(newStatus *serverStatus) (res bool) {
|
||||||
|
res = false
|
||||||
|
if ss == nil || newStatus == nil {
|
||||||
|
res = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 描述变化、版本变化、Favicon变化
|
||||||
|
if ss.Description != newStatus.Description || ss.Version != newStatus.Version || ss.FaviconMD5 != newStatus.FaviconMD5 {
|
||||||
|
res = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 状态由不可达变为可达 or 反之
|
||||||
|
if (ss.PingDelay == pingDelayUnreachable && newStatus.PingDelay != pingDelayUnreachable) ||
|
||||||
|
(ss.PingDelay != pingDelayUnreachable && newStatus.PingDelay == pingDelayUnreachable) {
|
||||||
|
res = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// deepCopy 深拷贝
|
||||||
|
func (ss *serverStatus) deepCopy() (dst *serverStatus) {
|
||||||
|
if ss == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dst = &serverStatus{}
|
||||||
|
*dst = *ss
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateServerStatusMsg 生成服务器状态消息
|
||||||
|
func (ss *serverStatus) generateServerStatusMsg() (msg string, iconBase64 string) {
|
||||||
|
var msgBuilder strings.Builder
|
||||||
|
if ss == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msgBuilder.WriteString(ss.Description)
|
||||||
|
msgBuilder.WriteString("\n")
|
||||||
|
msgBuilder.WriteString("服务器地址:")
|
||||||
|
msgBuilder.WriteString(ss.ServerAddr)
|
||||||
|
msgBuilder.WriteString("\n")
|
||||||
|
// 版本
|
||||||
|
msgBuilder.WriteString("版本:")
|
||||||
|
msgBuilder.WriteString(ss.Version)
|
||||||
|
msgBuilder.WriteString("\n")
|
||||||
|
// Ping
|
||||||
|
if ss.PingDelay < 0 {
|
||||||
|
msgBuilder.WriteString("Ping延迟:超时\n")
|
||||||
|
} else {
|
||||||
|
msgBuilder.WriteString("Ping延迟:")
|
||||||
|
msgBuilder.WriteString(fmt.Sprintf("%d 毫秒\n", ss.PingDelay))
|
||||||
|
msgBuilder.WriteString("在线人数:")
|
||||||
|
msgBuilder.WriteString(ss.Players)
|
||||||
|
}
|
||||||
|
// 图标
|
||||||
|
if ss.FaviconRaw != "" && ss.FaviconRaw.checkPNG() {
|
||||||
|
iconBase64 = ss.FaviconRaw.toBase64String()
|
||||||
|
}
|
||||||
|
msg = msgBuilder.String()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DB Schema End
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
// Ping & List Response DTO
|
||||||
|
|
||||||
|
// serverPingAndListResp 服务器状态数据传输对象 From mc server response
|
||||||
|
type serverPingAndListResp struct {
|
||||||
|
Description chat.Message
|
||||||
|
Players struct {
|
||||||
|
Max int
|
||||||
|
Online int
|
||||||
|
Sample []struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Version struct {
|
||||||
|
Name string
|
||||||
|
Protocol int
|
||||||
|
}
|
||||||
|
Favicon icon
|
||||||
|
Delay time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// icon should be a PNG image that is Base64 encoded
|
||||||
|
// (without newlines: \n, new lines no longer work since 1.13)
|
||||||
|
// and prepended with "data:image/png;base64,".
|
||||||
|
type icon string
|
||||||
|
|
||||||
|
// func (i icon) toImage() (icon image.Image, err error) {
|
||||||
|
// const prefix = "data:image/png;base64,"
|
||||||
|
// if !strings.HasPrefix(string(i), prefix) {
|
||||||
|
// return nil, errors.Errorf("server icon should prepended with %s", prefix)
|
||||||
|
// }
|
||||||
|
// base64png := strings.TrimPrefix(string(i), prefix)
|
||||||
|
// r := base64.NewDecoder(base64.StdEncoding, strings.NewReader(base64png))
|
||||||
|
// icon, err = png.Decode(r)
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
|
// checkPNG 检查是否为PNG
|
||||||
|
func (i icon) checkPNG() bool {
|
||||||
|
const prefix = "data:image/png;base64,"
|
||||||
|
return strings.HasPrefix(string(i), prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toBase64String 转换为base64字符串
|
||||||
|
func (i icon) toBase64String() string {
|
||||||
|
return "base64://" + strings.TrimPrefix(string(i), "data:image/png;base64,")
|
||||||
|
}
|
||||||
|
|
||||||
|
// genServerSubscribeSchema 将DTO转换为DB Schema
|
||||||
|
func (dto *serverPingAndListResp) genServerSubscribeSchema(addr string, id int64) *serverStatus {
|
||||||
|
if dto == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
faviconMD5 := md5.Sum(helper.StringToBytes(string(dto.Favicon)))
|
||||||
|
return &serverStatus{
|
||||||
|
ID: id,
|
||||||
|
ServerAddr: addr,
|
||||||
|
Description: dto.Description.ClearString(),
|
||||||
|
Version: dto.Version.Name,
|
||||||
|
Players: fmt.Sprintf("%d/%d", dto.Players.Online, dto.Players.Max),
|
||||||
|
FaviconMD5: hex.EncodeToString(faviconMD5[:]),
|
||||||
|
FaviconRaw: dto.Favicon,
|
||||||
|
PingDelay: dto.Delay.Milliseconds(),
|
||||||
|
LastUpdate: time.Now().Unix(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping & List Response DTO End
|
||||||
|
// ====================
|
||||||
|
|
||||||
|
// ====================
|
||||||
|
// Biz Model
|
||||||
|
const (
|
||||||
|
logPrefix = "[minecraft observer] "
|
||||||
|
)
|
||||||
|
|
||||||
|
// warpTargetIDAndType 转换消息信息到订阅的目标ID和类型
|
||||||
|
func warpTargetIDAndType(groupID, userID int64) (int64, int64) {
|
||||||
|
// 订阅
|
||||||
|
var targetID int64
|
||||||
|
var targetType int64
|
||||||
|
if groupID == 0 {
|
||||||
|
targetType = targetTypeUser
|
||||||
|
targetID = userID
|
||||||
|
} else {
|
||||||
|
targetType = targetTypeGroup
|
||||||
|
targetID = groupID
|
||||||
|
}
|
||||||
|
return targetID, targetType
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatSubStatusChangeText 格式化状态变更文本
|
||||||
|
func formatSubStatusChangeText(oldStatus, newStatus *serverStatus) string {
|
||||||
|
var msgBuilder strings.Builder
|
||||||
|
if oldStatus == nil || newStatus == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// 变更通知
|
||||||
|
msgBuilder.WriteString("[Minecraft服务器状态变更通知]\n")
|
||||||
|
// 地址
|
||||||
|
msgBuilder.WriteString(fmt.Sprintf("服务器地址: %v\n", oldStatus.ServerAddr))
|
||||||
|
// 描述
|
||||||
|
if oldStatus.Description != newStatus.Description {
|
||||||
|
msgBuilder.WriteString("\n-----[描述变更]-----\n")
|
||||||
|
msgBuilder.WriteString(fmt.Sprintf("[旧]\n%v\n", oldStatus.Description))
|
||||||
|
msgBuilder.WriteString(fmt.Sprintf("[新]\n%v\n", newStatus.Description))
|
||||||
|
}
|
||||||
|
// 版本
|
||||||
|
if oldStatus.Version != newStatus.Version {
|
||||||
|
msgBuilder.WriteString("\n-----[版本变更]-----\n")
|
||||||
|
msgBuilder.WriteString(fmt.Sprintf("[旧]\n%v\n", oldStatus.Version))
|
||||||
|
msgBuilder.WriteString(fmt.Sprintf("[新]\n%v\n", newStatus.Version))
|
||||||
|
}
|
||||||
|
// 状态由不可达变为可达,反之
|
||||||
|
if oldStatus.PingDelay == pingDelayUnreachable && newStatus.PingDelay != pingDelayUnreachable {
|
||||||
|
msgBuilder.WriteString("\n-----[Ping延迟]-----\n")
|
||||||
|
msgBuilder.WriteString("[旧]\n超时\n")
|
||||||
|
msgBuilder.WriteString(fmt.Sprintf("[新]\n%v毫秒\n", newStatus.PingDelay))
|
||||||
|
}
|
||||||
|
if oldStatus.PingDelay != pingDelayUnreachable && newStatus.PingDelay == pingDelayUnreachable {
|
||||||
|
msgBuilder.WriteString("\n-----[Ping延迟]-----\n")
|
||||||
|
msgBuilder.WriteString(fmt.Sprintf("[旧]\n%v毫秒\n", oldStatus.PingDelay))
|
||||||
|
msgBuilder.WriteString("[新]\n超时\n")
|
||||||
|
}
|
||||||
|
return msgBuilder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Biz Model End
|
||||||
|
// ====================
|
||||||
63
plugin/minecraftobserver/ping.go
Normal file
63
plugin/minecraftobserver/ping.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package minecraftobserver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/RomiChan/syncx"
|
||||||
|
"github.com/Tnze/go-mc/bot"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// pingServerUnreachableCounter Ping服务器不可达计数器,防止bot本体网络抖动导致误报
|
||||||
|
pingServerUnreachableCounter = syncx.Map[string, pingServerUnreachableCounterDef]{}
|
||||||
|
// 计数器阈值
|
||||||
|
pingServerUnreachableCounterThreshold = int64(3)
|
||||||
|
// 时间阈值
|
||||||
|
pingServerUnreachableCounterTimeThreshold = time.Minute * 30
|
||||||
|
)
|
||||||
|
|
||||||
|
type pingServerUnreachableCounterDef struct {
|
||||||
|
count int64
|
||||||
|
firstUnreachableTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func addPingServerUnreachableCounter(addr string, ts time.Time) (int64, time.Time) {
|
||||||
|
key := addr
|
||||||
|
get, ok := pingServerUnreachableCounter.Load(key)
|
||||||
|
if !ok {
|
||||||
|
pingServerUnreachableCounter.Store(key, pingServerUnreachableCounterDef{
|
||||||
|
count: 1,
|
||||||
|
firstUnreachableTime: ts,
|
||||||
|
})
|
||||||
|
return 1, ts
|
||||||
|
}
|
||||||
|
// 存在则更新,时间戳不变
|
||||||
|
pingServerUnreachableCounter.Store(key, pingServerUnreachableCounterDef{
|
||||||
|
count: get.count + 1,
|
||||||
|
firstUnreachableTime: get.firstUnreachableTime,
|
||||||
|
})
|
||||||
|
return get.count + 1, get.firstUnreachableTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetPingServerUnreachableCounter(addr string) {
|
||||||
|
key := addr
|
||||||
|
pingServerUnreachableCounter.Delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getMinecraftServerStatus 获取Minecraft服务器状态
|
||||||
|
func getMinecraftServerStatus(addr string) (*serverPingAndListResp, error) {
|
||||||
|
var s serverPingAndListResp
|
||||||
|
resp, delay, err := bot.PingAndListTimeout(addr, time.Second*5)
|
||||||
|
if err != nil {
|
||||||
|
// logrus.Errorln(logPrefix+"PingAndList error: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(resp, &s)
|
||||||
|
if err != nil {
|
||||||
|
// logrus.Errorln(logPrefix+"Parse json response fail: ", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.Delay = delay
|
||||||
|
return &s, nil
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user