mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 22:00:11 +08:00
Compare commits
403 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 | ||
|
|
a248bb1420 | ||
|
|
95451f96d8 | ||
|
|
f3a841fc60 | ||
|
|
e4cfcef05b | ||
|
|
be26b052a6 | ||
|
|
c2b7ae31cc | ||
|
|
7d48916d2c | ||
|
|
a15c241bd6 | ||
|
|
5e91bd7a63 | ||
|
|
817c4fab61 | ||
|
|
fbadd8924f | ||
|
|
c008214be4 | ||
|
|
54471d16e4 | ||
|
|
6f7d4beb17 | ||
|
|
2cee275771 | ||
|
|
9de8092416 | ||
|
|
3cffc36dec | ||
|
|
7d5c770398 | ||
|
|
13ef54ef62 | ||
|
|
6ec3dff78a | ||
|
|
158baea605 | ||
|
|
e861b66ace | ||
|
|
3866ff8a46 | ||
|
|
863f99cb05 | ||
|
|
badd65a207 | ||
|
|
ff62723e91 | ||
|
|
7b45374310 | ||
|
|
3da55c4b75 | ||
|
|
a7d2a31bb8 | ||
|
|
074e77dfa2 | ||
|
|
ac909f95db | ||
|
|
4fd923c731 | ||
|
|
4b771f2809 | ||
|
|
89a5b68601 | ||
|
|
adbcb3956d | ||
|
|
293859460b | ||
|
|
c8594cfc54 | ||
|
|
31b70179f9 | ||
|
|
5d2898bc53 | ||
|
|
47f176a56e | ||
|
|
fa02189fad | ||
|
|
de558dc87b | ||
|
|
c9939d145b | ||
|
|
852c5f2f35 | ||
|
|
1c0f8ffadb | ||
|
|
2a4aa39bab | ||
|
|
26fcb5aad5 | ||
|
|
9119ded754 | ||
|
|
f6ef326495 | ||
|
|
4ffa18c511 | ||
|
|
2710074f00 | ||
|
|
0afe577b1b | ||
|
|
7329426fa4 | ||
|
|
97a647a620 | ||
|
|
61501d8ed9 | ||
|
|
289e74a619 | ||
|
|
18f77165ec | ||
|
|
7a3589e26d | ||
|
|
ca12560d29 | ||
|
|
c70766a989 | ||
|
|
b637fe18e9 | ||
|
|
81e255eb3a | ||
|
|
3b3b17aa33 | ||
|
|
4d7b7835e8 | ||
|
|
180f7564f3 | ||
|
|
835ba2617f | ||
|
|
286caaca8c | ||
|
|
445d82b090 | ||
|
|
487cd4db20 | ||
|
|
07122bbbf7 | ||
|
|
018f6c4008 | ||
|
|
fdb291d1d7 | ||
|
|
dc0d7c4151 | ||
|
|
e55c1fbd3d | ||
|
|
8c1f4e2d2f | ||
|
|
502693e222 | ||
|
|
23e567f2b1 | ||
|
|
a5a24e748e | ||
|
|
6210ed9496 | ||
|
|
a29b116f0d | ||
|
|
3faabc4fd8 | ||
|
|
7c47a55d74 | ||
|
|
94efc8a1af | ||
|
|
cda583e7b6 | ||
|
|
e62c86a740 | ||
|
|
a9dfbdb54b | ||
|
|
8fa928d37f | ||
|
|
d832f9aaea | ||
|
|
5e047cafb0 | ||
|
|
baaef6cb7f | ||
|
|
d1b83f4764 | ||
|
|
78c64ac310 | ||
|
|
0a45fafb1b | ||
|
|
509c462c8d | ||
|
|
61b70a86de | ||
|
|
8d0279fec7 | ||
|
|
8e5fbbae15 | ||
|
|
995f37ce17 | ||
|
|
97950bebcc | ||
|
|
a0e9816ea4 | ||
|
|
15df65af7b | ||
|
|
1351a7edbe | ||
|
|
4f193f4251 | ||
|
|
71109f23fb | ||
|
|
ec00251972 | ||
|
|
79f1beac53 | ||
|
|
1a20ecb634 | ||
|
|
3225a2d6c7 | ||
|
|
0e3c025b80 | ||
|
|
2a820cfc54 | ||
|
|
d57d7a7abf | ||
|
|
ad9a74e159 | ||
|
|
4c0c06ab1b | ||
|
|
c287ae7d92 | ||
|
|
c8d846d747 | ||
|
|
ff898b86ed | ||
|
|
a4094cca64 | ||
|
|
803c027264 | ||
|
|
63784b4ed0 | ||
|
|
1971e2274a | ||
|
|
68fee3532b | ||
|
|
c29b1238c2 | ||
|
|
a72bec15a9 | ||
|
|
f4e9d3e4dd | ||
|
|
6e54d214f0 | ||
|
|
f54b9adf84 | ||
|
|
cd91373215 | ||
|
|
a497609340 | ||
|
|
75d91b3d45 | ||
|
|
06fd754cc5 | ||
|
|
8e8c51a263 | ||
|
|
33580ab947 | ||
|
|
9531347292 | ||
|
|
717446ae6c | ||
|
|
786b5055c2 | ||
|
|
9eadefba73 | ||
|
|
730ab28d92 | ||
|
|
83b46dd071 | ||
|
|
a7d07ecf60 | ||
|
|
4334f4dd22 | ||
|
|
879948a5c4 | ||
|
|
b09025a330 | ||
|
|
d95760a534 | ||
|
|
a5130cd7f6 | ||
|
|
bab5c4c308 | ||
|
|
e0891200af | ||
|
|
b050b5d5b5 | ||
|
|
2ff164c2df | ||
|
|
cab917d054 | ||
|
|
dfe6d347a5 | ||
|
|
5c6af1af61 | ||
|
|
d7cdfb1544 | ||
|
|
cf0e87ab9a | ||
|
|
0a33224571 | ||
|
|
dd878f7dfe | ||
|
|
ac52c9cfca | ||
|
|
ece68dae9b | ||
|
|
6c20f22548 | ||
|
|
6f2c9f7fc0 | ||
|
|
b8858f0acd | ||
|
|
9c65383a7c | ||
|
|
a006b30392 | ||
|
|
54c67e30f4 | ||
|
|
61168adb2e |
45
.github/workflows/gomod2nix.yml
vendored
Normal file
45
.github/workflows/gomod2nix.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
name: 自动更新 nix 依赖
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'go.mod'
|
||||
- 'go.sum'
|
||||
- '.github/workflows/gomod2nix.yml'
|
||||
jobs:
|
||||
gomod2nix:
|
||||
name: gomod2nix update
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up nix
|
||||
uses: cachix/install-nix-action@v27
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: "1.25"
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: gomod2nix update
|
||||
run: |
|
||||
nix run github:nix-community/gomod2nix
|
||||
- name: Commit back
|
||||
if: ${{ !github.head_ref }}
|
||||
continue-on-error: true
|
||||
run: |
|
||||
git config --local user.name 'github-actions[bot]'
|
||||
git config --local user.email '41898282+github-actions[bot]@users.noreply.github.com'
|
||||
git add --all
|
||||
git commit -m "chore: bump deps"
|
||||
- name: Create Pull Request
|
||||
if: ${{ !github.head_ref }}
|
||||
continue-on-error: true
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
delete-branch: true
|
||||
branch-suffix: short-commit-hash
|
||||
8
.github/workflows/nightly.yml
vendored
8
.github/workflows/nightly.yml
vendored
@ -22,15 +22,20 @@ jobs:
|
||||
goarch: arm
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
- goos: windows
|
||||
goarch: 386
|
||||
fail-fast: true
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go environment
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: '1.20'
|
||||
go-version: '1.25'
|
||||
- name: Cache downloaded module
|
||||
uses: actions/cache@master
|
||||
continue-on-error: true
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
@ -42,6 +47,7 @@ jobs:
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
IS_PR: ${{ !!github.head_ref }}
|
||||
run: |
|
||||
GOOS= GOARCH= go generate ./...
|
||||
if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi
|
||||
if $IS_PR ; then echo $PR_PROMPT; fi
|
||||
export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX"
|
||||
|
||||
14
.github/workflows/pull.yml
vendored
14
.github/workflows/pull.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
uses: superbrothers/close-pull-request@v3
|
||||
with:
|
||||
# Optional. Post a issue comment just before closing a pull request.
|
||||
comment: "非法PR. 请`fork`后修改自己的仓库, 而不是向主仓库提交更改. 如果您确信您的PR是为了给主仓库新增功能或修复bug, 请更改默认PR标题."
|
||||
comment: "非法PR. 请`fork`后修改自己的仓库, 而不是向主仓库提交更改. 如果您确信您的PR是为了给主仓库新增功能或修复bug, 请更改默认PR标题. **注意**: 如果您再次触发本提示, 则有可能导致账号被封禁."
|
||||
|
||||
golangci:
|
||||
name: lint
|
||||
@ -26,10 +26,18 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: '1.20'
|
||||
go-version: '1.24'
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Tidy Modules
|
||||
run: |
|
||||
go mod tidy
|
||||
go generate main.go
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@master
|
||||
|
||||
9
.github/workflows/push.yml
vendored
9
.github/workflows/push.yml
vendored
@ -8,10 +8,17 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: '1.20'
|
||||
go-version: '1.24'
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Tidy Modules
|
||||
run: |
|
||||
go mod tidy
|
||||
go generate main.go
|
||||
|
||||
- name: Run Lint
|
||||
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
|
||||
uses: actions/setup-go@master
|
||||
with:
|
||||
go-version: '1.20'
|
||||
go-version: '1.25'
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@master
|
||||
with:
|
||||
version: latest
|
||||
version: "~> v2"
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -8,3 +8,5 @@ nohup.out
|
||||
zerobot
|
||||
ZeroBot-Plugin*
|
||||
*.syso
|
||||
/.direnv
|
||||
/result
|
||||
@ -1,6 +1,5 @@
|
||||
linters-settings:
|
||||
errcheck:
|
||||
ignore: fmt:.*
|
||||
ignoretests: true
|
||||
|
||||
goimports:
|
||||
@ -21,7 +20,7 @@ linters:
|
||||
#- depguard
|
||||
- dogsled
|
||||
- errcheck
|
||||
- exportloopref
|
||||
#- exportloopref
|
||||
- exhaustive
|
||||
#- funlen
|
||||
#- goconst
|
||||
@ -57,21 +56,20 @@ run:
|
||||
deadline: 5m
|
||||
issues-exit-code: 1
|
||||
tests: false
|
||||
skip-dirs:
|
||||
- order
|
||||
go: '1.20'
|
||||
go: '1.24'
|
||||
|
||||
# output configuration options
|
||||
output:
|
||||
format: "colored-line-number"
|
||||
formats:
|
||||
- format: "colored-line-number"
|
||||
print-issued-lines: true
|
||||
print-linter-name: true
|
||||
uniq-by-line: true
|
||||
|
||||
issues:
|
||||
# Fix found issues (if it's supported by the linter)
|
||||
fix: true
|
||||
exclude-use-default: false
|
||||
uniq-by-line: true
|
||||
exclude:
|
||||
- "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\+.*'
|
||||
|
||||
@ -4,6 +4,7 @@ env:
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
- go generate ./...
|
||||
- go install github.com/tc-hib/go-winres@latest
|
||||
- go-winres make
|
||||
builds:
|
||||
@ -33,7 +34,6 @@ builds:
|
||||
goos:
|
||||
- windows
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
mod_timestamp: "{{ .CommitTimestamp }}"
|
||||
flags:
|
||||
@ -63,7 +63,7 @@ archives:
|
||||
name_template: "zbp_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
formats: zip
|
||||
|
||||
nfpms:
|
||||
- license: AGPL 3.0
|
||||
|
||||
556
README.md
556
README.md
@ -1,5 +1,6 @@
|
||||
<div align="center">
|
||||
<img src=".github/hua_nobg_512.gif" alt="椛" width = "400">
|
||||
<img src=".github/hua_nobg_512.gif" alt="椛" width = "256">
|
||||
<img src="https://github.com/FloatTech/ZeroBot-Plugin/assets/41315874/93fb795d-e519-45a6-a654-076fd6ac54ae" alt="zbp-uwu" width = "400">
|
||||
<br>
|
||||
|
||||
<h1>ZeroBot-Plugin</h1>
|
||||
@ -19,7 +20,7 @@
|
||||
|
||||
[](https://goreportcard.com/badge/github.com/FloatTech/ZeroBot-Plugin)
|
||||
[](https://t.me/zerobotplugin)
|
||||
[](https://github.com/wdvxdr1123/ZeroBot)
|
||||
[](https://github.com/wdvxdr1123/ZeroBot)
|
||||
|
||||
|
||||
|
||||
@ -29,11 +30,12 @@
|
||||
[](https://t.me/zerobotplugin)
|
||||
|
||||
本项目符合 [OneBot](https://github.com/howmanybots/onebot) 标准,可基于以下项目与机器人框架/平台进行交互
|
||||
| 项目地址 | 平台 | 核心作者 |
|
||||
| --- | --- | --- |
|
||||
| [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) | [MiraiGo](https://github.com/Mrs4s/MiraiGo) | Mrs4s |
|
||||
| [onebot-kotlin](https://github.com/yyuueexxiinngg/onebot-kotlin) | [Mirai](https://github.com/mamoe/mirai) | yyuueexxiinngg |
|
||||
| [oicq/http-api](https://github.com/takayama-lily/oicq/tree/master/http-api) | [OICQ](https://github.com/takayama-lily/oicq) | takayama |
|
||||
| 项目地址 | 平台 | 核心作者 | 备注 |
|
||||
| :---: | :---: | :---: | :---: |
|
||||
| [LLOneBot](https://github.com/LLOneBot/LLOneBot) | NTQQ | linyuchen | 目前推荐使用 |
|
||||
| [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) | [MiraiGo](https://github.com/Mrs4s/MiraiGo) | Mrs4s | 因签名原因不再维护 |
|
||||
| [onebot-kotlin](https://github.com/yyuueexxiinngg/onebot-kotlin) | [Mirai](https://github.com/mamoe/mirai) | yyuueexxiinngg | 不再积极维护 |
|
||||
| [oicq/http-api](https://github.com/takayama-lily/oicq/tree/master/http-api) | [OICQ](https://github.com/takayama-lily/oicq) | takayama | 已归档不再维护 |
|
||||
|
||||
[](https://seladb.github.io/StarTrack-js/#/preload?r=FloatTech,ZeroBot-Plugin)
|
||||
|
||||
@ -41,8 +43,6 @@
|
||||
|
||||
> 专为[后 go-cqhttp 时代](https://github.com/Mrs4s/go-cqhttp/issues/2471)开发迁移的`类zbp`新机器人现已出炉,基于官方api,稳定不风控: [NanoBot-Plugin](https://github.com/FloatTech/NanoBot-Plugin)
|
||||
|
||||
> 如果您不知道什么是 [OneBot](https://github.com/howmanybots/onebot) 或不希望运行多个程序,还可以直接前往 [gocqzbp](https://github.com/FloatTech/gocqzbp) 的 [Release](https://github.com/FloatTech/gocqzbp/releases) 页面下载单一可执行文件或前往 [Packages](https://github.com/FloatTech/gocqzbp/pkgs/container/gocqzbp) 页面使用`docker`,运行后按提示登录即可。
|
||||
|
||||
> 如果您对开发插件感兴趣,欢迎加入[ZeroBot-Plugin-Playground](https://github.com/FloatTech/ZeroBot-Plugin-Playground)
|
||||
|
||||
> webui持续开发中, 欢迎加入[ZeroBot-Plugin-Webui](https://github.com/FloatTech/ZeroBot-Plugin-Webui)
|
||||
@ -50,7 +50,7 @@
|
||||
## 命令行参数
|
||||
> `[]`代表是可选参数
|
||||
```bash
|
||||
zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w] [-c|s config.json] [-l latency] [-r ringlen] [-x max process time] [qq1 qq2 qq3 ...] [&]
|
||||
zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w] [-c|s config.json] [-l latency] [-r ringlen] [-x max process time] [-mirror] [qq1 qq2 qq3 ...] [&]
|
||||
```
|
||||
- **-h**: 显示帮助
|
||||
- **-m**: 不自动标记消息为已读
|
||||
@ -65,6 +65,7 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
|
||||
- **-l latency**: 全局处理延时 (ms)
|
||||
- **-r ringlen**: 接收消息环缓冲区大小,`0`为不设缓冲,并发处理
|
||||
- **-x max process time**: 最大处理时间 (min)
|
||||
- **-mirror**: 直接使用镜像懒加载数据站而不尝试访问源站
|
||||
- **qqs**: superusers 的 qq 号
|
||||
- **&**: 驻留在后台,必须放在最后,仅`Linux`下有效
|
||||
|
||||
@ -173,6 +174,16 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
|
||||
|
||||
- [x] 设置温度[正整数]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>聊天时长统计</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/chatcount"`
|
||||
|
||||
- [x] 查询水群@xxx
|
||||
|
||||
- [x] 查看水群排名
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>睡眠管理</summary>
|
||||
@ -181,6 +192,18 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
|
||||
|
||||
- [x] 早安 | 晚安
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>违禁词检测</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/antiabuse"
|
||||
`
|
||||
- [x] 添加违禁词
|
||||
|
||||
- [x] 删除违禁词
|
||||
|
||||
- [x] 查看违禁词
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>ATRI</summary>
|
||||
@ -243,6 +266,10 @@ zerobot [-h] [-m] [-n nickname] [-t token] [-u url] [-g url] [-p prefix] [-d|w]
|
||||
|
||||
- [x] 翻牌
|
||||
|
||||
- [x] 赞我
|
||||
|
||||
- [x] 群签到
|
||||
|
||||
- [x] [开启 | 关闭]入群验证
|
||||
|
||||
- [x] [开启 | 关闭]gist加群自动审批
|
||||
@ -263,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} 是当前群群名
|
||||
|
||||
</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>
|
||||
<summary>定时指令触发器</summary>
|
||||
@ -373,27 +414,15 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>ai绘图</summary>
|
||||
<summary>aiimage</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aipaint"`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiimage"`
|
||||
|
||||
- [x] [ ai绘图 | 生成色图 | 生成涩图 | ai画图 ] xxx
|
||||
|
||||
- [x] [ ai高级绘图 | 高级生成色图 | 高级生成涩图 | ai高级画图 ] xxx
|
||||
|
||||
- [x] [ 以图绘图 | 以图生图 | 以图画图 ] xxx [图片]|@xxx|[qq号]
|
||||
|
||||
- [x] 设置ai绘图配置 [server] [token]
|
||||
|
||||
- [x] 设置ai绘图撤回时间90s
|
||||
|
||||
- [x] 查看ai绘图配置
|
||||
|
||||
例: 设置ai绘图配置 http://91.216.169.75:5010 abc
|
||||
|
||||
参考服务器 http://91.217.139.190:5010, http://91.216.169.75:5010, http://185.80.202.180:5010
|
||||
|
||||
通过 http://91.217.139.190:5010/token 获取token
|
||||
- [x] 设置AI画图密钥xxx
|
||||
- [x] 设置AI画图接口地址https://api.siliconflow.cn/v1/images/generations
|
||||
- [x] 设置AI画图模型名Kwai-Kolors/Kolors
|
||||
- [x] 查看AI画图配置
|
||||
- [x] AI画图 [描述]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@ -411,6 +440,18 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [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>
|
||||
<summary>触发者撤回时也自动撤回</summary>
|
||||
@ -433,14 +474,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 用yyy解密xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百科</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu"`
|
||||
|
||||
- [x] 百度/百科/维基/wiki[xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>百度内容审核</summary>
|
||||
@ -538,7 +571,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
<details>
|
||||
<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
|
||||
|
||||
@ -546,7 +579,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
<details>
|
||||
<summary>b站动态、直播推送,需要配合job一起使用</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibilipush"`
|
||||
|
||||
- [x] 添加b站订阅[uid|name]
|
||||
|
||||
@ -570,16 +603,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 随机书评
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>藏头诗</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/cangtoushi"`
|
||||
|
||||
- [x] 藏头诗[xxx]
|
||||
|
||||
- [x] 藏尾诗[xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>选择困难症帮手</summary>
|
||||
@ -622,6 +645,17 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 磕cp大老师 雪乃
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>奇怪语言加解密</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/crypter"`
|
||||
|
||||
- [x] 齁语加密 [文本] 或 h加密 [文本]
|
||||
- [x] 齁语解密 [密文] 或 h解密 [密文]
|
||||
- [x] fumo加密 [文本]
|
||||
- [x] fumo解密 [文本]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>今日早报</summary>
|
||||
@ -678,20 +712,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 删签[gif签名]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>女装</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/dress"`
|
||||
|
||||
- [x] 女装
|
||||
|
||||
- [x] 男装
|
||||
|
||||
- [x] 随机女装
|
||||
|
||||
- [x] 随机男装
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>漂流瓶</summary>
|
||||
@ -710,6 +730,16 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] [emoji][emoji]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>颜文字抽象转写</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/emozi"`
|
||||
|
||||
- [x] 抽象转写[文段]
|
||||
- [x] 抽象还原[文段]
|
||||
- [x] 抽象登录[用户名]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>好友申请及群聊邀请事件处理</summary>
|
||||
@ -815,14 +845,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] 下载歌单[网易云歌单链接/ID]到[歌单名称]
|
||||
- [x] 解除绑定 [歌单名称]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>黑丝</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/heisi"`
|
||||
|
||||
- [x] 来点黑丝/白丝/jk/巨乳/足控/网红
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>一言</summary>
|
||||
@ -855,14 +877,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 百人一首之n
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>关键字搜图</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/image_finder"`
|
||||
|
||||
- [x] 来张 [xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>注入指令</summary>
|
||||
@ -881,24 +895,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 更新[屌|弔|吊]图
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>兽语加密(嗷呜~)</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/jiami"`
|
||||
|
||||
- [x] 兽语加密xxx
|
||||
|
||||
- [x] 兽语解密xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>小鸡词典</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/jikipedia"`
|
||||
|
||||
- [x] [查梗|小鸡词典][梗]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>日语听力学习材料</summary>
|
||||
@ -913,14 +909,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 日语歌曲 xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>绝绝子</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/juejuezi"`
|
||||
|
||||
- [x] 喝奶茶绝绝子 | 绝绝子吃饭
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>疯狂星期四</summary>
|
||||
@ -959,6 +947,24 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
来份萝莉
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>桑帛云 API</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolimi"`
|
||||
|
||||
- [x] 随机妹子
|
||||
|
||||
- [x] 随机绕口令
|
||||
|
||||
- [x] 颜值鉴定[图片]
|
||||
|
||||
- [x] 随机情话
|
||||
|
||||
- [x] 发病 嘉然
|
||||
|
||||
- [x] 让[嘉然|塔菲|东雪莲|懒羊羊|科比|孙笑川|陈泽|丁真|空|荧|派蒙|纳西妲|阿贝多|温迪|枫原万叶|钟离|荒泷一斗|八重神子|艾尔海森|提纳里|迪希雅|卡维|宵宫|莱依拉|赛诺|诺艾尔|托马|凝光|莫娜|北斗|神里绫华|雷电将军|芭芭拉|鹿野院平藏|五郎|迪奥娜|凯亚|安柏|班尼特|琴|柯莱|夜兰|妮露|辛焱|珐露珊|魈|香菱|达达利亚|砂糖|早柚|云堇|刻晴|丽莎|迪卢克|烟绯|重云|珊瑚宫心海|胡桃|可莉|流浪者|久岐忍|神里绫人|甘雨|戴因斯雷布|优菈|菲谢尔|行秋|白术|九条裟罗|雷泽|申鹤|迪娜泽黛|凯瑟琳|多莉|坎蒂丝|萍姥姥|罗莎莉亚|留云借风真君|绮良良|瑶瑶|七七|奥兹|米卡|夏洛蒂|埃洛伊|博士|女士|大慈树王|三月七|娜塔莎|希露瓦|虎克|克拉拉|丹恒|希儿|布洛妮娅|瓦尔特|杰帕德|佩拉|姬子|艾丝妲|白露|星|穹|桑博|伦纳德|停云|罗刹|卡芙卡|彦卿|史瓦罗|螺丝咕姆|阿兰|银狼|素裳|丹枢|黑塔|景元|帕姆|可可利亚|半夏|符玄|公输师傅|奥列格|青雀|大毫|青镞|费斯曼|绿芙蓉|镜流|信使|丽塔|失落迷迭|缭乱星棘|伊甸|伏特加女孩|狂热蓝调|莉莉娅|萝莎莉娅|八重樱|八重霞|卡莲|第六夜想曲|卡萝尔|姬子|极地战刃|布洛妮娅|次生银翼|理之律者|真理之律者|迷城骇兔|希儿|魇夜星渊|黑希儿|帕朵菲莉丝|天元骑英|幽兰黛尔|德丽莎|月下初拥|朔夜观星|暮光骑士|明日香|李素裳|格蕾修|梅比乌斯|渡鸦|人之律者|爱莉希雅|爱衣|天穹游侠|琪亚娜|空之律者|终焉之律者|薪炎之律者|云墨丹心|符华|识之律者|维尔薇|始源之律者|芽衣|雷之律者|苏莎娜|阿波尼亚|陆景和|莫弈|夏彦|左然]说我测尼玛
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>MagicPrompt-Stable-Diffusion吟唱提示</summary>
|
||||
@ -975,7 +981,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 钓鱼商店
|
||||
- [x] 购买xxx [数量]
|
||||
- [x] 出售xxx [数量]
|
||||
- [x] 出售[xxx [数量]|所有垃圾]
|
||||
- [x] 钓鱼背包
|
||||
- [x] 装备[xx竿|三叉戟|美西螈]
|
||||
- [x] 附魔[诱钓|海之眷顾]
|
||||
@ -1008,16 +1014,26 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</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>
|
||||
|
||||
- [x] 让[수아|미미르|아린|연화|유화|선배]说(韩语)
|
||||
|
||||
- [x] 让[派蒙|空|荧|阿贝多|枫原万叶|温迪|八重神子|纳西妲|钟离|诺艾尔|凝光|托马|北斗|莫娜|荒泷一斗|提纳里|芭芭拉|艾尔海森|雷电将军|赛诺|琴|班尼特|五郎|神里绫华|迪希雅|夜兰|辛焱|安柏|宵宫|云堇|妮露|烟绯|鹿野院平藏|凯亚|达达利亚|迪卢克|可莉|早柚|香菱|重云|刻晴|久岐忍|珊瑚宫心海|迪奥娜|戴因斯雷布|魈|神里绫人|丽莎|优菈|凯瑟琳|雷泽|菲谢尔|九条裟罗|甘雨|行秋|胡桃|迪娜泽黛|柯莱|申鹤|砂糖|萍姥姥|奥兹|罗莎莉亚|式大将|哲平|坎蒂丝|托克|留云借风真君|昆钧|塞琉斯|多莉|大肉丸|莱依拉|散兵|拉赫曼|杜拉夫|阿守|玛乔丽|纳比尔|海芭夏|九条镰治|阿娜耶|阿晃|阿扎尔|七七|博士|白术|埃洛伊|大慈树王|女士|丽塔|失落迷迭|缭乱星棘|伊甸|伏特加女孩|狂热蓝调|莉莉娅|萝莎莉娅|八重樱|八重霞|卡莲|第六夜想曲|卡萝尔|姬子|极地战刃|布洛妮娅|次生银翼|理之律者|迷城骇兔|希儿|魇夜星渊|黑希儿|帕朵菲莉丝|天元骑英|幽兰黛尔|德丽莎|月下初拥|朔夜观星|暮光骑士|明日香|李素裳|格蕾修|梅比乌斯|渡鸦|人之律者|爱莉希雅|爱衣|天穹游侠|琪亚娜|空之律者|薪炎之律者|云墨丹心|符华|识之律者|维尔薇|芽衣|雷之律者|阿波尼亚]说(中文)
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/movies"`
|
||||
|
||||
- [x] 今日电影
|
||||
- [x] 预售电影
|
||||
</details>
|
||||
<details>
|
||||
<summary>摸鱼</summary>
|
||||
@ -1062,6 +1078,10 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 酷狗点歌[xxx]
|
||||
|
||||
- [x] qq点歌[xxx]
|
||||
|
||||
- [x] 咪咕点歌[xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>本地涩图</summary>
|
||||
@ -1080,22 +1100,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- 注:刷新文件夹较慢,请耐心等待刷新完成,会提示“成功”。
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>抽wife</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativewife"`
|
||||
|
||||
- [x] 抽wife[@xxx]
|
||||
|
||||
- [x] 添加wife[名字][图片]
|
||||
|
||||
- [x] 删除wife[名字]
|
||||
|
||||
- [x] [让 | 不让]所有人均可添加wife
|
||||
|
||||
- 注:不同群添加后不会重叠
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>拼音首字母释义工具</summary>
|
||||
@ -1114,6 +1118,40 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 搜索日语语法 [xxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>牛牛大作战</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/niuniu" `
|
||||
|
||||
- [x] 打胶
|
||||
|
||||
- [x] 使用[道具名称]打胶
|
||||
|
||||
- [x] jj[@xxx]
|
||||
|
||||
- [x] 使用[道具名称]jj[@xxx]
|
||||
|
||||
- [x] 赎牛牛
|
||||
|
||||
- [x] 牛牛拍卖行
|
||||
|
||||
- [x] 出售牛牛
|
||||
|
||||
- [x] 牛牛商店
|
||||
|
||||
- [x] 牛牛背包
|
||||
|
||||
- [x] 注册牛牛
|
||||
|
||||
- [x] 注销牛牛
|
||||
|
||||
- [x] 牛子长度排行
|
||||
|
||||
- [x] 牛子深度排行
|
||||
|
||||
- [x] 查看我的牛牛
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>小说</summary>
|
||||
@ -1138,6 +1176,22 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 当图片属于非 neutral 类别时自动发送评价(默认禁用,启用输入 /启用 nsfwauto)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>抽wife</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/nwife"`
|
||||
|
||||
- [x] 抽wife[@xxx]
|
||||
|
||||
- [x] 添加wife[名字][图片]
|
||||
|
||||
- [x] 删除wife[名字]
|
||||
|
||||
- [x] [让 | 不让]所有人均可添加wife
|
||||
|
||||
- 注:不同群添加后不会重叠
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>浅草寺求签</summary>
|
||||
@ -1148,6 +1202,14 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 解签
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>抽扑克</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/poker"`
|
||||
|
||||
- [x] 抽扑克牌
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>一群一天一夫一妻制群老婆</summary>
|
||||
@ -1180,18 +1242,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 重置花名册
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>权重查询</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/quan"`
|
||||
|
||||
- 来看看大家的账号分吧~据说越高越不容易封号哦
|
||||
|
||||
- [x] 权重查询+@xxx
|
||||
|
||||
- [x] 权重查询+QQ号(为空时匹配触发者QQ)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>qq空间表白墙</summary>
|
||||
@ -1226,6 +1276,25 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- 注:本插件来源于[tgbot](https://github.com/YukariChiba/tgbot/blob/main/modules/Reborn.py)
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>打劫</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/robbery"`
|
||||
|
||||
- [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>
|
||||
<summary>在线代码运行</summary>
|
||||
@ -1250,14 +1319,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 设置 saucenao api key [apikey]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>叔叔的AI二次元图片放大</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/scale"`
|
||||
|
||||
- [x] 放大图片[图片]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>签到得分</summary>
|
||||
@ -1354,14 +1415,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] >TL 你好
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>vits猫雷</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru"`
|
||||
|
||||
- [x] 让猫雷说[xxxx]
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>vtb语录</summary>
|
||||
@ -1374,33 +1427,23 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 更新vtb
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>vtb点歌</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtbmusic"`
|
||||
|
||||
- [x] vtb点歌
|
||||
|
||||
- [x] vtb随机点歌
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>钱包</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet"`
|
||||
|
||||
- [x] 查看我的钱包
|
||||
|
||||
- [x] 查看钱包排名
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>网易云音乐热评</summary>
|
||||
- [x] 设置硬币名称[ATRI币]
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun"`
|
||||
- [x] 管理钱包余额[+金额|-金额][@xxx]
|
||||
|
||||
- [x] 来份网易云热评
|
||||
- [x] 查看我的钱包|查看钱包余额[@xxx]
|
||||
|
||||
- [x] 钱包转账[金额][@xxx]
|
||||
|
||||
- 注:仅超级用户能"管理钱包余额",
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@ -1430,64 +1473,6 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
- [x] 每日特惠
|
||||
</details>
|
||||
<details>
|
||||
<summary>天气/拼音查询-名言</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben"`
|
||||
|
||||
- [x] xx天气
|
||||
|
||||
- [x] xx拼音
|
||||
|
||||
- [x] 每日情话/一言/鸡汤
|
||||
|
||||
- [x] 绕口令
|
||||
|
||||
</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>
|
||||
<summary>抽老婆</summary>
|
||||
|
||||
@ -1501,7 +1486,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/word_count"`
|
||||
|
||||
- [x] 热词 [群号] [消息数目]|热词 123456 1000
|
||||
- [x] 热词 [消息数目]|热词 1000
|
||||
|
||||
</details>
|
||||
<details>
|
||||
@ -1519,21 +1504,33 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>一些游戏王插件</summary>
|
||||
<summary>鬼东西</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygo"`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wtf"`
|
||||
|
||||
##### 白鸽API卡查
|
||||
- [x] 鬼东西列表
|
||||
|
||||
- [x] 查询鬼东西[序号][@xxx]
|
||||
|
||||
- 注:由于需要科学,默认注释。
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>游戏王白鸽API卡查</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ygocdb"`
|
||||
|
||||
###### `"github.com/FloatTech/ZeroBot-Plugin/plugin/ygo/ygocdb.go"`
|
||||
- [x] /ydp [xxx]
|
||||
- [x] /yds [xxx]
|
||||
- [x] /ydb [xxx]
|
||||
- 注:[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] 查卡价 [卡名] -r [稀有度 稀有度 ...]
|
||||
- [x] 查卡店 [卡名]
|
||||
@ -1558,20 +1555,71 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>鬼东西</summary>
|
||||
<summary>遇见API</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wtf"`
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/yujn"`
|
||||
|
||||
- [x] 鬼东西列表
|
||||
|
||||
- [x] 查询鬼东西[序号][@xxx]
|
||||
|
||||
- 注:由于需要科学,默认注释。
|
||||
- [x] 小姐姐视频
|
||||
- [x] 小姐姐视频2
|
||||
- [x] 黑丝视频
|
||||
- [x] 白丝视频
|
||||
- [x] 欲梦视频
|
||||
- [x] 甜妹视频
|
||||
- [x] 双倍快乐
|
||||
- [x] 纯情女高
|
||||
- [x] 萝莉视频
|
||||
- [x] 玉足视频
|
||||
- [x] 帅哥视频
|
||||
- [x] 热舞视频
|
||||
- [x] 吊带视频
|
||||
- [x] 汉服视频
|
||||
- [x] 极品狱卒
|
||||
- [x] 清纯视频
|
||||
- [x] 快手变装
|
||||
- [x] 抖音变装
|
||||
- [x] 萌娃视频
|
||||
- [x] 穿搭视频
|
||||
- [x] 完美身材
|
||||
- [x] 御姐撒娇
|
||||
- [x] 绿茶语音
|
||||
- [x] 怼人语音
|
||||
- [x] 随机骚话
|
||||
- [x] 随机污句子
|
||||
- [x] 随机美句
|
||||
- [x] 土味情话
|
||||
- [x] 让[lulu]说我测尼玛
|
||||
|
||||
</details>
|
||||
|
||||
### *低优先级*
|
||||
|
||||
<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>
|
||||
<summary>骂人</summary>
|
||||
|
||||
@ -1583,19 +1631,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>人工智能回复</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_reply"`
|
||||
|
||||
- [x] @Bot 任意文本(任意一句话回复)
|
||||
|
||||
- [x] 设置回复模式[青云客 | 小爱 | ChatGPT]
|
||||
|
||||
- [x] 设置 ChatGPT api key xxx
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>词典匹配回复</summary>
|
||||
<summary>词典匹配回复, 仅@触发</summary>
|
||||
|
||||
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus"`
|
||||
|
||||
@ -1616,8 +1652,7 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
|
||||
### 1. 使用稳定版/测试版 (推荐)
|
||||
|
||||
可以前往[Release](https://github.com/FloatTech/ZeroBot-Plugin/releases)页面下载对应系统版本可执行文件,编译时开启了全部插件。您还可以选择 [gocqzbp](https://github.com/FloatTech/gocqzbp) 的 [Release](https://github.com/FloatTech/gocqzbp/releases) 或 [Package](https://github.com/FloatTech/gocqzbp/pkgs/container/gocqzbp),它是 [Mrs4s/go-cqhttp](https://github.com/Mrs4s/go-cqhttp) 与本插件的合体。
|
||||
|
||||
可以前往[Release](https://github.com/FloatTech/ZeroBot-Plugin/releases)页面下载对应系统版本可执行文件,编译时开启了全部插件。
|
||||
### 2. 本地直接运行
|
||||
|
||||
1. 下载安装最新 [Go](https://studygolang.com/dl) 环境
|
||||
@ -1650,6 +1685,7 @@ go version
|
||||
go env -w GOPROXY=https://goproxy.cn,direct
|
||||
go env -w GO111MODULE=auto
|
||||
go mod tidy
|
||||
go generate 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() {
|
||||
debugMode := os.Getenv("DEBUG_MODE") == "1"
|
||||
stdin := windows.Handle(os.Stdin.Fd())
|
||||
|
||||
var mode uint32
|
||||
err := windows.GetConsoleMode(stdin, &mode)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
if debugMode {
|
||||
logrus.Warnf("调试模式下忽略控制台模式获取失败: %v", err)
|
||||
return // 调试模式下直接返回,跳过后续配置
|
||||
} else {
|
||||
panic(err) // 非调试模式下 panic
|
||||
}
|
||||
}
|
||||
|
||||
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 9b983625cad379783e3f9cda8026f9a7a6c38132
|
||||
Subproject commit 1b0abcd3fe4943fa3298885cf0311e8d94a02c0b
|
||||
26
default.nix
Normal file
26
default.nix
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
pkgs ? (
|
||||
let
|
||||
inherit (builtins) fetchTree fromJSON readFile;
|
||||
inherit ((fromJSON (readFile ./flake.lock)).nodes) nixpkgs gomod2nix;
|
||||
in
|
||||
import (fetchTree nixpkgs.locked) {
|
||||
overlays = [
|
||||
(import "${fetchTree gomod2nix.locked}/overlay.nix")
|
||||
];
|
||||
}
|
||||
),
|
||||
buildGoApplication ? pkgs.buildGoApplication,
|
||||
...
|
||||
}:
|
||||
buildGoApplication {
|
||||
pname = "ZeroBot-Plugin";
|
||||
version = "1.8.0";
|
||||
pwd = ./.;
|
||||
src = ./.;
|
||||
# spec go version manually bcs
|
||||
# https://github.com/nix-community/gomod2nix/blob/30e3c3a9ec4ac8453282ca7f67fca9e1da12c3e6/builder/default.nix#L130
|
||||
# do not work
|
||||
go = pkgs.go_1_20;
|
||||
modules = ./gomod2nix.toml;
|
||||
}
|
||||
102
flake.lock
Normal file
102
flake.lock
Normal file
@ -0,0 +1,102 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gomod2nix": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1742209644,
|
||||
"narHash": "sha256-jMy1XqXqD0/tJprEbUmKilTkvbDY/C0ZGSsJJH4TNCE=",
|
||||
"owner": "nix-community",
|
||||
"repo": "gomod2nix",
|
||||
"rev": "8f3534eb8f6c5c3fce799376dc3b91bae6b11884",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "gomod2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1745391562,
|
||||
"narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"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": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"gomod2nix": "gomod2nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-with-go_1_20": "nixpkgs-with-go_1_20"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
63
flake.nix
Normal file
63
flake.nix
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
description = "基于 ZeroBot 的 OneBot 插件";
|
||||
|
||||
inputs.nixpkgs-with-go_1_20.url = "github:NixOS/nixpkgs/33c51330782cb486764eb598d5907b43dc87b4c2";
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
inputs.gomod2nix.url = "github:nix-community/gomod2nix";
|
||||
inputs.gomod2nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.gomod2nix.inputs.flake-utils.follows = "flake-utils";
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
nixpkgs-with-go_1_20,
|
||||
flake-utils,
|
||||
gomod2nix,
|
||||
...
|
||||
} @ inputs: let
|
||||
allSystems = flake-utils.lib.allSystems;
|
||||
in (
|
||||
flake-utils.lib.eachSystem allSystems
|
||||
(system: let
|
||||
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.
|
||||
# This has no effect on other platforms.
|
||||
callPackage = pkgs.darwin.apple_sdk_11_0.callPackage or pkgs.callPackage;
|
||||
in {
|
||||
# doCheck will fail at write files
|
||||
packages = rec {
|
||||
ZeroBot-Plugin = (callPackage ./. (inputs
|
||||
// {
|
||||
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
|
||||
}))
|
||||
.overrideAttrs (_: {doCheck = false;});
|
||||
|
||||
default = ZeroBot-Plugin;
|
||||
|
||||
docker_builder = pkgs.dockerTools.buildLayeredImage {
|
||||
name = "ZeroBot-Plugin";
|
||||
tag = "latest";
|
||||
contents = [
|
||||
self.packages.${system}.ZeroBot-Plugin
|
||||
pkgs.cacert
|
||||
];
|
||||
};
|
||||
};
|
||||
devShells.default = callPackage ./shell.nix {
|
||||
inherit (gomod2nix.legacyPackages.${system}) mkGoEnv gomod2nix;
|
||||
};
|
||||
formatter = pkgs.alejandra;
|
||||
})
|
||||
);
|
||||
}
|
||||
147
go.mod
147
go.mod
@ -1,102 +1,107 @@
|
||||
module github.com/FloatTech/ZeroBot-Plugin
|
||||
|
||||
go 1.20
|
||||
go 1.24.2
|
||||
|
||||
require (
|
||||
github.com/Baidu-AIP/golang-sdk v1.1.1
|
||||
github.com/FloatTech/AnimeAPI v1.7.1-0.20231017135344-aefd1d56e900
|
||||
github.com/FloatTech/floatbox v0.0.0-20231107124407-e38535efa2a2
|
||||
github.com/FloatTech/gg v1.1.3-0.20230226151425-6ea91286ba08
|
||||
github.com/FloatTech/AnimeAPI v1.7.1-0.20251028071248-0c948e3db65c
|
||||
github.com/FloatTech/floatbox v0.0.0-20251002074805-f95cbc7edb31
|
||||
github.com/FloatTech/gg v1.1.3
|
||||
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef
|
||||
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9
|
||||
github.com/FloatTech/sqlite v1.6.3
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
||||
github.com/FloatTech/zbpctrl v1.6.0
|
||||
github.com/FloatTech/zbputils v1.7.1-0.20231107124514-083e678fbfe6
|
||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
||||
github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5
|
||||
github.com/antchfx/htmlquery v1.2.5
|
||||
github.com/FloatTech/rendercard v0.2.0
|
||||
github.com/FloatTech/sqlite v1.7.2
|
||||
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d
|
||||
github.com/FloatTech/zbpctrl v1.7.0
|
||||
github.com/FloatTech/zbputils v1.7.2-0.20251002080916-b554b7039913
|
||||
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7
|
||||
github.com/RomiChan/websocket v1.4.3-0.20251002072000-d3eb41798438
|
||||
github.com/Tnze/go-mc v1.20.2
|
||||
github.com/antchfx/htmlquery v1.3.4
|
||||
github.com/corona10/goimagehash v1.1.0
|
||||
github.com/davidscholberg/go-durationfmt v0.0.0-20170122144659-64843a2083d3
|
||||
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/deepinfra v0.0.0-20250924162107-cf156d49a0fa
|
||||
github.com/fumiama/go-base16384 v1.7.0
|
||||
github.com/fumiama/go-registry v0.2.6
|
||||
github.com/fumiama/go-onebot-agent v0.0.0-20250926145606-37ebfa6131c8
|
||||
github.com/fumiama/go-registry v0.2.7
|
||||
github.com/fumiama/gotracemoe v0.0.3
|
||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565
|
||||
github.com/fumiama/unibase2n v0.0.0-20221020155353-02876e777430
|
||||
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4
|
||||
github.com/fumiama/terasu v1.0.1
|
||||
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6
|
||||
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/jozsefsallai/gophersauce v1.0.1
|
||||
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5
|
||||
github.com/lithammer/fuzzysearch v1.1.5
|
||||
github.com/lithammer/fuzzysearch v1.1.8
|
||||
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/notnil/chess v1.9.0
|
||||
github.com/notnil/chess v1.10.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/quic-go/quic-go v0.38.1
|
||||
github.com/shirou/gopsutil/v3 v3.23.1
|
||||
github.com/shirou/gopsutil/v4 v4.25.11
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0
|
||||
github.com/wdvxdr1123/ZeroBot v1.7.5-0.20231009162356-57f71b9f5258
|
||||
gitlab.com/gomidi/midi/v2 v2.0.25
|
||||
golang.org/x/image v0.3.0
|
||||
golang.org/x/sys v0.8.0
|
||||
golang.org/x/text v0.9.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.2
|
||||
github.com/wdvxdr1123/ZeroBot v1.8.2-0.20251002074418-56567b7fc282
|
||||
gitlab.com/gomidi/midi/v2 v2.3.16
|
||||
golang.org/x/image v0.32.0
|
||||
golang.org/x/sys v0.38.0
|
||||
golang.org/x/text v0.30.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca // indirect
|
||||
github.com/antchfx/xpath v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.10.3 // indirect
|
||||
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
|
||||
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/antchfx/xpath v1.3.5 // 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/faiface/beep v1.1.0 // indirect
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0 // indirect
|
||||
github.com/fumiama/gofastTEA v0.0.10 // indirect
|
||||
github.com/fumiama/imgsz v0.0.2 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.0.4 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/hajimehoshi/oto v0.7.1 // indirect
|
||||
github.com/jfreymuth/oggvorbis v1.0.1 // indirect
|
||||
github.com/jfreymuth/vorbis v1.0.0 // indirect
|
||||
github.com/fumiama/go-simple-protobuf v0.2.0 // indirect
|
||||
github.com/fumiama/gofastTEA v0.1.3 // indirect
|
||||
github.com/fumiama/imgsz v0.0.4 // indirect
|
||||
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/gopxl/beep/v2 v2.1.1 // indirect
|
||||
github.com/jfreymuth/oggvorbis v1.0.5 // indirect
|
||||
github.com/jfreymuth/vorbis v1.0.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
|
||||
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // 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/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pkumza/numcn v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/tetratelabs/wazero v1.5.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
|
||||
golang.org/x/exp/shiny v0.0.0-20221126150942-6ab00d035af9 // indirect
|
||||
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/tools v0.9.1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
modernc.org/libc v1.21.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.4.0 // indirect
|
||||
modernc.org/sqlite v1.20.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||
github.com/tidwall/match v1.2.0 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.16 // indirect
|
||||
github.com/tklauser/numcpus v0.11.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.66.10 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.39.1 // indirect
|
||||
)
|
||||
|
||||
replace modernc.org/sqlite => github.com/fumiama/sqlite3 v1.20.0-with-win386
|
||||
replace modernc.org/sqlite => github.com/fumiama/sqlite3 v1.29.10-simp
|
||||
|
||||
replace github.com/remyoudompheng/bigfft => github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b
|
||||
replace modernc.org/libc => github.com/fumiama/libc v0.0.0-20240530081950-6f6d8586b5c5
|
||||
|
||||
438
go.sum
438
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/go.mod h1:bXnGw7xPeKt8aF7UCELKrV6UZ/46spItONK1RQBQj1Y=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/FloatTech/AnimeAPI v1.7.1-0.20231017135344-aefd1d56e900 h1:UPXoj+lMHFBulp/m+F7uHju0MXslFKQqEplDDz/nOiU=
|
||||
github.com/FloatTech/AnimeAPI v1.7.1-0.20231017135344-aefd1d56e900/go.mod h1:7Olb5U9q1oeayRZQTNBhXQNMf8QT4T9hccsn38IEt/U=
|
||||
github.com/FloatTech/floatbox v0.0.0-20231107124407-e38535efa2a2 h1:O4kptIzgYzNwZlBARZFv8EkA40yB6M5LGxxIF7NKLR8=
|
||||
github.com/FloatTech/floatbox v0.0.0-20231107124407-e38535efa2a2/go.mod h1:TeTlp+hTxpJti4JSdmUqzxGEr4wUBOVct9YWBepilpc=
|
||||
github.com/FloatTech/gg v1.1.3-0.20230226151425-6ea91286ba08 h1:dPLeoiTVSBlgls+66EB/UJ2e38BaASmBN5nANaycSBU=
|
||||
github.com/FloatTech/gg v1.1.3-0.20230226151425-6ea91286ba08/go.mod h1:uzPzAeT35egARdRuu+1oyjU3CmTwCceoq3Vvje7LpcI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/FloatTech/AnimeAPI v1.7.1-0.20251028071248-0c948e3db65c h1:fmvlRUzwoK6KdoRSW+XeTQ9myKHimd0pV6GbmRJLNRo=
|
||||
github.com/FloatTech/AnimeAPI v1.7.1-0.20251028071248-0c948e3db65c/go.mod h1:cuDd67B23xmICSmFBhWzXN51blod2BlM1liN9Ux0pSc=
|
||||
github.com/FloatTech/floatbox v0.0.0-20251002074805-f95cbc7edb31 h1:2K+/M64ixD1Pg5hr00Nbxr7GoWQOgahvpmp1pAMnrYc=
|
||||
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/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/go.mod h1:el5hGpj1C1bDRxcTXYRwEivDCr40zZeJpcrLrB1fajs=
|
||||
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9 h1:hffajvmQFfP68U6wUwHemPuuwCUoss+SEFfoLYwbGwE=
|
||||
github.com/FloatTech/rendercard v0.0.10-0.20230223064326-45d29fa4ede9/go.mod h1:NBFPhWae4hqVMeG8ELBBnUQkKce3nDjkljVn6PdiUNs=
|
||||
github.com/FloatTech/sqlite v1.6.3 h1:MQkqBNlkPuCoKQQgoNLuTL/2Ci3tBTFAnVYBdD0Wy4M=
|
||||
github.com/FloatTech/sqlite v1.6.3/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
|
||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||
github.com/FloatTech/zbpctrl v1.6.0 h1:BWg9aRR4bUCmNNKj6GPH0TmzFRWYImIi6rQcQTTYRs4=
|
||||
github.com/FloatTech/zbpctrl v1.6.0/go.mod h1:i3GGM5K4HiDsXzvmXQSYoH1QT3tsSaAHjRzHwKGsHG0=
|
||||
github.com/FloatTech/zbputils v1.7.1-0.20231107124514-083e678fbfe6 h1:EMdvLnt6i5dSFloLD1klOM8bdoFZqTtILcMCciOpcMo=
|
||||
github.com/FloatTech/zbputils v1.7.1-0.20231107124514-083e678fbfe6/go.mod h1:4oXgjQ6bGosAF4GbuL/keAhTrGWOV369X5X0ISFebmw=
|
||||
github.com/FloatTech/rendercard v0.2.0 h1:PBTZ2gCEy/dAEGSfWecrGTrWDYpiBJD1dVzNDDaOxh4=
|
||||
github.com/FloatTech/rendercard v0.2.0/go.mod h1:Sbojcy1t3NfFz7/WicZRmR/uKFxNMYkKF8qHx69dxY0=
|
||||
github.com/FloatTech/sqlite v1.7.2 h1:b8COegNLSzofzOyARsVwSbz9OOzWEa8IElsTlx1TBLw=
|
||||
github.com/FloatTech/sqlite v1.7.2/go.mod h1:/4tzfCGhrZnnjC1U8vcfwGQeF6eR649fhOsS3+Le0+s=
|
||||
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d h1:mUQ/c3wXKsUGa4Sg9DBy01APXKB68PmobhxOyaJI7lY=
|
||||
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||
github.com/FloatTech/zbpctrl v1.7.0 h1:Hxo6EIhJo+pHjcQP9QgIJgluaT1pHH99zkk3njqTNMo=
|
||||
github.com/FloatTech/zbpctrl v1.7.0/go.mod h1:xmM4dSwHA02Gei3ogCRiG+RTrw/7Z69PfrN5NYf8BPE=
|
||||
github.com/FloatTech/zbputils v1.7.2-0.20251002080916-b554b7039913 h1:uGexKAPL26sAWGemyHbfkjYyzFItMsbI8EREBLSZ/sU=
|
||||
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/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA=
|
||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/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.20220227141055-9b2c6168c9c5/go.mod h1:0UcFaCkhp6vZw6l5Dpq0Dp673CoF9GdvA8lTfst0GiU=
|
||||
github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca h1:kWzLcty5V2rzOqJM7Tp/MfSX0RMSI1x4IOLApEefYxA=
|
||||
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/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
|
||||
github.com/RomiChan/websocket v1.4.3-0.20251002072000-d3eb41798438 h1:I0bdwHZ+2DY45b39xPoTD2u+Z8zhvBuu9aZfjMZeiZM=
|
||||
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/go.mod h1:PRWNwWq0yifz6XDPZu48aSld8BWwBfr2JKB2bGWiEd4=
|
||||
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-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/antchfx/htmlquery v1.2.5 h1:1lXnx46/1wtv1E/kzmH8vrfMuUKYgkdDBA9pIdMJnk4=
|
||||
github.com/antchfx/htmlquery v1.2.5/go.mod h1:2MCVBzYVafPBmKbrmwB9F5xdd+IEgRY61ci2oOsOQVw=
|
||||
github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8=
|
||||
github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||
github.com/antchfx/htmlquery v1.3.4 h1:Isd0srPkni2iNTWCwVj/72t7uCphFeor5Q8nCzj1jdQ=
|
||||
github.com/antchfx/htmlquery v1.3.4/go.mod h1:K9os0BwIEmLAvTqaNSua8tXLWRWZpocZIH73OzWQbwM=
|
||||
github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
|
||||
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/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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -48,79 +54,79 @@ github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6RO
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
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/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/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/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c=
|
||||
github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4=
|
||||
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/bigfft v0.0.0-20211011143303-6e0bfa3c836b h1:Zt3pFQditAdWTHCOVkiloc9ZauBoWrb37guFV4iIRvE=
|
||||
github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/fumiama/ahsai v0.1.1 h1:/t5tdKRim0TK6YwgNFQfqtDOW7Y2tFBsmdUWt3JK+C0=
|
||||
github.com/fumiama/ahsai v0.1.1/go.mod h1:rBhHLgN2bygcqLpBi+XQa8B8Afn4UkPHQ5vvQibdbDQ=
|
||||
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/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/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||
github.com/fumiama/go-registry v0.2.6 h1:+vEeBUwa1+GC87ujW3Km42fi8O/H7QcpVJWu1iuGNh0=
|
||||
github.com/fumiama/go-registry v0.2.6/go.mod h1:HjYagPZXzR2xCCxaSQerqX7JRzC0yiv2kslDdBiTq/g=
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0 h1:rLzJgNqB6LHNDVMl81yyNt6ZKziWtVfu+ioF0edlEVw=
|
||||
github.com/fumiama/go-simple-protobuf v0.1.0/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4=
|
||||
github.com/fumiama/gofastTEA v0.0.10 h1:JJJ+brWD4kie+mmK2TkspDXKzqq0IjXm89aGYfoGhhQ=
|
||||
github.com/fumiama/gofastTEA v0.0.10/go.mod h1:RIdbYZyB4MbH6ZBlPymRaXn3cD6SedlCu5W/HHfMPBk=
|
||||
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/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/go.mod h1:5yYNapXq1tQMOZg9bOIVhQlZk9pQqpuFIO4DZLbsdy4=
|
||||
github.com/fumiama/gofastTEA v0.1.3 h1:fxOi2D66knV6QN170hb59YiqxPhjlgizvBw+o0OjxUA=
|
||||
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/go.mod h1:tyqahdUzHf0bQIAVY/GYmDWvYYe5ik1ZbhnGYh+zl40=
|
||||
github.com/fumiama/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak=
|
||||
github.com/fumiama/imgsz v0.0.2/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4=
|
||||
github.com/fumiama/imgsz v0.0.4 h1:Lsasu2hdSSFS+vnD+nvR1UkiRMK7hcpyYCC0FzgSMFI=
|
||||
github.com/fumiama/imgsz v0.0.4/go.mod h1:bISOQVTlw9sRytPwe8ir7tAaEmyz9hSNj9n8mXMBG0E=
|
||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565 h1:sQuR2+N5HurnvsZhiKdEg+Ig354TaqgCQRxd/0KgIOQ=
|
||||
github.com/fumiama/jieba v0.0.0-20221203025406-36c17a10b565/go.mod h1:UUEvyLTJ7yoOA/viKG4wEis4ERydM7+Ny6gZUWgkS80=
|
||||
github.com/fumiama/sqlite3 v1.20.0-with-win386 h1:ZR1AXGBEtkfq9GAXehOVcwn+aaCG8itrkgEsz4ggx5k=
|
||||
github.com/fumiama/sqlite3 v1.20.0-with-win386/go.mod h1:Os58MHwYCcYZCy2PGChBrQtBAw5/LS1ZZOkfc+C/I7s=
|
||||
github.com/fumiama/unibase2n v0.0.0-20221020155353-02876e777430 h1:XL4SnagpaVHYybnnj6whQxmt8Ps9/kaG6sCNn4X1GGA=
|
||||
github.com/fumiama/unibase2n v0.0.0-20221020155353-02876e777430/go.mod h1:lEaZsT4FRSqcjnQ5q8y+mkenkzR/r1D3BJmfdp0vqDg=
|
||||
github.com/gabriel-vasile/mimetype v1.0.4 h1:uBejfH8l3/2f+5vjl1e4xIaSyNEhRBZ5N/ij7ohpNd8=
|
||||
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/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/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/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA=
|
||||
github.com/fumiama/terasu v1.0.1 h1:WdP12r8xhRTyeCGWBtZx0QP0Eg5S3obJyS5MQVbBilE=
|
||||
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/go.mod h1:lEaZsT4FRSqcjnQ5q8y+mkenkzR/r1D3BJmfdp0vqDg=
|
||||
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/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
|
||||
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-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
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/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/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
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/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/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
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/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
|
||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk=
|
||||
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
|
||||
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
|
||||
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/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
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/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopxl/beep/v2 v2.1.1 h1:6FYIYMm2qPAdWkjX+7xwKrViS1x0Po5kDMdRkq8NVbU=
|
||||
github.com/gopxl/beep/v2 v2.1.1/go.mod h1:ZAm9TGQ9lvpoiFLd4zf5B1IuyxZhgRACMId1XJbaW0E=
|
||||
github.com/jfreymuth/oggvorbis v1.0.5 h1:u+Ck+R0eLSRhgq8WTmffYnrVtSztJcYrl588DM4e3kQ=
|
||||
github.com/jfreymuth/oggvorbis v1.0.5/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
||||
github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE=
|
||||
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
|
||||
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
@ -129,192 +135,220 @@ 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/jozsefsallai/gophersauce v1.0.1 h1:BA3ovtQRrAb1qYU9JoRLbDHpxnDunlNcEkEfhCvDDCM=
|
||||
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/go.mod h1:c9+VS9GaommgIOzNWb5ze4lYwfT8BZ2UDyGiuQTT7yc=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
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/lithammer/fuzzysearch v1.1.5 h1:Ag7aKU08wp0R9QCfF4GoGST9HbmAIeLP7xwMrOBEp1c=
|
||||
github.com/lithammer/fuzzysearch v1.1.5/go.mod h1:1R1LRNk7yKid1BaQkmuLQaHruxcC4HmAH30Dh61Ih1Q=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
||||
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
||||
github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:qSmEGTgjkESUX5kPMSGJ4pcBUtYVDdkNzMrjQyvRvp0=
|
||||
github.com/liuzl/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:x7SghIWwLVcJObXbjK7S2ENsT1cAcdJcPl7dRaSFog0=
|
||||
github.com/liuzl/da v0.0.0-20180704015230-14771aad5b1d h1:hTRDIpJ1FjS9ULJuEzu69n3qTgc18eI+ztw/pJv47hs=
|
||||
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/go.mod h1:7KaV9YIR92M1FpbczAcfYQ3UZ5ayT27pNtunDmXvLBo=
|
||||
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=
|
||||
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
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-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
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/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
|
||||
github.com/mmcdole/gofeed v1.3.0 h1:5yn+HeqlcvjMeAI4gu6T+crm7d0anY85+M+v6fIFNG4=
|
||||
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/go.mod h1:3p2SIcC8al1YMzGhAIoXD+r9olo/g/cdJgAD905gyNE=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
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/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/notnil/chess v1.9.0 h1:YMxR5kUVjtwcuFptGU0/3q7eG3MSHQNbg0VUekvRKV0=
|
||||
github.com/notnil/chess v1.9.0/go.mod h1:cRuJUIBFq9Xki05TWHJxHYkC+fFpq45IWwk94DdlCrA=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
github.com/notnil/chess v1.10.0 h1:RR3MgS9G6zZmJ+VPTJolyxdaIgxoUPyUUY+2iaw35G0=
|
||||
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/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkumza/numcn v1.0.0 h1:ZT5cf9IJkUZgRgEtCiNNykk0RwsrKXSTsvDHOwUTzgE=
|
||||
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/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-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM=
|
||||
github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
|
||||
github.com/quic-go/quic-go v0.38.1 h1:M36YWA5dEhEeT+slOu/SwMEucbYd0YFidxG3KlGPZaE=
|
||||
github.com/quic-go/quic-go v0.38.1/go.mod h1:ijnZM7JsFIkp4cRyjxJNIzdSfCLmUMg9wdyhGmg+SN4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/shirou/gopsutil/v3 v3.23.1 h1:a9KKO+kGLKEvcPIs4W62v0nu3sciVDOOOPUD0Hz7z/4=
|
||||
github.com/shirou/gopsutil/v3 v3.23.1/go.mod h1:NN6mnm5/0k8jw4cBfCnJtr5L7ErOTg18tMNpgFkn0hA=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
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/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAXZILTY=
|
||||
github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
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.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tetratelabs/wazero v1.5.0 h1:Yz3fZHivfDiZFUXnWMPUoiW7s8tC1sjdBtlJn08qYa0=
|
||||
github.com/tetratelabs/wazero v1.5.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
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/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
||||
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
|
||||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA=
|
||||
github.com/wdvxdr1123/ZeroBot v1.7.5-0.20231009162356-57f71b9f5258 h1:Q0dKoj9SHrR8WjjlcX+eyYBjQKqBn/x1pdJJO1IIOxQ=
|
||||
github.com/wdvxdr1123/ZeroBot v1.7.5-0.20231009162356-57f71b9f5258/go.mod h1:y29UIOy0RD3P+0meDNIWRhcJF3jtWPN9xP9hgt/AJAU=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=
|
||||
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
|
||||
github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=
|
||||
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
|
||||
github.com/wcharczuk/go-chart/v2 v2.1.2 h1:Y17/oYNuXwZg6TFag06qe8sBajwwsuvPiJJXcUcLL6E=
|
||||
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/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
gitlab.com/gomidi/midi/v2 v2.0.25 h1:dkzVBqbaFHjyWwP71MrQNX7IeRUIDonddmHbPpO/Ucg=
|
||||
gitlab.com/gomidi/midi/v2 v2.0.25/go.mod h1:quTyMKSQ4Klevxu6gY4gy2USbeZra0fV5SalndmPfsY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
gitlab.com/gomidi/midi/v2 v2.3.16 h1:yufWSENyjnJ4LFQa9BerzUm4E4aLfTyzw5nmnCteO0c=
|
||||
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-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
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-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.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
|
||||
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/exp/shiny v0.0.0-20221126150942-6ab00d035af9 h1:tLxpBz7qD8qFkRDC159unetNbxKp4zeqsqw2rLwvdxc=
|
||||
golang.org/x/exp/shiny v0.0.0-20221126150942-6ab00d035af9/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8=
|
||||
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
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-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.3.0 h1:HTDXbdK9bjfSWkPzDJIw89W8CAtfFGduujWs33NLLsg=
|
||||
golang.org/x/image v0.3.0/go.mod h1:fXd9211C/0VTlYuAcOhW8dY/RtEJqODXOWBDpmYBf+A=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f h1:kgfVkAEEQXXQ0qc6dH7n6y37NAYmTFmz0YRwrRjgxKw=
|
||||
golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
|
||||
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/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-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-20200421231249-e086a090c8fd/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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
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-20210220032951-036812b2e83c/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.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-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-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-20191204072324-ce4227a45e2e/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-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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-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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.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-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.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.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.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
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.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
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.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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
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.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
|
||||
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
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-20191011141410-1b5146add898/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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
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 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
modernc.org/libc v1.21.5 h1:xBkU9fnHV+hvZuPSRszN0AXDG4M7nwPLwTWwkYcvLCI=
|
||||
modernc.org/libc v1.21.5/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
|
||||
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
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/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||
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/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
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/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
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/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
|
||||
290
gomod2nix.toml
Normal file
290
gomod2nix.toml
Normal file
@ -0,0 +1,290 @@
|
||||
schema = 3
|
||||
|
||||
[mod]
|
||||
[mod."github.com/Baidu-AIP/golang-sdk"]
|
||||
version = "v1.1.1"
|
||||
hash = "sha256-hKshA0K92bKuK92mmtM0osVmqLJcSbeobeWSDpQoRCo="
|
||||
[mod."github.com/FloatTech/AnimeAPI"]
|
||||
version = "v1.7.1-0.20250926171956-ba37dfebfc4a"
|
||||
hash = "sha256-wtr9hgHSPsD5NqSmI3Lo8RVWE+cNMIUGo2bcsKTN8Gg="
|
||||
[mod."github.com/FloatTech/floatbox"]
|
||||
version = "v0.0.0-20251002074805-f95cbc7edb31"
|
||||
hash = "sha256-c50unGhF0JVPHN8geZM/YYQKgGqJgCtVksh4Ij1Pg+4="
|
||||
[mod."github.com/FloatTech/gg"]
|
||||
version = "v1.1.3"
|
||||
hash = "sha256-7K/R2mKjUHVnoJ3b1wDObJ5Un2Htj59Y97G1Ja1tuPo="
|
||||
[mod."github.com/FloatTech/imgfactory"]
|
||||
version = "v0.2.2-0.20230413152719-e101cc3606ef"
|
||||
hash = "sha256-2okFyPQSYIxrc8hxICsbjEM9xq25a3I2A4wmDIYFCg8="
|
||||
[mod."github.com/FloatTech/rendercard"]
|
||||
version = "v0.2.0"
|
||||
hash = "sha256-fgntEYGh2mEl618hM13kb0GGeQEXdP+lochYX8F2OXs="
|
||||
[mod."github.com/FloatTech/sqlite"]
|
||||
version = "v1.7.2"
|
||||
hash = "sha256-R9QaP5FQwtWpHdbCoNX/rYOS/CgkIeRdFB9cwJ4n/JM="
|
||||
[mod."github.com/FloatTech/ttl"]
|
||||
version = "v0.0.0-20250224045156-012b1463287d"
|
||||
hash = "sha256-C5xBt0roPgahradCOTgkhL+j5bvoSXmGwdqcu0aSczc="
|
||||
[mod."github.com/FloatTech/zbpctrl"]
|
||||
version = "v1.7.0"
|
||||
hash = "sha256-HDDnE0oktWJH1tkxuQwUUbeJhmVwY5fyc/vR72D2mkU="
|
||||
[mod."github.com/FloatTech/zbputils"]
|
||||
version = "v1.7.2-0.20251002080916-b554b7039913"
|
||||
hash = "sha256-9z7c79uuFl2LKaCgW1gQN5lmMjgKIcKrakcBlb3zJ90="
|
||||
[mod."github.com/PuerkitoBio/goquery"]
|
||||
version = "v1.10.3"
|
||||
hash = "sha256-Mth7nYm/MtcOhPMbHj7gXF+Mot7eDUBVN570RitGR/c="
|
||||
[mod."github.com/RomiChan/syncx"]
|
||||
version = "v0.0.0-20240418144900-b7402ffdebc7"
|
||||
hash = "sha256-L1j1vgiwqXpF9pjMoRRlrQUHzoULisw/01plaEAwxs4="
|
||||
[mod."github.com/RomiChan/websocket"]
|
||||
version = "v1.4.3-0.20251002072000-d3eb41798438"
|
||||
hash = "sha256-vLu9Va+9AbOIdh1LEetz5JlJK0P2IXKsYRvCdAO8tYw="
|
||||
[mod."github.com/Tnze/go-mc"]
|
||||
version = "v1.20.2"
|
||||
hash = "sha256-Nu4PXNxeARH0itm6yIIplFaywL2yQnPJFksmmuyIptI="
|
||||
[mod."github.com/adamzy/cedar-go"]
|
||||
version = "v0.0.0-20170805034717-80a9c64b256d"
|
||||
hash = "sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0="
|
||||
[mod."github.com/ajstarks/svgo"]
|
||||
version = "v0.0.0-20211024235047-1546f124cd8b"
|
||||
hash = "sha256-sPwt5sImKFk949TzUeYEF2UiJDqHxXFJKRL2Y7JWJ6Y="
|
||||
[mod."github.com/andybalholm/cascadia"]
|
||||
version = "v1.3.3"
|
||||
hash = "sha256-jv7ZshpSd7FZzKKN6hqlUgiR8C3y85zNIS/hq7g76Ho="
|
||||
[mod."github.com/antchfx/htmlquery"]
|
||||
version = "v1.3.4"
|
||||
hash = "sha256-nrtIgRgdOvo0iIQyrhHOFKOmoT8e2gduUsct3f5zDNA="
|
||||
[mod."github.com/antchfx/xpath"]
|
||||
version = "v1.3.5"
|
||||
hash = "sha256-AVM0rR81hgVAI0QVzlz4WijFUjByf6Zew3ZwuikKw2Q="
|
||||
[mod."github.com/corona10/goimagehash"]
|
||||
version = "v1.1.0"
|
||||
hash = "sha256-HyS8nc7kUNnDaVBDzJ9Ym4pRs83YB4M2vHSRwfm6mr4="
|
||||
[mod."github.com/davidscholberg/go-durationfmt"]
|
||||
version = "v0.0.0-20170122144659-64843a2083d3"
|
||||
hash = "sha256-0rdbpBf3AAjMpxvVEGFb2ImgB2i7vdEhIwCyqJs1iHE="
|
||||
[mod."github.com/disintegration/imaging"]
|
||||
version = "v1.6.2"
|
||||
hash = "sha256-pSeMTPvSkxlthh65LjNYYhPLvCZDkBgVgAGYWW0Aguo="
|
||||
[mod."github.com/dustin/go-humanize"]
|
||||
version = "v1.0.1"
|
||||
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"]
|
||||
version = "v0.0.0-20200331213906-ae555eb2afa4"
|
||||
hash = "sha256-sMN6D7IlDpDqUWM8ppoE5Sdb7DvLAJaN6qAucBWJ3rs="
|
||||
[mod."github.com/fumiama/ahsai"]
|
||||
version = "v0.1.1"
|
||||
hash = "sha256-knYw0R5fhjE/asc/TwlGJDzVr+Oaj8sH7kr7x6Mqs3E="
|
||||
[mod."github.com/fumiama/cron"]
|
||||
version = "v1.3.0"
|
||||
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"]
|
||||
version = "v1.7.0"
|
||||
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"]
|
||||
version = "v0.2.7"
|
||||
hash = "sha256-Rjl+z0Hlp2LMi8+pnFe5HrxctyHMi7UPiK33g/OgLdA="
|
||||
[mod."github.com/fumiama/go-simple-protobuf"]
|
||||
version = "v0.2.0"
|
||||
hash = "sha256-2kULBi1sXsFDX2g/KRFmCGkwF60o/UXacNUbIYa/cvw="
|
||||
[mod."github.com/fumiama/gofastTEA"]
|
||||
version = "v0.1.3"
|
||||
hash = "sha256-/Qu57mkkFt7aFufhlkMYPgrWj5XCGbuM28EHDD8w4XY="
|
||||
[mod."github.com/fumiama/gotracemoe"]
|
||||
version = "v0.0.3"
|
||||
hash = "sha256-O3cDkVXu5NG1ZtzubxhH+S91zfgu4uH1L+OiSGYSNXQ="
|
||||
[mod."github.com/fumiama/imgsz"]
|
||||
version = "v0.0.4"
|
||||
hash = "sha256-rrGx+v41OEl0ATwL6u5TNcpfkCQbj3jFNnGiQUNu2qs="
|
||||
[mod."github.com/fumiama/jieba"]
|
||||
version = "v0.0.0-20221203025406-36c17a10b565"
|
||||
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"]
|
||||
version = "v0.0.0-20241001074058-27c4fe5259a4"
|
||||
hash = "sha256-rsV3MKRCSOBMIgJXFCGbCHRY2aBAb32ftU49hT3GjqY="
|
||||
[mod."github.com/fumiama/terasu"]
|
||||
version = "v1.0.1"
|
||||
hash = "sha256-7pe0ByxkmqWeYsxWNwa8urfv6lK1cEPrW1b5l86eM1Y="
|
||||
[mod."github.com/fumiama/unibase2n"]
|
||||
version = "v0.0.0-20240530074540-ec743fd5a6d6"
|
||||
hash = "sha256-I3xNzjrj5y0fy0dfa75V57GanfmHIHmubEn9/y0BBHw="
|
||||
[mod."github.com/gabriel-vasile/mimetype"]
|
||||
version = "v1.4.10"
|
||||
hash = "sha256-ha8NJOAWcmEfQaybfNxyUupt0+zlWxoAKLjCacew43s="
|
||||
[mod."github.com/go-ole/go-ole"]
|
||||
version = "v1.3.0"
|
||||
hash = "sha256-tF8t3VcV71jQ4jbPL91BwR59AKDpUAFV1waIKzkXJu8="
|
||||
[mod."github.com/golang/freetype"]
|
||||
version = "v0.0.0-20170609003504-e2365dfdc4a0"
|
||||
hash = "sha256-AHAFBd20/tqxohkWyQkui2bUef9i1HWYgk9LOIFErvA="
|
||||
[mod."github.com/golang/groupcache"]
|
||||
version = "v0.0.0-20241129210726-2c02b8208cf8"
|
||||
hash = "sha256-AdLZ3dJLe/yduoNvZiXugZxNfmwJjNQyQGsIdzYzH74="
|
||||
[mod."github.com/google/uuid"]
|
||||
version = "v1.6.0"
|
||||
hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw="
|
||||
[mod."github.com/gopxl/beep/v2"]
|
||||
version = "v2.1.1"
|
||||
hash = "sha256-JLCUJCG+VvNlVF296JWIOUvvUFHlqEAJvZfw853qwwU="
|
||||
[mod."github.com/jfreymuth/oggvorbis"]
|
||||
version = "v1.0.5"
|
||||
hash = "sha256-jphTCaPr34ZT9Id4ZZ6zU9Vnxzy6cTjCwjpQ819eGV0="
|
||||
[mod."github.com/jfreymuth/vorbis"]
|
||||
version = "v1.0.2"
|
||||
hash = "sha256-gVS+/PZ5pDnswpTQNZILcrx5ZNq9ShXd6vXn7Jabes4="
|
||||
[mod."github.com/jinzhu/gorm"]
|
||||
version = "v1.9.16"
|
||||
hash = "sha256-qKEwgNE8NxcX1uzT20LwC1TKVmve/nIy+oxdAKlxAuc="
|
||||
[mod."github.com/jinzhu/inflection"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-3h3pHib5MaCXKyKLIMyQnSptDJ16kPjCOQPoEBoQsZg="
|
||||
[mod."github.com/jozsefsallai/gophersauce"]
|
||||
version = "v1.0.1"
|
||||
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"]
|
||||
version = "v0.0.2-0.20231001163256-63db194ca9f5"
|
||||
hash = "sha256-plRZ3yhyCafCXmAD4vnFUoCTRsHmLp7Jn9gFKcEKbds="
|
||||
[mod."github.com/lithammer/fuzzysearch"]
|
||||
version = "v1.1.8"
|
||||
hash = "sha256-aMMRcrlUc9CBiiNkcnWWn4hfNMNyVhrAt67kvP4D4Do="
|
||||
[mod."github.com/liuzl/cedar-go"]
|
||||
version = "v0.0.0-20170805034717-80a9c64b256d"
|
||||
hash = "sha256-N19KTxh70IUBqnchFuWkrJD8uuFOIVqv1iSuN3YFIT0="
|
||||
[mod."github.com/liuzl/da"]
|
||||
version = "v0.0.0-20180704015230-14771aad5b1d"
|
||||
hash = "sha256-J43kwDFmB6LzDhS3Ig/4ddZUTXz1cKztbTA3hILScs8="
|
||||
[mod."github.com/liuzl/gocc"]
|
||||
version = "v0.0.0-20231231122217-0372e1059ca5"
|
||||
hash = "sha256-Dr1xDbO+eR4Y/EpPgQ/S6g6C5etRFKWr8de77skcJR8="
|
||||
[mod."github.com/lufia/plan9stats"]
|
||||
version = "v0.0.0-20251013123823-9fd1530e3ec3"
|
||||
hash = "sha256-N760qPHHaMcxICyA3Ap/b/3exi40AStu7458VPvC9GI="
|
||||
[mod."github.com/mattn/go-isatty"]
|
||||
version = "v0.0.20"
|
||||
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"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-bP+yIaBUY5+oI455mNM8zh14z/SNPaQg44L3RJ0/v/c="
|
||||
[mod."github.com/ncruces/go-strftime"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-GYIwYDONuv/yTE0AEugCHQbtV3oiBaco93xUNYFcVBQ="
|
||||
[mod."github.com/nfnt/resize"]
|
||||
version = "v0.0.0-20180221191011-83c6a9932646"
|
||||
hash = "sha256-yvPV+HlDOyJsiwAcVHQkmtw8DHSXyw+cXHkigXm8rAA="
|
||||
[mod."github.com/notnil/chess"]
|
||||
version = "v1.10.0"
|
||||
hash = "sha256-hsUOS4rVuMW+UCPJzhsZh3PHCi1Lol12BwKujcICayo="
|
||||
[mod."github.com/pbnjay/memory"]
|
||||
version = "v0.0.0-20210728143218-7b4eea64cf58"
|
||||
hash = "sha256-QI+F1oPLOOtwNp8+m45OOoSfYFs3QVjGzE0rFdpF/IA="
|
||||
[mod."github.com/pkg/errors"]
|
||||
version = "v0.9.1"
|
||||
hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw="
|
||||
[mod."github.com/pkumza/numcn"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-cPxqj5tb10+MurN1Lehkk/v8KjaxXpL08+pVgL4x4Hg="
|
||||
[mod."github.com/power-devops/perfstat"]
|
||||
version = "v0.0.0-20240221224432-82ca36839d55"
|
||||
hash = "sha256-ujzuJ1ttQgjHQJEij4O/2+I8DZaUVZQCQgA4ysfqulI="
|
||||
[mod."github.com/remyoudompheng/bigfft"]
|
||||
version = "v0.0.0-20230129092748-24d4a6f8daec"
|
||||
hash = "sha256-vYmpyCE37eBYP/navhaLV4oX4/nu0Z/StAocLIFqrmM="
|
||||
[mod."github.com/shirou/gopsutil/v3"]
|
||||
version = "v3.24.5"
|
||||
hash = "sha256-tc+t1u7gf5A+Bd956dYeM8pGbxs9ezQHqKAKfLQLpuQ="
|
||||
[mod."github.com/shoenig/go-m1cpu"]
|
||||
version = "v0.1.7"
|
||||
hash = "sha256-kIKIE9uxHOniFHGgMgtypYB/OPI8VSQxFUHXehlpuYY="
|
||||
[mod."github.com/sirupsen/logrus"]
|
||||
version = "v1.9.3"
|
||||
hash = "sha256-EnxsWdEUPYid+aZ9H4/iMTs1XMvCLbXZRDyvj89Ebms="
|
||||
[mod."github.com/tetratelabs/wazero"]
|
||||
version = "v1.9.0"
|
||||
hash = "sha256-b8D0cDMuDgyjvJ6LFY8REdcL95BIjM27SeOEQWfB0+0="
|
||||
[mod."github.com/tidwall/gjson"]
|
||||
version = "v1.18.0"
|
||||
hash = "sha256-CO6hqDu8Y58Po6A01e5iTpwiUBQ5khUZsw7czaJHw0I="
|
||||
[mod."github.com/tidwall/match"]
|
||||
version = "v1.2.0"
|
||||
hash = "sha256-O2wTU0SmNIEEOxfncl2BW2czgWeIW5vqR6+A7dtNtXI="
|
||||
[mod."github.com/tidwall/pretty"]
|
||||
version = "v1.2.1"
|
||||
hash = "sha256-S0uTDDGD8qr415Ut7QinyXljCp0TkL4zOIrlJ+9OMl8="
|
||||
[mod."github.com/tklauser/go-sysconf"]
|
||||
version = "v0.3.15"
|
||||
hash = "sha256-Twh9dD/mfNb7Qr5p/KmaK5Xi25VJwj5jESZeJr0qeUc="
|
||||
[mod."github.com/tklauser/numcpus"]
|
||||
version = "v0.10.0"
|
||||
hash = "sha256-NWg68H2Y6MijtlscPaZlLQwgPthEwLV+WpRT01m6kkI="
|
||||
[mod."github.com/wcharczuk/go-chart/v2"]
|
||||
version = "v2.1.2"
|
||||
hash = "sha256-GXWWea/u6BezTsPPrWhTYiTetPP/YW6P+Sj4YdocPaM="
|
||||
[mod."github.com/wdvxdr1123/ZeroBot"]
|
||||
version = "v1.8.2-0.20251002074418-56567b7fc282"
|
||||
hash = "sha256-KaoqopWcXqiRhGYNaA3UqYtXf27yMuBEj/bvqOWxaC4="
|
||||
[mod."github.com/yusufpapurcu/wmi"]
|
||||
version = "v1.2.4"
|
||||
hash = "sha256-N+YDBjOW59YOsZ2lRBVtFsEEi48KhNQRb63/0ZSU3bA="
|
||||
[mod."gitlab.com/gomidi/midi/v2"]
|
||||
version = "v2.3.16"
|
||||
hash = "sha256-o+6UtQH+TRSQlcX8J53esAA/b2c9e7BY7gcO5iSeOy0="
|
||||
[mod."golang.org/x/image"]
|
||||
version = "v0.32.0"
|
||||
hash = "sha256-a5C5nG4IKFkqM/EXjt29wzjrkYEFLKlg5C0aBnXnlZw="
|
||||
[mod."golang.org/x/net"]
|
||||
version = "v0.46.0"
|
||||
hash = "sha256-GkAUXwqEJZF2t5dmxJVEE+t58EDzO24KtihqHqsrZH0="
|
||||
[mod."golang.org/x/sys"]
|
||||
version = "v0.37.0"
|
||||
hash = "sha256-5aT0xP02sW1o9sfJHtWoGGNVYDdwb9FyiX/n6RAlzPo="
|
||||
[mod."golang.org/x/text"]
|
||||
version = "v0.30.0"
|
||||
hash = "sha256-VPT1Y2zzgdk+Q3Gx8hdwKdxbVh0/Zn/HwDpILCW3ZNA="
|
||||
[mod."gopkg.in/yaml.v3"]
|
||||
version = "v3.0.1"
|
||||
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="
|
||||
[mod."modernc.org/libc"]
|
||||
version = "v0.0.0-20240530081950-6f6d8586b5c5"
|
||||
hash = "sha256-SJYYRaiDUmIbqy9l/IgiT/4VkFsPYsaslqGEowut34w="
|
||||
replaced = "github.com/fumiama/libc"
|
||||
[mod."modernc.org/mathutil"]
|
||||
version = "v1.7.1"
|
||||
hash = "sha256-COZ5rF2GhQVR1r6a0DanJ8qwQ94JSKdQxTMWrDzE0Cc="
|
||||
[mod."modernc.org/memory"]
|
||||
version = "v1.11.0"
|
||||
hash = "sha256-MkybF8vvrxXS5j7O8w3skwTo0aMo1yjWS0K440rYcHM="
|
||||
[mod."modernc.org/sqlite"]
|
||||
version = "v1.29.10-simp"
|
||||
hash = "sha256-HCUVN6gZDG0g2WIsQ4ksqE1+XR1IjxvnqEBEU2MO1eE="
|
||||
replaced = "github.com/fumiama/sqlite3"
|
||||
@ -3,13 +3,13 @@
|
||||
package banner
|
||||
|
||||
// Version ...
|
||||
var Version = "v1.7.6"
|
||||
var Version = "v1.10.0"
|
||||
|
||||
// Copyright ...
|
||||
var Copyright = "© 2020 - 2023 FloatTech"
|
||||
var Copyright = "© 2020 - 2025 FloatTech"
|
||||
|
||||
// Banner ...
|
||||
var Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* Version " + Version + " - 2023-11-08 14:13:37 +0900 JST\n" +
|
||||
"* Version " + Version + " - 2025-09-30 23:45:28 +0800 CST\n" +
|
||||
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
|
||||
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"
|
||||
|
||||
@ -27,7 +27,7 @@ var Banner = "* OneBot + ZeroBot + Golang\n" +
|
||||
"* 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() {
|
||||
f, err := os.Create("banner/banner.go")
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
//go:build go1.21
|
||||
|
||||
package kanban
|
||||
|
||||
const Error int = "请使用小于1.21版本的Go"
|
||||
49
main.go
49
main.go
@ -1,6 +1,8 @@
|
||||
// Package main ZeroBot-Plugin main file
|
||||
package main
|
||||
|
||||
//go:generate go run github.com/FloatTech/ZeroBot-Plugin/abineundo/ref -r .
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
@ -12,8 +14,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/abineundo" // 设置插件优先级
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/console" // 更改控制台属性
|
||||
|
||||
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 打印 banner
|
||||
|
||||
// ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- //
|
||||
@ -34,8 +36,12 @@ import (
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chat" // 基础词库
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chatcount" // 聊天时长统计
|
||||
|
||||
_ "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/manager" // 群管
|
||||
@ -60,34 +66,37 @@ import (
|
||||
// vvvvvvvvvvvvvv //
|
||||
// vvvv //
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/custom" // 自定义插件合集
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ahsai" // ahsai tts
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aifalse" // 服务器监控
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aipaint" // ai绘图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiimage" // AI画图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
|
||||
_ "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/baidu" // 百度一下
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baiduaudit" // 百度内容审核
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base16384" // base16384加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/base64gua" // base64卦加解密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baseamasiro" // base天城文加解密
|
||||
_ "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/cangtoushi" // 藏头诗
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chess" // 国际象棋
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chouxianghua" // 说抽象话
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/chrev" // 英文字符翻转
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/coser" // 三次元小姐姐
|
||||
_ "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/danbooru" // DeepDanbooru二次元图标签识别
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana" // 嘉心糖发病
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dish" // 程序员做饭指南
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/drawlots" // 多功能抽签
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/dress" // 女装
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/driftbottle" // 漂流瓶
|
||||
_ "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/font" // 渲染任意文字到图片
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/fortune" // 运势
|
||||
@ -96,40 +105,40 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/gif" // 制图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/github" // 搜索GitHub仓库
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/guessmusic" // 猜歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/heisi" // 黑丝
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hitokoto" // 一言
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hs" // 炉石
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/hyaku" // 百人一首
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/imgfinder" // 关键字搜图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/inject" // 注入指令
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jandan" // 煎蛋网无聊图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jiami" // 兽语加密
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/jptingroom" // 日语听力学习材料
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/juejuezi" // 绝绝子生成器
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/kfccrazythursday" // 疯狂星期四
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolicon" // lolicon 随机图片
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/lolimi" // 桑帛云 API
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/magicprompt" // magicprompt吟唱提示
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/mcfish" // 钓鱼模拟器
|
||||
_ "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/moyucalendar" // 摸鱼人日历
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/music" // 点歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nativesetu" // 本地涩图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nbnhhsh" // 拼音首字母缩写释义工具
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nihongo" // 日语语法学习
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/niuniu" // 牛牛大作战
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/novel" // 铅笔小说网搜索
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nsfw" // nsfw图片识别
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/nwife" // 本地老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/omikuji" // 浅草寺求签
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/poker" // 抽扑克
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qqwife" // 一群一天一夫一妻制群老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/quan" // QQ权重查询
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/qzone" // qq空间表白墙
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/realcugan" // realcugan清晰术
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/reborn" // 投胎
|
||||
_ "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/saucenao" // 以图搜图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/scale" // 叔叔的AI二次元图片放大
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/score" // 分数
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/setutime" // 来份涩图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/shadiao" // 沙雕app
|
||||
@ -139,20 +148,16 @@ import (
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou" // 舔狗日记
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/tracemoe" // 搜番
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/translation" // 翻译
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vitsnyaru" // vits猫雷
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtbmusic" // vtb点歌
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/vtbquotation" // vtb语录
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wallet" // 钱包
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wangyiyun" // 网易云音乐热评
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wantquotes" // 据意查句
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/warframeapi" // warframeAPI插件
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenben" // 文本指令大全
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wenxinvilg" // 百度文心AI画图
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wife" // 抽老婆
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/wordcount" // 聊天热词
|
||||
_ "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/yujn" // 遇见API
|
||||
|
||||
// _ "github.com/FloatTech/ZeroBot-Plugin/plugin/wtf" // 鬼东西
|
||||
|
||||
@ -174,9 +179,9 @@ import (
|
||||
// vvvvvvvvvvvvvv //
|
||||
// vvvv //
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/curse" // 骂人
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aichat" // AI聊天
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/ai_reply" // 人工智能回复
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/curse" // 骂人
|
||||
|
||||
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/thesaurus" // 词典匹配回复
|
||||
|
||||
@ -194,6 +199,7 @@ import (
|
||||
// //
|
||||
// //
|
||||
// -----------------------以下为内置依赖,勿动------------------------ //
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
"github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
@ -234,6 +240,7 @@ func init() {
|
||||
rsz := flag.Uint("r", 4096, "Receiving buffer ring size.")
|
||||
maxpt := flag.Uint("x", 4, "Max process time (min).")
|
||||
markmsg := flag.Bool("m", false, "Don't mark message as read automatically")
|
||||
flag.BoolVar(&file.SkipOriginal, "mirror", false, "Use mirrored lazy data at first")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
|
||||
@ -1,266 +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/ttscn"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
)
|
||||
|
||||
// 数据结构: [4 bits] [4 bits] [8 bits] [8 bits]
|
||||
// [ttscn模式] [百度模式] [tts模式] [回复模式]
|
||||
|
||||
// defaultttsindexkey
|
||||
// 数据结构: [4 bits] [4 bits] [8 bits]
|
||||
// [ttscn模式] [百度模式] [tts模式]
|
||||
|
||||
// [tts模式]: 0~200 genshin 201 baidu 202 ttscn
|
||||
|
||||
const (
|
||||
lastgsttsindex = 200 + iota
|
||||
baiduttsindex
|
||||
ttscnttsindex
|
||||
)
|
||||
|
||||
// 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")
|
||||
)
|
||||
|
||||
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(index)&^0xff)|(index&0xff))
|
||||
}
|
||||
|
||||
func (r replymode) getReplyMode(ctx *zero.Ctx) aireply.AIReply {
|
||||
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.NewQYK(aireply.QYKURL, aireply.QYKBotName)
|
||||
case 1:
|
||||
return aireply.NewXiaoAi(aireply.XiaoAiURL, aireply.XiaoAiBotName)
|
||||
case 2:
|
||||
k := ཆཏ.k
|
||||
if k != "" {
|
||||
return aireply.NewChatGPT(aireply.ChatGPTURL, k)
|
||||
}
|
||||
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
|
||||
}
|
||||
}
|
||||
return aireply.NewQYK(aireply.QYKURL, aireply.QYKBotName)
|
||||
}
|
||||
|
||||
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, lastgsttsindex-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(genshin.SoundList)) || msk == baiduttsindex || msk == ttscnttsindex) {
|
||||
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, index)
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *ttsmode) setSoundMode(ctx *zero.Ctx, name string, baiduper, mockingsynt 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)
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
switch name {
|
||||
case extrattsname[0]:
|
||||
index = baiduttsindex
|
||||
case extrattsname[1]:
|
||||
index = ttscnttsindex
|
||||
default:
|
||||
return errors.New("语音人物" + name + "未注册index")
|
||||
}
|
||||
}
|
||||
m := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
(*syncx.Map[int64, int64])(t).Store(gid, index)
|
||||
return m.SetData(gid, (m.GetData(gid)&^0xffff00)|((index<<8)&0xff00)|((int64(baiduper)<<16)&0x0f0000)|((int64(mockingsynt)<<20)&0xf00000))
|
||||
}
|
||||
|
||||
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(genshin.SoundList)) && m != baiduttsindex && m != ttscnttsindex) {
|
||||
i, _ = (*syncx.Map[int64, int64])(t).Load(defaultttsindexkey)
|
||||
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&0x0f00)>>8, id, sec)
|
||||
case extrattsname[1]:
|
||||
var err error
|
||||
ins, err = ttscn.NewTTSCN("中文(普通话,简体)", ttscnspeakers[int(i&0xf000)>>12], ttscn.KBRates[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default: // 原神
|
||||
k := 原.k
|
||||
if k != "" {
|
||||
ins = genshin.NewGenshin(int(m), 原.k)
|
||||
ttsins[mode] = ins
|
||||
} else {
|
||||
return nil, errors.New("no valid speaker")
|
||||
}
|
||||
}
|
||||
}
|
||||
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])
|
||||
index := m.GetData(defaultttsindexkey)
|
||||
return m.SetData(gid, (m.GetData(gid)&0xff)|((index&^0xff)<<8)) // 重置数据
|
||||
}
|
||||
|
||||
func (t *ttsmode) setDefaultSoundMode(name string, baiduper, mockingsynt 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)
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
switch name {
|
||||
case extrattsname[0]:
|
||||
index = baiduttsindex
|
||||
case extrattsname[1]:
|
||||
index = ttscnttsindex
|
||||
default:
|
||||
return errors.New("语音人物" + name + "未注册index")
|
||||
}
|
||||
}
|
||||
m, ok := control.Lookup("tts")
|
||||
if !ok {
|
||||
return errors.New("[tts] service not found")
|
||||
}
|
||||
(*syncx.Map[int64, int64])(t).Store(defaultttsindexkey, index)
|
||||
return m.SetData(defaultttsindexkey, (index&0xff)|((int64(baiduper)<<8)&0x0f00)|((int64(mockingsynt)<<12)&0xf000))
|
||||
}
|
||||
@ -1,212 +0,0 @@
|
||||
// Package aireply AI 回复
|
||||
package aireply
|
||||
|
||||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"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" +
|
||||
"- 设置原神语音 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.Register("aireply", &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)
|
||||
if zero.OnlyPublic(ctx) {
|
||||
reply = append(reply, message.Reply(ctx.Event.MessageID))
|
||||
ctx.Send(reply)
|
||||
return
|
||||
}
|
||||
ctx.Send(reply)
|
||||
})
|
||||
|
||||
enr.OnPrefix("设置回复模式", zero.AdminPermission).SetBlock(true).Handle(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.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 := r.TalkPlain(ctx.Event.UserID, msg, zero.BotConfig.NickName[0])
|
||||
// 获取语音
|
||||
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(reply) {
|
||||
return reply + "。"
|
||||
}
|
||||
return reply
|
||||
})
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(reply))
|
||||
return
|
||||
}
|
||||
// 发送语音
|
||||
if id := ctx.SendChain(message.Record(rec)); id.ID() == 0 {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Text(reply))
|
||||
}
|
||||
})
|
||||
|
||||
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, n, ")")
|
||||
err = ttsmd.setSoundMode(ctx, param, n, 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("设置成功"))
|
||||
})
|
||||
|
||||
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, 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)
|
||||
}
|
||||
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/gg"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/FloatTech/rendercard"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/shirou/gopsutil/v3/cpu"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
"github.com/shirou/gopsutil/v3/mem"
|
||||
"github.com/shirou/gopsutil/v4/cpu"
|
||||
"github.com/shirou/gopsutil/v4/disk"
|
||||
"github.com/shirou/gopsutil/v4/host"
|
||||
"github.com/shirou/gopsutil/v4/mem"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
@ -41,7 +40,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
backgroundURL = "https://iw233.cn/api.php?sort=mp"
|
||||
backgroundURL = "https://pic.re/image"
|
||||
referer = "https://weibo.com/"
|
||||
)
|
||||
|
||||
@ -184,7 +183,7 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string, botrunsta
|
||||
return
|
||||
}
|
||||
|
||||
data, err = web.GetData("http://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640")
|
||||
data, err = web.GetData("https://q4.qlogo.cn/g?b=qq&nk=" + strconv.FormatInt(uid, 10) + "&s=640")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -237,14 +236,17 @@ func drawstatus(m *ctrl.Control[*zero.Ctx], uid int64, botname string, botrunsta
|
||||
defer wg.Done()
|
||||
titlecard := gg.NewContext(cardw, titlecardh)
|
||||
bwg.Wait()
|
||||
titlecard.DrawImage(blurback, -70, -70)
|
||||
|
||||
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.SetColor(colorswitch(100))
|
||||
titlecard.StrokePreserve()
|
||||
titlecard.SetColor(colorswitch(140))
|
||||
titlecard.Fill()
|
||||
titlecard.ResetClip()
|
||||
titlecard.Stroke()
|
||||
|
||||
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)
|
||||
|
||||
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() {
|
||||
defer wg.Done()
|
||||
basiccard := gg.NewContext(cardw, basiccardh)
|
||||
bwg.Wait()
|
||||
basiccard.DrawImage(blurback, -70, -70-titlecardh-40)
|
||||
|
||||
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.SetColor(colorswitch(100))
|
||||
basiccard.StrokePreserve()
|
||||
basiccard.SetColor(colorswitch(140))
|
||||
basiccard.Fill()
|
||||
basiccard.ResetClip()
|
||||
basiccard.Stroke()
|
||||
|
||||
bslen := len(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)
|
||||
}
|
||||
}
|
||||
basicimg = rendercard.Fillet(basiccard.Image(), 16)
|
||||
basicimg = basiccard.Image()
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
diskcard := gg.NewContext(cardw, diskcardh)
|
||||
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.ClipPreserve()
|
||||
diskcard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40)
|
||||
diskcard.SetColor(colorswitch(140))
|
||||
diskcard.FillPreserve()
|
||||
|
||||
diskcard.SetLineWidth(3)
|
||||
diskcard.SetColor(colorswitch(100))
|
||||
diskcard.StrokePreserve()
|
||||
diskcard.SetColor(colorswitch(140))
|
||||
diskcard.Fill()
|
||||
diskcard.ResetClip()
|
||||
diskcard.Stroke()
|
||||
|
||||
err = diskcard.ParseFontFace(fontbyte, 32)
|
||||
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.ClipPreserve()
|
||||
diskcard.Fill()
|
||||
|
||||
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.Fill()
|
||||
diskcard.ResetClip()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
diskimg = rendercard.Fillet(diskcard.Image(), 16)
|
||||
diskimg = diskcard.Image()
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
moreinfocard := gg.NewContext(cardw, moreinfocardh)
|
||||
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.ClipPreserve()
|
||||
moreinfocard.DrawImage(blurback, -70, -70-titlecardh-40-basiccardh-40-diskcardh-40)
|
||||
moreinfocard.SetColor(colorswitch(140))
|
||||
moreinfocard.FillPreserve()
|
||||
|
||||
moreinfocard.SetLineWidth(3)
|
||||
moreinfocard.SetColor(colorswitch(100))
|
||||
moreinfocard.StrokePreserve()
|
||||
moreinfocard.SetColor(colorswitch(140))
|
||||
moreinfocard.Fill()
|
||||
moreinfocard.ResetClip()
|
||||
moreinfocard.Stroke()
|
||||
|
||||
err = moreinfocard.ParseFontFace(fontbyte, 32)
|
||||
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.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() {
|
||||
defer wg.Done()
|
||||
@ -668,7 +681,7 @@ func diskstate() (stateinfo []*status, err error) {
|
||||
func moreinfo(m *ctrl.Control[*zero.Ctx]) (stateinfo []*status, err error) {
|
||||
var mems runtime.MemStats
|
||||
runtime.ReadMemStats(&mems)
|
||||
fmtmem := storagefmt(float64(mems.Sys))
|
||||
fmtmem := storagefmt(float64(mems.Alloc))
|
||||
|
||||
hostinfo, err := host.Info()
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1,224 +0,0 @@
|
||||
// Package aipaint ai绘图
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
datapath string
|
||||
predictRe = regexp.MustCompile(`{"steps".+?}`)
|
||||
// 参考host http://91.217.139.190:5010 http://91.216.169.75:5010
|
||||
aipaintTxt2ImgURL = "/got_image?token=%v&tags=%v"
|
||||
aipaintImg2ImgURL = "/got_image2image?token=%v&tags=%v"
|
||||
cfg = newServerConfig("data/aipaint/config.json")
|
||||
)
|
||||
|
||||
type result struct {
|
||||
Steps int `json:"steps"`
|
||||
Sampler string `json:"sampler"`
|
||||
Seed int `json:"seed"`
|
||||
Strength float64 `json:"strength"`
|
||||
Noise float64 `json:"noise"`
|
||||
Scale float64 `json:"scale"`
|
||||
Uc string `json:"uc"`
|
||||
}
|
||||
|
||||
func (r *result) String() string {
|
||||
return fmt.Sprintf("steps: %v\nsampler: %v\nseed: %v\nstrength: %v\nnoise: %v\nscale: %v\nuc: %v\n", r.Steps, r.Sampler, r.Seed, r.Strength, r.Noise, r.Scale, r.Uc)
|
||||
}
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "ai绘图",
|
||||
Help: "- [ ai绘图 | 生成色图 | 生成涩图 | ai画图 ] xxx\n" +
|
||||
"- [ ai高级绘图 | 高级生成色图 | 高级生成涩图 | ai高级画图 ] [prompt]\n" +
|
||||
"- 设置ai绘图配置 [server] [token]\n" +
|
||||
"- 设置ai绘图撤回时间90s\n" +
|
||||
"- 查看ai绘图配置\n" +
|
||||
"Tips: 使用前请先前往 http://91.217.139.190:5010/token 按提示获取token" +
|
||||
"设置token示例(请确保是主人并且响应): 设置ai绘图配置 http://91.217.139.190:5010 [token] (中括号无需输入)\n" +
|
||||
"参考服务器 http://91.217.139.190:5010, http://91.216.169.75:5010, http://185.80.202.180:5010\n" +
|
||||
"[prompt]参数如下\n" +
|
||||
"tags:tag词条\nntags:ntag词条\nshape:[Portrait|Landscape|Square]\nscale:[6:20]\nseed:种子\nstrength:[0-1] 建议0-0.7\nnoise:[0-1] 建议0-0.15" +
|
||||
"参数与参数内容用:连接,每个参数之间用回车分割",
|
||||
PrivateDataFolder: "aipaint",
|
||||
})
|
||||
datapath = file.BOTPATH + "/" + engine.DataFolder()
|
||||
if file.IsNotExist(cfg.file) {
|
||||
s := serverConfig{}
|
||||
data, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = os.WriteFile(cfg.file, data, 0666)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
engine.OnPrefixGroup([]string{`ai绘图`, `生成色图`, `生成涩图`, `ai画图`}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
args := ctx.State["args"].(string)
|
||||
data, err := web.GetData(cfg.BaseURL + fmt.Sprintf(aipaintTxt2ImgURL, cfg.Token, url.QueryEscape(strings.TrimSpace(strings.ReplaceAll(args, " ", "%20")))))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
engine.OnPrefixGroup([]string{`ai高级绘图`, `高级生成色图`, `高级生成涩图`, `ai高级画图`}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
tags := make(map[string]string)
|
||||
args := strings.Split(ctx.State["args"].(string), "\n")
|
||||
if len(args) < 1 {
|
||||
ctx.SendChain(message.Text("ERROR: 请输入正确的参数"))
|
||||
return
|
||||
}
|
||||
for _, info := range args {
|
||||
value := strings.Split(info, ":")
|
||||
if len(value) > 1 {
|
||||
if value[0] == "R18" && value[1] == "1" {
|
||||
value[1] = "0"
|
||||
ctx.SendChain(message.Text("不准涩涩! 已将R18设置为0. "))
|
||||
}
|
||||
tags[value[0]] = strings.Join(value[1:], ":")
|
||||
}
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
apiurl := "/got_image?token=" + cfg.Token
|
||||
if _, ok := tags["tags"]; ok {
|
||||
apiurl += "&tags=" + url.QueryEscape(strings.ReplaceAll(strings.TrimSpace(tags["tags"]), " ", "%20"))
|
||||
}
|
||||
if _, ok := tags["ntags"]; ok {
|
||||
apiurl += "&ntags=" + url.QueryEscape(strings.ReplaceAll(strings.TrimSpace(tags["ntags"]), " ", "%20"))
|
||||
}
|
||||
if _, ok := tags["R18"]; ok {
|
||||
apiurl += "&R18=" + url.QueryEscape(strings.TrimSpace(tags["R18"]))
|
||||
}
|
||||
if _, ok := tags["shape"]; ok {
|
||||
apiurl += "&shape=" + url.QueryEscape(strings.TrimSpace(tags["shape"]))
|
||||
}
|
||||
if _, ok := tags["scale"]; ok {
|
||||
apiurl += "&scale=" + url.QueryEscape(strings.TrimSpace(tags["scale"]))
|
||||
}
|
||||
if _, ok := tags["seed"]; ok {
|
||||
apiurl += "&seed=" + url.QueryEscape(strings.TrimSpace(tags["seed"]))
|
||||
}
|
||||
if _, ok := tags["strength"]; ok {
|
||||
apiurl += "&strength=" + url.QueryEscape(strings.TrimSpace(tags["strength"]))
|
||||
}
|
||||
if _, ok := tags["noise"]; ok {
|
||||
apiurl += "&noise=" + url.QueryEscape(strings.TrimSpace(tags["noise"]))
|
||||
}
|
||||
data, err := web.GetData(cfg.BaseURL + apiurl)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
engine.OnRegex(`^设置ai绘图配置\s(.*[^\s$])\s(.+)$`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = cfg.update(regexMatched[1], regexMatched[2], cfg.Interval)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功设置\nbase_url: ", cfg.BaseURL, "\ntoken: ", cfg.Token, "\ninterval: ", cfg.Interval))
|
||||
})
|
||||
engine.OnRegex(`^设置ai绘图撤回时间(\d{1,3})s$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
regexMatched := ctx.State["regex_matched"].([]string)
|
||||
interval, err := strconv.Atoi(regexMatched[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
err = cfg.update(cfg.BaseURL, cfg.Token, interval)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功设置撤回时间为", cfg.Interval, "s"))
|
||||
})
|
||||
engine.OnFullMatch(`查看ai绘图配置`, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("base_url: ", cfg.BaseURL, "\ntoken: ", cfg.Token, "\ninterval: ", cfg.Interval))
|
||||
})
|
||||
}
|
||||
|
||||
func sendAiImg(ctx *zero.Ctx, data []byte, interval int) {
|
||||
var loadData string
|
||||
if predictRe.MatchString(binary.BytesToString(data)) {
|
||||
loadData = predictRe.FindStringSubmatch(binary.BytesToString(data))[0]
|
||||
}
|
||||
var r result
|
||||
if loadData != "" {
|
||||
err := json.Unmarshal(binary.StringToBytes(loadData), &r)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
r.Uc, err = url.QueryUnescape(r.Uc)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
encodeStr := base64.StdEncoding.EncodeToString(data)
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image("base64://"+encodeStr))}
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Text(r.String())))
|
||||
if mid := ctx.Send(m); mid.ID() == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
} else if interval > 0 {
|
||||
go func(i message.MessageID) {
|
||||
time.Sleep(time.Duration(interval) * time.Second)
|
||||
ctx.DeleteMessage(i)
|
||||
}(mid)
|
||||
}
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
)
|
||||
|
||||
// 配置结构体
|
||||
type serverConfig struct {
|
||||
BaseURL string `json:"base_url"`
|
||||
Token string `json:"token"`
|
||||
Interval int `json:"interval"`
|
||||
file string
|
||||
}
|
||||
|
||||
func newServerConfig(file string) *serverConfig {
|
||||
return &serverConfig{
|
||||
file: file,
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *serverConfig) update(baseURL, token string, interval int) (err error) {
|
||||
if baseURL != "" {
|
||||
cfg.BaseURL = baseURL
|
||||
}
|
||||
if token != "" {
|
||||
cfg.Token = token
|
||||
}
|
||||
cfg.Interval = interval
|
||||
reader, err := os.Create(cfg.file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer reader.Close()
|
||||
return json.NewEncoder(reader).Encode(cfg)
|
||||
}
|
||||
|
||||
func (cfg *serverConfig) load() (err error) {
|
||||
if cfg.BaseURL != "" && cfg.Token != "" && cfg.Interval != 0 {
|
||||
return
|
||||
}
|
||||
if file.IsNotExist(cfg.file) {
|
||||
err = errors.New("no server config")
|
||||
return
|
||||
}
|
||||
reader, err := os.Open(cfg.file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer reader.Close()
|
||||
err = json.NewDecoder(reader).Decode(cfg)
|
||||
return
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
)
|
||||
|
||||
type context struct {
|
||||
usrdir string
|
||||
headimgsdir []string
|
||||
}
|
||||
|
||||
func newContext(user int64) *context {
|
||||
c := new(context)
|
||||
c.usrdir = datapath + "users/" + strconv.FormatInt(user, 10) + `/`
|
||||
_ = os.MkdirAll(c.usrdir, 0755)
|
||||
c.headimgsdir = make([]string, 2)
|
||||
c.headimgsdir[0] = c.usrdir + "0.gif"
|
||||
c.headimgsdir[1] = c.usrdir + "1.gif"
|
||||
return c
|
||||
}
|
||||
|
||||
func (cc *context) prepareLogos(s ...string) error {
|
||||
for i, v := range s {
|
||||
_, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
err = file.DownloadTo("https://gchat.qpic.cn/gchatpic_new//--"+strings.ToUpper(v)+"/0", cc.usrdir+strconv.Itoa(i)+".gif")
|
||||
} else {
|
||||
err = file.DownloadTo("http://q4.qlogo.cn/g?b=qq&nk="+v+"&s=640", cc.usrdir+strconv.Itoa(i)+".gif")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
process.SleepAbout1sTo2s()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1,88 +0,0 @@
|
||||
// Package aipaint ai绘图
|
||||
package aipaint
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.Register("img2img", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: true,
|
||||
Brief: "以图绘图",
|
||||
Help: "- [ 以图绘图 | 以图生图 | 以图画图 ] xxx [图片]|@xxx|[qq号]\n" +
|
||||
"- 官方以图绘图api已失效 需要自建api 其他配置参数同ai绘图",
|
||||
PrivateDataFolder: "img2img",
|
||||
})
|
||||
datapath = file.BOTPATH + "/" + engine.DataFolder()
|
||||
engine.OnRegex(`^(以图绘图|以图生图|以图画图)[\s\S]*?(\[CQ:(image\,file=([0-9a-zA-Z]{32}).*|at.+?(\d{5,11}))\].*|(\d+))$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
err := cfg.load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
c := newContext(ctx.Event.UserID)
|
||||
list := ctx.State["regex_matched"].([]string)
|
||||
err = c.prepareLogos(list[4]+list[5]+list[6], strconv.FormatInt(ctx.Event.UserID, 10))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
args := strings.TrimSuffix(strings.TrimPrefix(list[0], list[1]), list[2])
|
||||
if args == "" {
|
||||
ctx.SendChain(message.Text("ERROR: 以图绘图必须添加tag"))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
postURL := cfg.BaseURL + fmt.Sprintf(aipaintImg2ImgURL, cfg.Token, url.QueryEscape(strings.TrimSpace(strings.ReplaceAll(args, " ", "%20"))))
|
||||
|
||||
f, err := os.Open(c.headimgsdir[0])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
img, _, err := image.Decode(f)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
imageShape := ""
|
||||
switch {
|
||||
case img.Bounds().Dx() > img.Bounds().Dy():
|
||||
imageShape = "Landscape"
|
||||
case img.Bounds().Dx() == img.Bounds().Dy():
|
||||
imageShape = "Square"
|
||||
default:
|
||||
imageShape = "Portrait"
|
||||
}
|
||||
|
||||
// 图片转base64
|
||||
base64Bytes, err := imgfactory.ToBase64(img)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
data, err := web.PostData(postURL+"&shape="+imageShape, "text/plain", bytes.NewReader(base64Bytes))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
sendAiImg(ctx, data, cfg.Interval)
|
||||
})
|
||||
}
|
||||
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))
|
||||
})
|
||||
}
|
||||
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"
|
||||
)
|
||||
|
||||
const bandur time.Duration = time.Minute * 10
|
||||
const (
|
||||
bandur time.Duration = time.Minute * 2
|
||||
add = "添加违禁词"
|
||||
del = "删除违禁词"
|
||||
list = "查看违禁词"
|
||||
)
|
||||
|
||||
var (
|
||||
managers *ctrl.Manager[*zero.Ctx] // managers lazy load
|
||||
@ -41,7 +46,7 @@ func init() {
|
||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "违禁词检测",
|
||||
Help: "- /[添加|删除|查看]违禁词",
|
||||
Help: "- [添加|删除|查看]违禁词",
|
||||
PrivateDataFolder: "anti_abuse",
|
||||
})
|
||||
|
||||
@ -56,10 +61,14 @@ func init() {
|
||||
return true
|
||||
})
|
||||
|
||||
engine.OnMessage(onceRule, zero.OnlyGroup, func(ctx *zero.Ctx) bool {
|
||||
if !ctx.Event.IsToMe {
|
||||
notAntiabuse := func(ctx *zero.Ctx) bool {
|
||||
if zero.PrefixRule(add)(ctx) || zero.PrefixRule(del)(ctx) || zero.PrefixRule(list)(ctx) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
engine.OnMessage(onceRule, notAntiabuse, zero.OnlyGroup, func(ctx *zero.Ctx) bool {
|
||||
uid := ctx.Event.UserID
|
||||
gid := ctx.Event.GroupID
|
||||
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 {
|
||||
t := time.Now().Unix()
|
||||
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))
|
||||
db.Lock()
|
||||
defer db.Unlock()
|
||||
@ -92,9 +102,9 @@ func init() {
|
||||
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) {
|
||||
args := ctx.State["args"].(string)
|
||||
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||
if err := db.insertWord(ctx.Event.GroupID, args); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
} 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) {
|
||||
args := ctx.State["args"].(string)
|
||||
args := strings.TrimSpace(ctx.State["args"].(string))
|
||||
if err := db.deleteWord(ctx.Event.GroupID, args); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
} 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) {
|
||||
b, err := text.RenderToBase64(db.listWords(ctx.Event.GroupID), text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
|
||||
@ -30,7 +30,7 @@ var (
|
||||
)
|
||||
|
||||
func newantidb(path string) (*antidb, error) {
|
||||
db := &antidb{Sqlite: sqlite.Sqlite{DBPath: path}}
|
||||
db := &antidb{Sqlite: sqlite.New(path)}
|
||||
err := db.Open(bandur)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -46,7 +46,7 @@ func newantidb(path string) (*antidb, error) {
|
||||
cache.Touch(nilbt.ID, -time.Since(t))
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ import (
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return message.Text("ERROR: ", err)
|
||||
@ -27,7 +27,7 @@ func (dgtr datagetter) randImage(file ...string) message.MessageSegment {
|
||||
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)
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
|
||||
func randText(text ...string) message.MessageSegment {
|
||||
func randText(text ...string) message.Segment {
|
||||
return message.Text(text[rand.Intn(len(text))])
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ func init() { // 插件主体
|
||||
Brief: "atri人格文本回复",
|
||||
Help: "本插件基于 ATRI ,为 Golang 移植版\n" +
|
||||
"- ATRI醒醒\n- ATRI睡吧\n- 萝卜子\n- 喜欢 | 爱你 | 爱 | suki | daisuki | すき | 好き | 贴贴 | 老婆 | 亲一个 | mua\n" +
|
||||
"- 草你妈 | 操你妈 | 脑瘫 | 废柴 | fw | 废物 | 战斗 | 爬 | 爪巴 | sb | SB | 傻B\n- 早安 | 早哇 | 早上好 | ohayo | 哦哈哟 | お早う | 早好 | 早 | 早早早\n" +
|
||||
"- 草你妈 | 操你妈 | 脑瘫 | 废柴 | fw | 废物 | 战斗 | 爬 | 爪巴 | sb | SB | 傻B\n- 早哇 | 早上好 | ohayo | 哦哈哟 | お早う | 早好 | 早 | 早早早\n" +
|
||||
"- 中午好 | 午安 | 午好\n- 晚安 | oyasuminasai | おやすみなさい | 晚好 | 晚上好\n- 高性能 | 太棒了 | すごい | sugoi | 斯国一 | よかった\n" +
|
||||
"- 没事 | 没关系 | 大丈夫 | 还好 | 不要紧 | 没出大问题 | 没伤到哪\n- 好吗 | 是吗 | 行不行 | 能不能 | 可不可以\n- 啊这\n- 我好了\n- ? | ? | ¿\n" +
|
||||
"- 离谱\n- 答应我",
|
||||
@ -84,7 +84,7 @@ func init() { // 插件主体
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(dgtr.randImage("FN.jpg", "WQ.jpg", "WQ1.jpg"))
|
||||
})
|
||||
engine.OnFullMatchGroup([]string{"早安", "早哇", "早上好", "ohayo", "哦哈哟", "お早う", "早好", "早", "早早早"}).SetBlock(true).
|
||||
engine.OnFullMatchGroup([]string{"早哇", "早上好", "ohayo", "哦哈哟", "お早う", "早好", "早", "早早早"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
now := time.Now().Hour()
|
||||
switch {
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
// Package baidu 百度百科
|
||||
package baidu
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
duURL = "https://api.a20safe.com/api.php?api=21&key=%s&text=%s" // api地址
|
||||
wikiURL = "https://api.a20safe.com/api.php?api=23&key=%s&text=%s"
|
||||
key = "7d06a110e9e20a684e02934549db1d3d"
|
||||
)
|
||||
|
||||
type result struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data []struct {
|
||||
Content string `json:"content"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func init() { // 主函数
|
||||
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Help: "百科\n" +
|
||||
"- 百度/百科/维基/wiki[关键字]",
|
||||
})
|
||||
en.OnRegex(`^(百度|维基|百科|wiki)\s*(.+)$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
var es []byte
|
||||
var err error
|
||||
switch ctx.State["regex_matched"].([]string)[1] {
|
||||
case "百度", "百科":
|
||||
es, err = web.GetData(fmt.Sprintf(duURL, key, ctx.State["regex_matched"].([]string)[2])) // 将网站返回结果赋值
|
||||
case "wiki", "维基":
|
||||
es, err = web.GetData(fmt.Sprintf(wikiURL, key, ctx.State["regex_matched"].([]string)[2])) // 将网站返回结果赋值
|
||||
}
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
var r result // r数组
|
||||
err = json.Unmarshal(es, &r) // 填api返回结果,struct地址
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出现错误捏:", err))
|
||||
return
|
||||
}
|
||||
if r.Code == 0 && len(r.Data) > 0 {
|
||||
ctx.SendChain(message.Text(r.Data[0].Content)) // 输出提取后的结果
|
||||
} else {
|
||||
ctx.SendChain(message.Text("API访问错误"))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -31,8 +31,6 @@ func (bdres *baiduRes) audit(ctx *zero.Ctx, configpath string) {
|
||||
if bdres.ConclusionType != 2 {
|
||||
return
|
||||
}
|
||||
// 创建消息ID
|
||||
mid := message.NewMessageIDFromInteger(ctx.Event.MessageID.(int64))
|
||||
// 获取群配置
|
||||
group := config.groupof(ctx.Event.GroupID)
|
||||
// 检测群配置里的不检测类型白名单, 忽略掉不检测的违规类型
|
||||
@ -44,7 +42,7 @@ func (bdres *baiduRes) audit(ctx *zero.Ctx, configpath string) {
|
||||
// 生成回复文本
|
||||
res := group.reply(bdres)
|
||||
// 撤回消息
|
||||
ctx.DeleteMessage(mid)
|
||||
ctx.DeleteMessage(ctx.Event.MessageID)
|
||||
// 查看是否启用撤回后禁言
|
||||
if group.DMBAN {
|
||||
// 从历史违规记录中获取指定用户
|
||||
@ -226,7 +224,7 @@ func (g *group) reply(bdres *baiduRes) message.Message {
|
||||
g.mu.Lock()
|
||||
defer g.mu.Unlock()
|
||||
// 建立消息段
|
||||
msgs := make([]message.MessageSegment, 0, 8)
|
||||
msgs := make([]message.Segment, 0, 8)
|
||||
// 生成简略审核结果回复
|
||||
msgs = append(msgs, message.Text(bdres.Conclusion, "\n"))
|
||||
// 查看是否开启详细审核内容提示, 并确定审核内容值为疑似, 或者不合规
|
||||
|
||||
@ -11,7 +11,6 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
@ -31,7 +30,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
re = regexp.MustCompile(`^\d+$`)
|
||||
danmakuTypeMap = map[int64]string{
|
||||
0: "普通消息",
|
||||
1: "礼物",
|
||||
@ -73,7 +71,7 @@ func init() {
|
||||
}
|
||||
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) {
|
||||
id := ctx.State["uid"].(string)
|
||||
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) {
|
||||
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) {
|
||||
id := ctx.State["uid"].(string)
|
||||
today := time.Now().Format("20060102")
|
||||
@ -134,7 +132,7 @@ func init() {
|
||||
return
|
||||
}
|
||||
vupLen := len(vups)
|
||||
medals, err := bz.GetMedalWall(cfg, id)
|
||||
medals, err := cfg.GetMedalWall(id)
|
||||
sort.Sort(bz.MedalSorter(medals))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
@ -275,7 +273,7 @@ func init() {
|
||||
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)
|
||||
pagenum := ctx.State["regex_matched"].([]string)[2]
|
||||
if pagenum == "" {
|
||||
@ -337,12 +335,12 @@ func init() {
|
||||
faceH := float64(510)
|
||||
|
||||
totalDanmuku := 0
|
||||
for i := 0; i < len(danmaku.Data.Data); i++ {
|
||||
totalDanmuku += len(danmaku.Data.Data[i].Danmakus) + 1
|
||||
for i := 0; i < len(danmaku.Data.Data.Records); i++ {
|
||||
totalDanmuku += len(danmaku.Data.Data.Records[i].Danmakus) + 1
|
||||
}
|
||||
cw := 3000
|
||||
mcw := float64(2000)
|
||||
ch := 550 + len(danmaku.Data.Data)*int(faceH) + totalDanmuku*int(danmuH)
|
||||
ch := 550 + len(danmaku.Data.Data.Records)*int(faceH) + totalDanmuku*int(danmuH)
|
||||
canvas = gg.NewContext(cw, ch)
|
||||
canvas.SetColor(color.White)
|
||||
canvas.Clear()
|
||||
@ -372,9 +370,9 @@ func init() {
|
||||
canvas.DrawString("网页链接: "+fmt.Sprintf(bz.DanmakuURL, u.Mid), startWidth, 422.5)
|
||||
var channelStart float64
|
||||
channelStart = float64(550)
|
||||
for i := 0; i < len(danmaku.Data.Data); i++ {
|
||||
item := danmaku.Data.Data[i]
|
||||
facePath = cachePath + strconv.Itoa(int(item.Channel.UID)) + "vupFace" + path.Ext(item.Channel.FaceURL)
|
||||
for i := 0; i < len(danmaku.Data.Data.Records); i++ {
|
||||
item := danmaku.Data.Data.Records[i]
|
||||
facePath = cachePath + strconv.Itoa(item.Channel.UID) + "vupFace" + path.Ext(item.Channel.FaceURL)
|
||||
if path.Ext(item.Channel.FaceURL) != ".webp" {
|
||||
err = initFacePic(facePath, item.Channel.FaceURL)
|
||||
if err != nil {
|
||||
@ -393,7 +391,7 @@ func init() {
|
||||
}
|
||||
canvas.SetRGB255(24, 144, 255)
|
||||
canvas.DrawString("标题: "+item.Live.Title, startWidth, channelStart+fontH)
|
||||
canvas.DrawString("主播: "+item.Channel.Name, startWidth, channelStart+fontH*2)
|
||||
canvas.DrawString("主播: "+item.Channel.UName, startWidth, channelStart+fontH*2)
|
||||
canvas.SetColor(color.Black)
|
||||
canvas.DrawString("开始时间: "+time.UnixMilli(item.Live.StartDate).Format("2006-01-02 15:04:05"), startWidth, channelStart+fontH*3)
|
||||
if item.Live.IsFinish {
|
||||
@ -411,8 +409,8 @@ func init() {
|
||||
|
||||
canvas.DrawString("直播时长: "+strconv.FormatFloat(float64(time.Now().UnixMilli()-item.Live.StartDate)/3600000.0, 'f', 1, 64)+"小时", startWidth, channelStart+fontH*5)
|
||||
}
|
||||
canvas.DrawString("弹幕数量: "+strconv.Itoa(int(item.Live.DanmakusCount)), startWidth, channelStart+fontH*6)
|
||||
canvas.DrawString("观看次数: "+strconv.Itoa(int(item.Live.WatchCount)), startWidth, channelStart+fontH*7)
|
||||
canvas.DrawString("弹幕数量: "+strconv.Itoa(item.Live.DanmakusCount), startWidth, channelStart+fontH*6)
|
||||
canvas.DrawString("观看次数: "+strconv.Itoa(item.Live.WatchCount), startWidth, channelStart+fontH*7)
|
||||
|
||||
t := "收益:"
|
||||
l, _ := canvas.MeasureString(t)
|
||||
@ -434,7 +432,7 @@ func init() {
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
moveW += l + dz
|
||||
|
||||
t = danItem.Name
|
||||
t = danItem.UName
|
||||
l, _ = canvas.MeasureString(t)
|
||||
canvas.SetRGB255(24, 144, 255)
|
||||
canvas.DrawString(t, moveW, danmuNow)
|
||||
@ -582,51 +580,3 @@ func int2rbg(t int64) (int64, int64, int64) {
|
||||
b, g, r := int64(buf[0]), int64(buf[1]), int64(buf[2])
|
||||
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,113 +0,0 @@
|
||||
// Package bilibili bilibili卡片解析
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
limit = ctxext.NewLimiterManager(time.Second*10, 1)
|
||||
searchVideo = `bilibili.com\\?/video\\?/(?:av(\d+)|([bB][vV][0-9a-zA-Z]+))`
|
||||
searchDynamic = `(t.bilibili.com|m.bilibili.com\\?/dynamic)\\?/(\d+)`
|
||||
searchArticle = `bilibili.com\\?/read\\?/(?:cv|mobile\\?/)(\d+)`
|
||||
searchLiveRoom = `live.bilibili.com\\?/(\d+)`
|
||||
searchVideoRe = regexp.MustCompile(searchVideo)
|
||||
searchDynamicRe = regexp.MustCompile(searchDynamic)
|
||||
searchArticleRe = regexp.MustCompile(searchArticle)
|
||||
searchLiveRoomRe = regexp.MustCompile(searchLiveRoom)
|
||||
)
|
||||
|
||||
// 插件主体
|
||||
func init() {
|
||||
en := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "b站链接解析",
|
||||
Help: "例:- t.bilibili.com/642277677329285174\n- bilibili.com/read/cv17134450\n- bilibili.com/video/BV13B4y1x7pS\n- live.bilibili.com/22603245 ",
|
||||
})
|
||||
en.OnRegex(`((b23|acg).tv|bili2233.cn)/[0-9a-zA-Z]+`).SetBlock(true).Limit(limit.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
url := ctx.State["regex_matched"].([]string)[0]
|
||||
realurl, err := bz.GetRealURL("https://" + url)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case searchVideoRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchVideoRe.FindStringSubmatch(realurl)
|
||||
handleVideo(ctx)
|
||||
case searchDynamicRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchDynamicRe.FindStringSubmatch(realurl)
|
||||
handleDynamic(ctx)
|
||||
case searchArticleRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchArticleRe.FindStringSubmatch(realurl)
|
||||
handleArticle(ctx)
|
||||
case searchLiveRoomRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchLiveRoomRe.FindStringSubmatch(realurl)
|
||||
handleLive(ctx)
|
||||
}
|
||||
})
|
||||
en.OnRegex(searchVideo).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleVideo)
|
||||
en.OnRegex(searchDynamic).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleDynamic)
|
||||
en.OnRegex(searchArticle).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleArticle)
|
||||
en.OnRegex(searchLiveRoom).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleLive)
|
||||
}
|
||||
|
||||
func handleVideo(ctx *zero.Ctx) {
|
||||
id := ctx.State["regex_matched"].([]string)[1]
|
||||
if id == "" {
|
||||
id = ctx.State["regex_matched"].([]string)[2]
|
||||
}
|
||||
card, err := bz.GetVideoInfo(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
msg, err := videoCard2msg(card)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
summaryMsg, err := getVideoSummary(card)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
msg = append(msg, summaryMsg...)
|
||||
ctx.SendChain(msg...)
|
||||
}
|
||||
|
||||
func handleDynamic(ctx *zero.Ctx) {
|
||||
msg, err := dynamicDetail(cfg, ctx.State["regex_matched"].([]string)[2])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(msg...)
|
||||
}
|
||||
|
||||
func handleArticle(ctx *zero.Ctx) {
|
||||
card, err := bz.GetArticleInfo(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(articleCard2msg(card, ctx.State["regex_matched"].([]string)[1])...)
|
||||
}
|
||||
|
||||
func handleLive(ctx *zero.Ctx) {
|
||||
card, err := bz.GetLiveRoomInfo(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(liveCard2msg(card)...)
|
||||
}
|
||||
@ -1,352 +0,0 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"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
|
||||
}
|
||||
|
||||
// getVideoSummary AI视频总结
|
||||
func getVideoSummary(card bz.Card) (msg []message.MessageSegment, err error) {
|
||||
var (
|
||||
data []byte
|
||||
videoSummary bz.VideoSummary
|
||||
)
|
||||
data, err = web.GetData(bz.SignURL(fmt.Sprintf(bz.VideoSummaryURL, card.BvID, card.CID)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(data, &videoSummary)
|
||||
msg = make([]message.MessageSegment, 0, 16)
|
||||
msg = append(msg, message.Text("已为你生成视频总结\n\n"))
|
||||
msg = append(msg, message.Text(videoSummary.Data.ModelResult.Summary, "\n\n"))
|
||||
for _, v := range videoSummary.Data.ModelResult.Outline {
|
||||
msg = append(msg, message.Text("● ", v.Title, "\n"))
|
||||
for _, p := range v.PartOutline {
|
||||
msg = append(msg, message.Text(fmt.Sprintf("%d:%d %s\n", p.Timestamp/60, p.Timestamp%60, p.Content)))
|
||||
}
|
||||
msg = append(msg, message.Text("\n"))
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -1,63 +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 TestGetVideoSummary(t *testing.T) {
|
||||
card, err := bz.GetVideoInfo("BV1mF411j7iU")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(getVideoSummary(card))
|
||||
}
|
||||
|
||||
func TestLiveRoomInfo(t *testing.T) {
|
||||
card, err := bz.GetLiveRoomInfo("83171")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(liveCard2msg(card))
|
||||
}
|
||||
@ -75,7 +75,7 @@ func updateVup() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gjson.Get(binary.BytesToString(data), "@this").ForEach(func(key, value gjson.Result) bool {
|
||||
gjson.Get(binary.BytesToString(data), "@this").ForEach(func(_, value gjson.Result) bool {
|
||||
mid := value.Get("mid").Int()
|
||||
uname := value.Get("uname").String()
|
||||
roomid := value.Get("roomid").Int()
|
||||
291
plugin/bilibiliparse/parse.go
Normal file
291
plugin/bilibiliparse/parse.go
Normal file
@ -0,0 +1,291 @@
|
||||
// Package bilibiliparse bilibili卡片解析
|
||||
package bilibiliparse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
bz "github.com/FloatTech/AnimeAPI/bilibili"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/pkg/errors"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const (
|
||||
enableVideoSummary = int64(0x10)
|
||||
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 (
|
||||
limit = ctxext.NewLimiterManager(time.Second*10, 1)
|
||||
searchVideo = `bilibili.com\\?/video\\?/(?:av(\d+)|([bB][vV][0-9a-zA-Z]+))`
|
||||
searchDynamic = `(t.bilibili.com|m.bilibili.com\\?/dynamic)\\?/(\d+)`
|
||||
searchArticle = `bilibili.com\\?/read\\?/(?:cv|mobile\\?/)(\d+)`
|
||||
searchLiveRoom = `live.bilibili.com\\?/(\d+)`
|
||||
searchVideoRe = regexp.MustCompile(searchVideo)
|
||||
searchDynamicRe = regexp.MustCompile(searchDynamic)
|
||||
searchArticleRe = regexp.MustCompile(searchArticle)
|
||||
searchLiveRoomRe = regexp.MustCompile(searchLiveRoom)
|
||||
cachePath string
|
||||
cfg = bz.NewCookieConfig("data/Bilibili/config.json")
|
||||
)
|
||||
|
||||
// 插件主体
|
||||
func init() {
|
||||
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "b站链接解析",
|
||||
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).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
u := ctx.State["regex_matched"].([]string)[0]
|
||||
u = strings.ReplaceAll(u, "\\", "")
|
||||
realurl, err := bz.GetRealURL("https://" + u)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case searchVideoRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchVideoRe.FindStringSubmatch(realurl)
|
||||
handleVideo(ctx)
|
||||
case searchDynamicRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchDynamicRe.FindStringSubmatch(realurl)
|
||||
handleDynamic(ctx)
|
||||
case searchArticleRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchArticleRe.FindStringSubmatch(realurl)
|
||||
handleArticle(ctx)
|
||||
case searchLiveRoomRe.MatchString(realurl):
|
||||
ctx.State["regex_matched"] = searchLiveRoomRe.FindStringSubmatch(realurl)
|
||||
handleLive(ctx)
|
||||
}
|
||||
})
|
||||
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 |= enableVideoSummary
|
||||
case "关闭", "关掉", "禁用":
|
||||
data &= disableVideoSummary
|
||||
default:
|
||||
return
|
||||
}
|
||||
err := c.SetData(gid, data)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("出错啦: ", err))
|
||||
return
|
||||
}
|
||||
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(searchDynamic).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleDynamic)
|
||||
en.OnRegex(searchArticle).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleArticle)
|
||||
en.OnRegex(searchLiveRoom).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleLive)
|
||||
}
|
||||
|
||||
func handleVideo(ctx *zero.Ctx) {
|
||||
id := ctx.State["regex_matched"].([]string)[1]
|
||||
if id == "" {
|
||||
id = ctx.State["regex_matched"].([]string)[2]
|
||||
}
|
||||
card, err := bz.GetVideoInfo(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
msg, err := card.ToVideoMessage()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
|
||||
if ok && c.GetData(ctx.Event.GroupID)&enableVideoSummary == enableVideoSummary {
|
||||
summaryMsg, err := getVideoSummary(cfg, card)
|
||||
if err != nil {
|
||||
msg = append(msg, message.Text("ERROR: ", err))
|
||||
} else {
|
||||
msg = append(msg, summaryMsg...)
|
||||
}
|
||||
}
|
||||
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) {
|
||||
msg, err := cfg.GetDetailMessage(ctx.State["regex_matched"].([]string)[2])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(msg...)
|
||||
}
|
||||
|
||||
func handleArticle(ctx *zero.Ctx) {
|
||||
card, err := bz.GetArticleInfo(ctx.State["regex_matched"].([]string)[1])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(card.ToArticleMessage(ctx.State["regex_matched"].([]string)[1])...)
|
||||
}
|
||||
|
||||
func handleLive(ctx *zero.Ctx) {
|
||||
cookie, err := cfg.Load()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
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视频总结
|
||||
func getVideoSummary(cookiecfg *bz.CookieConfig, card bz.Card) (msg []message.Segment, err error) {
|
||||
var (
|
||||
data []byte
|
||||
videoSummary bz.VideoSummary
|
||||
)
|
||||
data, err = web.RequestDataWithHeaders(web.NewDefaultClient(), bz.SignURL(fmt.Sprintf(bz.VideoSummaryURL, card.BvID, card.CID, card.Owner.Mid)), "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, &videoSummary)
|
||||
msg = make([]message.Segment, 0, 16)
|
||||
msg = append(msg, message.Text("已为你生成视频总结\n\n"))
|
||||
msg = append(msg, message.Text(videoSummary.Data.ModelResult.Summary, "\n\n"))
|
||||
for _, v := range videoSummary.Data.ModelResult.Outline {
|
||||
msg = append(msg, message.Text("● ", v.Title, "\n"))
|
||||
for _, p := range v.PartOutline {
|
||||
msg = append(msg, message.Text(fmt.Sprintf("%d:%d %s\n", p.Timestamp/60, p.Timestamp%60, p.Content)))
|
||||
}
|
||||
msg = append(msg, message.Text("\n"))
|
||||
}
|
||||
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 bilibili
|
||||
// Package bilibilipush b站推送
|
||||
package bilibilipush
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -24,7 +24,7 @@ import (
|
||||
const (
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
|
||||
referer = "https://space.bilibili.com/%v"
|
||||
infoURL = "https://api.bilibili.com/x/space/wbi/acc/info?mid=%v&token=&platform=web&web_location=1550101"
|
||||
infoURL = "https://api.bilibili.com/x/space/wbi/acc/info?mid=%v"
|
||||
)
|
||||
|
||||
// bdb bilibili推送数据库
|
||||
@ -34,10 +34,11 @@ var (
|
||||
lastTime = map[int64]int64{}
|
||||
liveStatus = map[int64]int{}
|
||||
upMap = map[int64]string{}
|
||||
cfg = bz.NewCookieConfig("data/Bilibili/config.json")
|
||||
)
|
||||
|
||||
func init() {
|
||||
en := control.Register("bilibilipush", &ctrl.Options[*zero.Ctx]{
|
||||
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "b站推送",
|
||||
Help: "- 添加b站订阅[uid|name]\n" +
|
||||
@ -46,8 +47,9 @@ func init() {
|
||||
"- 取消b站直播订阅[uid|name]\n" +
|
||||
"- b站推送列表\n" +
|
||||
"- [开启|关闭]艾特全体\n" +
|
||||
"Tips: 需要配合job一起使用, 全局只需要设置一个, 无视响应状态推送, 下为例子\n" +
|
||||
"记录在\"@every 5m\"触发的指令)\n" +
|
||||
"Tips: 需要先在 bilibili 插件中设置cookie\n" +
|
||||
"需要配合 job 插件一起使用, 全局只需要设置一个, 无视响应状态推送, 下为例子\n" +
|
||||
"记录在\"@every 5m\"触发的指令\n" +
|
||||
"拉取b站推送",
|
||||
PrivateDataFolder: "bilibilipush",
|
||||
})
|
||||
@ -74,9 +76,9 @@ func init() {
|
||||
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)
|
||||
name, err := getName(buid)
|
||||
name, err := getName(buid, cfg)
|
||||
if err != nil || name == "" {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@ -92,9 +94,9 @@ func init() {
|
||||
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)
|
||||
name, err := getName(buid)
|
||||
name, err := getName(buid, cfg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@ -109,9 +111,9 @@ func init() {
|
||||
}
|
||||
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)
|
||||
name, err := getName(buid)
|
||||
name, err := getName(buid, cfg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@ -126,13 +128,13 @@ func init() {
|
||||
}
|
||||
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)
|
||||
gid := ctx.Event.GroupID
|
||||
if gid == 0 {
|
||||
gid = -ctx.Event.UserID
|
||||
}
|
||||
name, err := getName(buid)
|
||||
name, err := getName(buid, cfg)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@ -199,10 +201,18 @@ func changeAtAll(gid int64, b int) (err error) {
|
||||
}
|
||||
|
||||
// 取得uid的名字
|
||||
func getName(buid int64) (name string, err error) {
|
||||
func getName(buid int64, cookiecfg *bz.CookieConfig) (name string, err error) {
|
||||
var ok bool
|
||||
if name, ok = upMap[buid]; !ok {
|
||||
data, err := web.RequestDataWithHeaders(web.NewDefaultClient(), bz.SignURL(fmt.Sprintf(infoURL, buid)), "GET", func(r *http.Request) error {
|
||||
if cookiecfg != nil {
|
||||
cookie := ""
|
||||
cookie, err = cookiecfg.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Header.Add("Cookie", cookie)
|
||||
}
|
||||
r.Header.Set("User-Agent", ua)
|
||||
return nil
|
||||
}, nil)
|
||||
@ -261,8 +271,19 @@ func unsubscribeLive(buid, groupid int64) (err error) {
|
||||
return bdb.insertOrUpdateLiveAndDynamic(bpMap)
|
||||
}
|
||||
|
||||
func getUserDynamicCard(buid int64) (cardList []gjson.Result, err error) {
|
||||
data, err := web.RequestDataWith(web.NewDefaultClient(), fmt.Sprintf(bz.SpaceHistoryURL, buid, 0), "GET", referer, ua, nil)
|
||||
func getUserDynamicCard(buid int64, cookiecfg *bz.CookieConfig) (cardList []gjson.Result, err error) {
|
||||
data, err := web.RequestDataWithHeaders(web.NewDefaultClient(), fmt.Sprintf(bz.SpaceHistoryURL, buid, 0), "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.Add("User-Agent", ua)
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -288,7 +309,7 @@ func sendDynamic(ctx *zero.Ctx) error {
|
||||
uids := bdb.getAllBuidByDynamic()
|
||||
for _, buid := range uids {
|
||||
time.Sleep(2 * time.Second)
|
||||
cardList, err := getUserDynamicCard(buid)
|
||||
cardList, err := getUserDynamicCard(buid, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -313,7 +334,7 @@ func sendDynamic(ctx *zero.Ctx) error {
|
||||
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
||||
return err
|
||||
}
|
||||
msg, err := dynamicCard2msg(&dc)
|
||||
msg, err := dc.ToMessage()
|
||||
if err != nil {
|
||||
err = errors.Errorf("动态%v的解析有问题,%v", cardList[i].Get("desc.dynamic_id_str"), err)
|
||||
return err
|
||||
@ -368,7 +389,7 @@ func sendLive(ctx *zero.Ctx) error {
|
||||
if lCover == "" {
|
||||
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(lTitle))
|
||||
msg = append(msg, message.Image(lCover))
|
||||
@ -379,7 +400,7 @@ func sendLive(ctx *zero.Ctx) error {
|
||||
switch {
|
||||
case gid > 0:
|
||||
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)
|
||||
case gid < 0:
|
||||
@ -1,4 +1,4 @@
|
||||
package bilibili
|
||||
package bilibilipush
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
@ -24,7 +25,7 @@ func init() {
|
||||
})
|
||||
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = engine.DataFolder() + "bookreview.db"
|
||||
db = sql.New(engine.DataFolder() + "bookreview.db")
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = engine.GetLazyData("bookreview.db", true)
|
||||
err := db.Open(time.Hour)
|
||||
|
||||
@ -7,11 +7,11 @@ type book struct {
|
||||
BookReview string `db:"bookreview"`
|
||||
}
|
||||
|
||||
var db = &sql.Sqlite{}
|
||||
var db sql.Sqlite
|
||||
|
||||
// 暂时随机选择一个书评
|
||||
func getBookReviewByKeyword(keyword string) (b book) {
|
||||
_ = db.Find("bookreview", &b, "where bookreview LIKE '%"+keyword+"%'")
|
||||
_ = db.Find("bookreview", &b, "WHERE bookreview LIKE ?", "%"+keyword+"%")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -1,139 +0,0 @@
|
||||
// Package cangtoushi 藏头诗
|
||||
package cangtoushi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/antchfx/htmlquery"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
"github.com/wdvxdr1123/ZeroBot/utils/helper"
|
||||
)
|
||||
|
||||
const (
|
||||
loginURL = "https://www.shicimingju.com/cangtoushi/"
|
||||
searchURL = "https://www.shicimingju.com/cangtoushi/index.html"
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"
|
||||
referer = "https://www.shicimingju.com/cangtoushi/index.html"
|
||||
)
|
||||
|
||||
var (
|
||||
gCurCookieJar *cookiejar.Jar
|
||||
csrf string
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "藏头诗, 藏尾诗",
|
||||
Help: "- 藏头诗[xxx]\n- 藏尾诗[xxx]",
|
||||
})
|
||||
engine.OnRegex(`藏头诗\s?([一-龥]{3,10})$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
kw := ctx.State["regex_matched"].([]string)[1]
|
||||
err := login()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
data, err := search(kw, "7", "0")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text, err := dealHTML(helper.BytesToString(data))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(text))
|
||||
})
|
||||
|
||||
engine.OnRegex(`藏尾诗\s?([一-龥]{3,10})$`).SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
kw := ctx.State["regex_matched"].([]string)[1]
|
||||
err := login()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
data, err := search(kw, "7", "2")
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
text, err := dealHTML(helper.BytesToString(data))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(text))
|
||||
})
|
||||
}
|
||||
|
||||
func login() error {
|
||||
gCurCookieJar, _ = cookiejar.New(nil)
|
||||
client := &http.Client{
|
||||
Jar: gCurCookieJar,
|
||||
}
|
||||
request, err := http.NewRequest("GET", loginURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.Header.Add("User-Agent", ua)
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response.Body.Close()
|
||||
doc, err := htmlquery.Parse(strings.NewReader(helper.BytesToString(data)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
csrf = htmlquery.SelectAttr(htmlquery.FindOne(doc, "//input[@name='_csrf']"), "value")
|
||||
return nil
|
||||
}
|
||||
|
||||
func search(kw, zishu, position string) (data []byte, err error) {
|
||||
postStr := fmt.Sprintf("_csrf=%s&kw=%s&zishu=%s&position=%s", url.QueryEscape(csrf), url.QueryEscape(kw), zishu, position)
|
||||
client := &http.Client{
|
||||
Jar: gCurCookieJar,
|
||||
}
|
||||
request, err := http.NewRequest("POST", searchURL, strings.NewReader(postStr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.Header.Add("Referer", referer)
|
||||
request.Header.Add("User-Agent", ua)
|
||||
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err = io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.Body.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func dealHTML(data string) (text string, err error) {
|
||||
doc, err := htmlquery.Parse(strings.NewReader(data))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
text = htmlquery.InnerText(htmlquery.FindOne(doc, "//div[@class='card']/div[@class='card']"))
|
||||
text = strings.ReplaceAll(text, " ", "")
|
||||
text = strings.Replace(text, "\n", "", 1)
|
||||
return text, nil
|
||||
}
|
||||
108
plugin/chatcount/chatcount.go
Normal file
108
plugin/chatcount/chatcount.go
Normal file
@ -0,0 +1,108 @@
|
||||
// Package chatcount 聊天时长统计
|
||||
package chatcount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
"github.com/FloatTech/rendercard"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
)
|
||||
|
||||
const (
|
||||
rankSize = 10
|
||||
)
|
||||
|
||||
func init() {
|
||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "聊天时长统计",
|
||||
Help: "- 查询水群@xxx\n- 查看水群排名",
|
||||
PrivateDataFolder: "chatcount",
|
||||
})
|
||||
go func() {
|
||||
ctdb = initialize(engine.DataFolder() + "chatcount.db")
|
||||
}()
|
||||
engine.OnMessage(zero.OnlyGroup).SetBlock(false).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
remindTime, remindFlag := ctdb.updateChatTime(ctx.Event.GroupID, ctx.Event.UserID)
|
||||
if remindFlag {
|
||||
ctx.SendChain(message.At(ctx.Event.UserID), message.Text(fmt.Sprintf("BOT提醒:你今天已经水群%d分钟了!", remindTime)))
|
||||
}
|
||||
})
|
||||
|
||||
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()
|
||||
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)))
|
||||
})
|
||||
engine.OnFullMatch("查看水群排名", zero.OnlyGroup).Limit(ctxext.LimitByGroup).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
chatTimeList := ctdb.getChatRank(ctx.Event.GroupID)
|
||||
if len(chatTimeList) == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 没有水群数据"))
|
||||
return
|
||||
}
|
||||
rankinfo := make([]*rendercard.RankInfo, len(chatTimeList))
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(len(chatTimeList))
|
||||
for i := 0; i < len(chatTimeList) && i < rankSize; i++ {
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
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: 可能被风控了"))
|
||||
}
|
||||
})
|
||||
}
|
||||
225
plugin/chatcount/model.go
Normal file
225
plugin/chatcount/model.go
Normal file
@ -0,0 +1,225 @@
|
||||
package chatcount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/RomiChan/syncx"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
const (
|
||||
chatInterval = 300
|
||||
)
|
||||
|
||||
var (
|
||||
// ctdb 聊天时长数据库全局变量
|
||||
ctdb *chattimedb
|
||||
// l 水群提醒时间提醒段,单位分钟
|
||||
l = newLeveler(60, 120, 180, 240, 300)
|
||||
)
|
||||
|
||||
// chattimedb 聊天时长数据库结构体
|
||||
type chattimedb struct {
|
||||
// ctdb.userTimestampMap 每个人发言的时间戳 key=groupID_userID
|
||||
userTimestampMap syncx.Map[string, int64]
|
||||
// ctdb.userTodayTimeMap 每个人今日水群时间 key=groupID_userID
|
||||
userTodayTimeMap syncx.Map[string, int64]
|
||||
// ctdb.userTodayMessageMap 每个人今日水群次数 key=groupID_userID
|
||||
userTodayMessageMap syncx.Map[string, int64]
|
||||
// db 数据库
|
||||
db *gorm.DB
|
||||
// chatmu 读写添加锁
|
||||
chatmu sync.Mutex
|
||||
}
|
||||
|
||||
// initialize 初始化
|
||||
func initialize(dbpath string) *chattimedb {
|
||||
var err error
|
||||
if _, err = os.Stat(dbpath); err != nil || os.IsNotExist(err) {
|
||||
// 生成文件
|
||||
f, err := os.Create(dbpath)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
}
|
||||
gdb, err := gorm.Open("sqlite3", dbpath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gdb.AutoMigrate(&chatTime{})
|
||||
return &chattimedb{
|
||||
db: gdb,
|
||||
}
|
||||
}
|
||||
|
||||
// Close 关闭
|
||||
func (ctdb *chattimedb) Close() error {
|
||||
db := ctdb.db
|
||||
return db.Close()
|
||||
}
|
||||
|
||||
// chatTime 聊天时长,时间的单位都是秒
|
||||
type chatTime struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
GroupID int64 `gorm:"column:group_id"`
|
||||
UserID int64 `gorm:"column:user_id"`
|
||||
TodayTime int64 `gorm:"-"`
|
||||
TodayMessage int64 `gorm:"-"`
|
||||
TotalTime int64 `gorm:"column:total_time;default:0"`
|
||||
TotalMessage int64 `gorm:"column:total_message;default:0"`
|
||||
}
|
||||
|
||||
// TableName 表名
|
||||
func (chatTime) TableName() string {
|
||||
return "chat_time"
|
||||
}
|
||||
|
||||
// updateChatTime 更新发言时间,todayTime的单位是分钟
|
||||
func (ctdb *chattimedb) updateChatTime(gid, uid int64) (remindTime int64, remindFlag bool) {
|
||||
ctdb.chatmu.Lock()
|
||||
defer ctdb.chatmu.Unlock()
|
||||
db := ctdb.db
|
||||
now := time.Now()
|
||||
keyword := fmt.Sprintf("%v_%v", gid, uid)
|
||||
ts, ok := ctdb.userTimestampMap.Load(keyword)
|
||||
if !ok {
|
||||
ctdb.userTimestampMap.Store(keyword, now.Unix())
|
||||
ctdb.userTodayMessageMap.Store(keyword, 1)
|
||||
return
|
||||
}
|
||||
lastTime := time.Unix(ts, 0)
|
||||
todayTime, _ := ctdb.userTodayTimeMap.Load(keyword)
|
||||
totayMessage, _ := ctdb.userTodayMessageMap.Load(keyword)
|
||||
// 这个消息数是必须统计的
|
||||
ctdb.userTodayMessageMap.Store(keyword, totayMessage+1)
|
||||
st := chatTime{
|
||||
GroupID: gid,
|
||||
UserID: uid,
|
||||
TotalTime: todayTime,
|
||||
TotalMessage: totayMessage,
|
||||
}
|
||||
|
||||
// 如果不是同一天,把TotalTime,TotalMessage重置
|
||||
if lastTime.YearDay() != now.YearDay() {
|
||||
if err := db.Model(&st).Where("group_id = ? and user_id = ?", gid, uid).First(&st).Error; err != nil {
|
||||
if gorm.IsRecordNotFoundError(err) {
|
||||
db.Model(&st).Create(&st)
|
||||
}
|
||||
} else {
|
||||
db.Model(&st).Where("group_id = ? and user_id = ?", gid, uid).Update(
|
||||
map[string]any{
|
||||
"total_time": st.TotalTime + todayTime,
|
||||
"total_message": st.TotalMessage + totayMessage,
|
||||
})
|
||||
}
|
||||
ctdb.userTimestampMap.Store(keyword, now.Unix())
|
||||
ctdb.userTodayTimeMap.Delete(keyword)
|
||||
ctdb.userTodayMessageMap.Delete(keyword)
|
||||
return
|
||||
}
|
||||
|
||||
userChatTime := int64(now.Sub(lastTime).Seconds())
|
||||
// 当聊天时间在一定范围内的话,则计入时长
|
||||
if userChatTime < chatInterval {
|
||||
ctdb.userTodayTimeMap.Store(keyword, todayTime+userChatTime)
|
||||
remindTime = (todayTime + userChatTime) / 60
|
||||
remindFlag = l.level(int((todayTime+userChatTime)/60)) > l.level(int(todayTime/60))
|
||||
}
|
||||
ctdb.userTimestampMap.Store(keyword, now.Unix())
|
||||
return
|
||||
}
|
||||
|
||||
// getChatTime 获得用户聊天时长和消息次数,todayTime,totalTime的单位是秒,todayMessage,totalMessage单位是条数
|
||||
func (ctdb *chattimedb) getChatTime(gid, uid int64) (todayTime, todayMessage, totalTime, totalMessage int64) {
|
||||
ctdb.chatmu.Lock()
|
||||
defer ctdb.chatmu.Unlock()
|
||||
db := ctdb.db
|
||||
st := chatTime{}
|
||||
db.Model(&st).Where("group_id = ? and user_id = ?", gid, uid).First(&st)
|
||||
keyword := fmt.Sprintf("%v_%v", gid, uid)
|
||||
todayTime, _ = ctdb.userTodayTimeMap.Load(keyword)
|
||||
todayMessage, _ = ctdb.userTodayMessageMap.Load(keyword)
|
||||
totalTime = st.TotalTime
|
||||
totalMessage = st.TotalMessage
|
||||
return
|
||||
}
|
||||
|
||||
// getChatRank 获得水群排名,时间单位为秒
|
||||
func (ctdb *chattimedb) getChatRank(gid int64) (chatTimeList []chatTime) {
|
||||
ctdb.chatmu.Lock()
|
||||
defer ctdb.chatmu.Unlock()
|
||||
chatTimeList = make([]chatTime, 0, 100)
|
||||
keyList := make([]string, 0, 100)
|
||||
ctdb.userTimestampMap.Range(func(key string, value int64) bool {
|
||||
t := time.Unix(value, 0)
|
||||
if strings.Contains(key, strconv.FormatInt(gid, 10)) && t.YearDay() == time.Now().YearDay() {
|
||||
keyList = append(keyList, key)
|
||||
}
|
||||
return true
|
||||
})
|
||||
for _, v := range keyList {
|
||||
_, a, _ := strings.Cut(v, "_")
|
||||
uid, _ := strconv.ParseInt(a, 10, 64)
|
||||
todayTime, _ := ctdb.userTodayTimeMap.Load(v)
|
||||
todayMessage, _ := ctdb.userTodayMessageMap.Load(v)
|
||||
chatTimeList = append(chatTimeList, chatTime{
|
||||
GroupID: gid,
|
||||
UserID: uid,
|
||||
TodayTime: todayTime,
|
||||
TodayMessage: todayMessage,
|
||||
})
|
||||
}
|
||||
sort.Sort(sortChatTime(chatTimeList))
|
||||
return
|
||||
}
|
||||
|
||||
// leveler 结构体,包含一个 levelArray 字段
|
||||
type leveler struct {
|
||||
levelArray []int
|
||||
}
|
||||
|
||||
// newLeveler 构造函数,用于创建 Leveler 实例
|
||||
func newLeveler(levels ...int) *leveler {
|
||||
return &leveler{
|
||||
levelArray: levels,
|
||||
}
|
||||
}
|
||||
|
||||
// level 方法,封装了 getLevel 函数的逻辑
|
||||
func (l *leveler) level(t int) int {
|
||||
for i := len(l.levelArray) - 1; i >= 0; i-- {
|
||||
if t >= l.levelArray[i] {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// sortChatTime chatTime排序数组
|
||||
type sortChatTime []chatTime
|
||||
|
||||
// Len 实现 sort.Interface
|
||||
func (a sortChatTime) Len() int {
|
||||
return len(a)
|
||||
}
|
||||
|
||||
// Less 实现 sort.Interface,按 TodayTime 降序,TodayMessage 降序
|
||||
func (a sortChatTime) Less(i, j int) bool {
|
||||
if a[i].TodayTime == a[j].TodayTime {
|
||||
return a[i].TodayMessage > a[j].TodayMessage
|
||||
}
|
||||
return a[i].TodayTime > a[j].TodayTime
|
||||
}
|
||||
|
||||
// Swap 实现 sort.Interface
|
||||
func (a sortChatTime) Swap(i, j int) {
|
||||
a[i], a[j] = a[j], a[i]
|
||||
}
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
@ -35,16 +34,7 @@ var (
|
||||
Brief: "国际象棋",
|
||||
Help: helpString,
|
||||
PrivateDataFolder: "chess",
|
||||
}).ApplySingle(single.New(
|
||||
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("有操作正在执行, 请稍后再试..."),
|
||||
),
|
||||
)
|
||||
}),
|
||||
))
|
||||
}).ApplySingle(ctxext.GroupSingle)
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@ -168,7 +168,7 @@ func resign(groupCode, senderUin int64) (msg message.Message, err error) {
|
||||
}
|
||||
|
||||
// play 走棋
|
||||
func play(senderUin int64, groupCode int64, moveStr string) (msg message.Message, err error) {
|
||||
func play(groupCode, senderUin int64, moveStr string) (msg message.Message, err error) {
|
||||
msg = message.Message{message.At(senderUin)}
|
||||
// 检查对局是否存在
|
||||
room, ok := chessRoomMap.Load(groupCode)
|
||||
@ -235,7 +235,7 @@ func play(senderUin int64, groupCode int64, moveStr string) (msg message.Message
|
||||
chessRoomMap.Store(groupCode, room)
|
||||
}
|
||||
// 生成棋盘图片
|
||||
var boardImgEle message.MessageSegment
|
||||
var boardImgEle message.Segment
|
||||
if !room.isBlindfold {
|
||||
boardImgEle, err = getBoardElement(groupCode)
|
||||
if err != nil {
|
||||
@ -343,7 +343,7 @@ func cleanUserRate(senderUin int64) (msg message.Message, err error) {
|
||||
}
|
||||
|
||||
// createGame 创建游戏
|
||||
func createGame(isBlindfold bool, groupCode int64, senderUin int64, senderName string) (msg message.Message, err error) {
|
||||
func createGame(isBlindfold bool, groupCode, senderUin int64, senderName string) (msg message.Message, err error) {
|
||||
room, ok := chessRoomMap.Load(groupCode)
|
||||
if !ok {
|
||||
chessRoomMap.Store(groupCode, &chessRoom{
|
||||
@ -400,7 +400,7 @@ func createGame(isBlindfold bool, groupCode int64, senderUin int64, senderName s
|
||||
room.blackPlayer = senderUin
|
||||
room.blackName = senderName
|
||||
chessRoomMap.Store(groupCode, room)
|
||||
var boardImgEle message.MessageSegment
|
||||
var boardImgEle message.Segment
|
||||
if !room.isBlindfold {
|
||||
boardImgEle, err = getBoardElement(groupCode)
|
||||
if err != nil {
|
||||
@ -442,7 +442,7 @@ func abortGame(room chessRoom, groupCode int64, hint string) (message.Message, e
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
)
|
||||
@ -23,7 +24,7 @@ func init() {
|
||||
|
||||
en.OnRegex("^抽象翻译((\\s|[\\r\\n]|[\\p{Han}\\p{P}A-Za-z0-9])+)$",
|
||||
fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = en.DataFolder() + "cxh.db"
|
||||
db = sql.New(en.DataFolder() + "cxh.db")
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = en.GetLazyData("cxh.db", true)
|
||||
err := db.Open(time.Hour)
|
||||
|
||||
@ -11,11 +11,11 @@ type emoji struct {
|
||||
Emoji string `db:"emoji"`
|
||||
}
|
||||
|
||||
var db = &sql.Sqlite{}
|
||||
var db sql.Sqlite
|
||||
|
||||
func getPinyinByWord(word string) string {
|
||||
var p pinyin
|
||||
_ = db.Find("pinyin", &p, "where word = '"+word+"'")
|
||||
_ = db.Find("pinyin", &p, "WHERE word = ?", word)
|
||||
return p.Pronun
|
||||
}
|
||||
|
||||
@ -25,6 +25,6 @@ func getPronunByDWord(w0, w1 rune) string {
|
||||
|
||||
func getEmojiByPronun(pronun string) string {
|
||||
var e emoji
|
||||
_ = db.Find("emoji", &e, "where pronunciation = '"+pronun+"'")
|
||||
_ = db.Find("emoji", &e, "WHERE pronunciation = ?", pronun)
|
||||
return e.Emoji
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ import (
|
||||
|
||||
var (
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36"
|
||||
coserURL = "http://ovooa.com/API/cosplay/api.php"
|
||||
coserURL = "https://picture.yinux.workers.dev"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/math"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
)
|
||||
@ -24,7 +25,7 @@ func init() {
|
||||
})
|
||||
|
||||
getdb := fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
db.DBPath = engine.DataFolder() + "cp.db"
|
||||
db = sql.New(engine.DataFolder() + "cp.db")
|
||||
// os.RemoveAll(dbpath)
|
||||
_, _ = engine.GetLazyData("cp.db", true)
|
||||
err := db.Open(time.Hour)
|
||||
|
||||
@ -9,7 +9,7 @@ type cpstory struct {
|
||||
Story string `db:"story"`
|
||||
}
|
||||
|
||||
var db = &sql.Sqlite{}
|
||||
var db sql.Sqlite
|
||||
|
||||
func getRandomCpStory() (cs cpstory) {
|
||||
_ = 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"
|
||||
"github.com/FloatTech/floatbox/process"
|
||||
sql "github.com/FloatTech/sqlite"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
@ -29,7 +30,7 @@ func init() {
|
||||
})
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
|
||||
@ -8,9 +8,9 @@ type curse struct {
|
||||
Level string `db:"level"`
|
||||
}
|
||||
|
||||
var db = &sql.Sqlite{}
|
||||
var db sql.Sqlite
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -2,16 +2,14 @@
|
||||
package dailynews
|
||||
|
||||
import (
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
const api = "http://dwz.2xb.cn/zaob"
|
||||
const api = "https://uapis.cn/api/v1/daily/news-image"
|
||||
|
||||
func init() {
|
||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
@ -24,14 +22,10 @@ func init() {
|
||||
engine.OnFullMatch(`今日早报`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
data, err := web.GetData(api)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
picURL := gjson.Get(binary.BytesToString(data), "imageUrl").String()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image(picURL))
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
})
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package deepdanbooru
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"net/url"
|
||||
@ -59,8 +60,12 @@ func tagurl(name, u string) (im image.Image, st *sorttags, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(data) < 4 {
|
||||
err = errors.New("data too short")
|
||||
return
|
||||
}
|
||||
tags := make(map[string]float64)
|
||||
err = json.Unmarshal(data, &tags)
|
||||
err = json.Unmarshal(data[1:len(data)-1], &tags)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ type text struct {
|
||||
// LoadText 加载小作文
|
||||
func LoadText(dbfile string) error {
|
||||
_, err := file.GetLazyData(dbfile, control.Md5File, false)
|
||||
db.DBPath = dbfile
|
||||
db = sql.New(dbfile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -63,7 +63,7 @@ func RandText() string {
|
||||
// HentaiText 发大病
|
||||
func HentaiText() string {
|
||||
var t text
|
||||
err := db.Find("text", &t, "where id = -3802576048116006195")
|
||||
err := db.Find("text", &t, "WHERE id = -3802576048116006195")
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
package dish
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -25,7 +24,7 @@ type dish struct {
|
||||
}
|
||||
|
||||
var (
|
||||
db = &sql.Sqlite{}
|
||||
db sql.Sqlite
|
||||
initialized = false
|
||||
)
|
||||
|
||||
@ -37,7 +36,7 @@ func init() {
|
||||
PublicDataFolder: "Dish",
|
||||
})
|
||||
|
||||
db.DBPath = en.DataFolder() + "dishes.db"
|
||||
db = sql.New(en.DataFolder() + "dishes.db")
|
||||
|
||||
if _, err := en.GetLazyData("dishes.db", true); err != nil {
|
||||
logrus.Warnln("[dish]获取菜谱数据库文件失败")
|
||||
@ -62,7 +61,7 @@ func init() {
|
||||
return
|
||||
}
|
||||
|
||||
name := ctx.NickName()
|
||||
name := ctx.CardOrNickName(ctx.Event.UserID)
|
||||
dishName := ctx.State["args"].(string)
|
||||
|
||||
if dishName == "" {
|
||||
@ -77,26 +76,25 @@ func init() {
|
||||
}
|
||||
|
||||
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))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SendChain(message.Text(fmt.Sprintf(
|
||||
"已为客官%s找到%s的做法辣!\n"+
|
||||
"原材料:%s\n"+
|
||||
"步骤:\n"+
|
||||
"%s",
|
||||
name, dishName, d.Materials, d.Steps),
|
||||
ctx.SendChain(message.Text(
|
||||
"已为客官", name, "找到", d.Name, "的做法辣!\n",
|
||||
"原材料:", d.Materials, "\n",
|
||||
"步骤:", d.Steps,
|
||||
))
|
||||
})
|
||||
|
||||
en.OnPrefixGroup([]string{"随机菜谱", "随便做点菜"}).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
en.OnFullMatchGroup([]string{"随机菜谱", "随便做点菜"}).SetBlock(true).Limit(ctxext.LimitByUser).Handle(func(ctx *zero.Ctx) {
|
||||
if !initialized {
|
||||
ctx.SendChain(message.Text("客官,本店暂未开业"))
|
||||
return
|
||||
}
|
||||
|
||||
name := ctx.NickName()
|
||||
name := ctx.CardOrNickName(ctx.Event.UserID)
|
||||
var d dish
|
||||
if err := db.Pick("dish", &d); err != nil {
|
||||
ctx.SendChain(message.Text("小店好像出错了,暂时端不出菜来惹"))
|
||||
@ -104,12 +102,10 @@ func init() {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SendChain(message.Text(fmt.Sprintf(
|
||||
"已为客官%s送上%s的做法:\n"+
|
||||
"原材料:%s\n"+
|
||||
"步骤:\n"+
|
||||
"%s",
|
||||
name, d.Name, d.Materials, d.Steps),
|
||||
ctx.SendChain(message.Text(
|
||||
"已为客官", name, "送上", d.Name, "的做法:\n",
|
||||
"原材料:", d.Materials, "\n",
|
||||
"步骤:", d.Steps,
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@ -5,13 +5,15 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/gif"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
fcext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/FloatTech/imgfactory"
|
||||
@ -89,7 +91,7 @@ func init() {
|
||||
ctx.SendChain(message.Reply(ctx.Event.MessageID), message.Image("file:///"+picPath))
|
||||
return
|
||||
}
|
||||
lotsImg, err := randGif(lotsType + "." + fileInfo.lotsType)
|
||||
lotsImg, err := randGif(lotsType+"."+fileInfo.lotsType, ctx.Event.UserID)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
@ -228,27 +230,48 @@ func randFile(path string, indexMax int) (string, error) {
|
||||
return "", errors.New("图包[" + path + "]不存在签内容!")
|
||||
}
|
||||
|
||||
func randGif(gifName string) (image.Image, error) {
|
||||
func randGif(gifName string, uid int64) (image.Image, error) {
|
||||
name := datapath + gifName
|
||||
file, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
im, err := gif.DecodeAll(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = file.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config, err := gif.DecodeConfig(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = file.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// https://zhuanlan.zhihu.com/p/27718135
|
||||
rect := image.Rect(0, 0, config.Width, config.Height)
|
||||
if rect.Min == rect.Max {
|
||||
var maxP image.Point
|
||||
for _, frame := range im.Image {
|
||||
maxF := frame.Bounds().Max
|
||||
if maxP.X < maxF.X {
|
||||
maxP.X = maxF.X
|
||||
}
|
||||
/*
|
||||
firstImg, err := imgfactory.Load(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if maxP.Y < maxF.Y {
|
||||
maxP.Y = maxF.Y
|
||||
}
|
||||
v := im.Image[rand.Intn(len(im.Image))]
|
||||
return imgfactory.Size(firstImg, firstImg.Bounds().Dx(), firstImg.Bounds().Dy()).InsertUpC(v, 0, 0, firstImg.Bounds().Dx()/2, firstImg.Bounds().Dy()/2).Clone().Image(),err
|
||||
/*/
|
||||
// 如果gif图片出现信息缺失请使用上面注释掉的代码,把下面注释了(上面代码部分图存在bug)
|
||||
v := im.Image[rand.Intn(len(im.Image))]
|
||||
return imgfactory.NewFactoryBG(v.Rect.Dx(), v.Rect.Dy(), color.NRGBA{0, 0, 0, 255}).InsertUp(v, 0, 0, 0, 0).Clone().Image(), err
|
||||
// */
|
||||
}
|
||||
rect.Max = maxP
|
||||
}
|
||||
img := image.NewRGBA(rect)
|
||||
b := fcext.RandSenderPerDayN(uid, len(im.Image)) + 1
|
||||
a := 0
|
||||
if b > 8 {
|
||||
a = b - 8
|
||||
}
|
||||
for _, srcimg := range im.Image[a:b] {
|
||||
draw.Draw(img, srcimg.Bounds(), srcimg, srcimg.Rect.Min, draw.Over)
|
||||
}
|
||||
return img, err
|
||||
}
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
package dress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const (
|
||||
dressURL = "http://www.yoooooooooo.com/gitdress"
|
||||
male = "dress"
|
||||
female = "girldress"
|
||||
dressListURL = dressURL + "/%v/album/list.json"
|
||||
dressDetailURL = dressURL + "/%v/album/%v/info.json"
|
||||
dressImageURL = dressURL + "/%v/album/%v/%v-m.webp"
|
||||
)
|
||||
|
||||
func dressList(sex string) (dressList []string, err error) {
|
||||
data, err := web.GetData(fmt.Sprintf(dressListURL, sex))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
arr := gjson.ParseBytes(data).Get("@this").Array()
|
||||
dressList = make([]string, len(arr))
|
||||
for i, v := range arr {
|
||||
dressList[i] = v.String()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func detail(sex, name string) (count int, err error) {
|
||||
data, err := web.GetData(fmt.Sprintf(dressDetailURL, sex, name))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
count = int(gjson.ParseBytes(data).Get("@this.#").Int())
|
||||
return
|
||||
}
|
||||
@ -1,113 +0,0 @@
|
||||
// Package dress 女装
|
||||
package dress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/floatbox/binary"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "女装",
|
||||
Help: "女装\n" +
|
||||
"- 女装\n" +
|
||||
"- 男装\n" +
|
||||
"- 随机女装\n" +
|
||||
"- 随机男装",
|
||||
PrivateDataFolder: "dress",
|
||||
})
|
||||
engine.OnFullMatchGroup([]string{"女装", "男装"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
matched := ctx.State["matched"].(string)
|
||||
sex := male
|
||||
if matched == "男装" {
|
||||
sex = female
|
||||
}
|
||||
next := zero.NewFutureEvent("message", 999, false, ctx.CheckSession())
|
||||
recv, cancel := next.Repeat()
|
||||
defer cancel()
|
||||
nameList, err := dressList(sex)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
tex := "请输入" + matched + "序号\n"
|
||||
for i, v := range nameList {
|
||||
tex += fmt.Sprintf("%d. %s\n", i, v)
|
||||
}
|
||||
base64Str, err := text.RenderToBase64(tex, text.FontFile, 400, 20)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("base64://" + binary.BytesToString(base64Str)))
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second * 120):
|
||||
ctx.SendChain(message.Text(matched, "指令过期"))
|
||||
return
|
||||
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 >= len(nameList) {
|
||||
ctx.SendChain(message.Text("序号非法!"))
|
||||
continue
|
||||
}
|
||||
name := nameList[num]
|
||||
sendImage(ctx, sex, matched, name)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
engine.OnFullMatchGroup([]string{"随机女装", "随机男装"}).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
matched := strings.TrimPrefix(ctx.State["matched"].(string), "随机")
|
||||
sex := male
|
||||
if matched == "男装" {
|
||||
sex = female
|
||||
}
|
||||
nameList, err := dressList(sex)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
name := nameList[rand.Intn(len(nameList))]
|
||||
sendImage(ctx, sex, matched, name)
|
||||
})
|
||||
}
|
||||
|
||||
func sendImage(ctx *zero.Ctx, sex, matched, name string) {
|
||||
ctx.SendChain(message.Text("请欣赏", matched, ": ", name))
|
||||
count, err := detail(sex, name)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
imageList := make([]string, count)
|
||||
for i := range imageList {
|
||||
imageList[i] = fmt.Sprintf(dressImageURL, sex, name, i+1)
|
||||
}
|
||||
m := message.Message{}
|
||||
for _, v := range imageList {
|
||||
m = append(m, ctxext.FakeSenderForwardNode(ctx, message.Image(v)))
|
||||
}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,7 @@ type sea struct {
|
||||
Time string `db:"time"` // we need to know the current time,master>
|
||||
}
|
||||
|
||||
var seaSide = &sql.Sqlite{}
|
||||
var seaSide sql.Sqlite
|
||||
var seaLocker sync.RWMutex
|
||||
|
||||
// We need a container to inject what we need :(
|
||||
@ -39,15 +39,15 @@ func init() {
|
||||
Help: "- @bot pick" + "- @bot throw xxx (xxx为投递内容)",
|
||||
PrivateDataFolder: "driftbottle",
|
||||
})
|
||||
seaSide.DBPath = en.DataFolder() + "sea.db"
|
||||
seaSide = sql.New(en.DataFolder() + "sea.db")
|
||||
err := seaSide.Open(time.Hour)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_ = createChannel(seaSide)
|
||||
_ = createChannel(&seaSide)
|
||||
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 {
|
||||
ctx.SendChain(message.Text("ERR:", err))
|
||||
}
|
||||
@ -75,7 +75,7 @@ func init() {
|
||||
senderFormatTime,
|
||||
ctx.CardOrNickName(ctx.Event.UserID),
|
||||
rawMessageCallBack,
|
||||
).throw(seaSide)
|
||||
).throw(&seaSide)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
|
||||
@ -195,55 +195,3 @@ var emojis = map[rune]int64{
|
||||
127819: 20210521, // 🍋 lemon
|
||||
127818: 20211115, // 🍊 tangerine orange
|
||||
}
|
||||
|
||||
var qqface = map[int]rune{
|
||||
0: 128558, // 😮 face exhaling
|
||||
1: 128556, // 😬 grimacing face
|
||||
2: 128525, // 😍 smiling face with heart-eyes
|
||||
4: 128526, // 😎 smiling face with sunglasses
|
||||
5: 128557, // 😭 loudly crying face
|
||||
6: 129402, // 🥺 pleading face
|
||||
7: 129296, // 🤐 zipper-mouth face
|
||||
8: 128554, // 😪 sleepy face
|
||||
11: 128545, // 😡 pouting face
|
||||
12: 128539, // 😛 face with tongue
|
||||
13: 128513, // 😁 beaming face with smiling eyes
|
||||
14: 128578, // 🙂 slightly smiling face
|
||||
15: 128577, // 🙁 slightly frowning face
|
||||
16: 128526, // 😎 smiling face with sunglasses
|
||||
19: 129326, // 🤮 face vomiting throw
|
||||
20: 129325, // 🤭 face with hand over mouth embarrassed
|
||||
21: 128522, // 😊 smiling face with smiling eyes
|
||||
23: 128533, // 😕 confused face
|
||||
24: 128523, // 😋 face savoring food
|
||||
27: 128531, // 😓 downcast face with sweat
|
||||
28: 128516, // 😄 grinning face with smiling eyes
|
||||
31: 129324, // 🤬 face with symbols on mouth
|
||||
32: 129300, // 🤔 thinking face question hmmm
|
||||
33: 129323, // 🤫 shushing face quiet whisper
|
||||
34: 128565, // 😵 face with crossed-out eyes
|
||||
35: 128547, // 😣 persevering face
|
||||
37: 128128, // 💀 skull
|
||||
46: 128055, // 🐷 pig face
|
||||
53: 127874, // 🎂 birthday cake
|
||||
59: 128169, // 💩 pile of poo
|
||||
60: 9749, // ☕ hot beverage coffee cup tea
|
||||
63: 127801, // 🌹 rose flower
|
||||
66: 10084, // ❤ mending heart
|
||||
67: 128148, // 💔 broken heart
|
||||
69: 127873, // 🎁 wrapped-gift
|
||||
74: 127774, // 🌞 sun with face
|
||||
75: 127772, // 🌜 last quarter moon face
|
||||
96: 128517, // 😅 grinning face with sweat
|
||||
104: 129393, // 🥱 yawning face
|
||||
109: 128535, // 😗 kissing face
|
||||
110: 128562, // 😲 astonished face
|
||||
111: 129402, // 🥺 pleading face
|
||||
172: 128539, // 😛 face with tongue
|
||||
182: 128514, // 😂 face with tears of joy
|
||||
187: 128123, // 👻 ghost
|
||||
247: 128567, // 😷 face with medical mask
|
||||
272: 128579, // 🙃 upside-down face
|
||||
320: 129395, // 🥳 partying face
|
||||
325: 128561, // 😱 face screaming in fear
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ func match(ctx *zero.Ctx) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func face2emoji(face message.MessageSegment) rune {
|
||||
func face2emoji(face message.Segment) rune {
|
||||
if face.Type == "text" {
|
||||
r := []rune(face.Data["text"])
|
||||
if len(r) != 1 {
|
||||
@ -94,7 +94,7 @@ func face2emoji(face message.MessageSegment) rune {
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
if r, ok := qqface[id]; ok {
|
||||
if r, ok := message.Emoji[id]; ok {
|
||||
return r
|
||||
}
|
||||
return 0
|
||||
|
||||
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))
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -154,7 +154,7 @@ func init() {
|
||||
_, err = draw(background, fontdata, title, text, f)
|
||||
_ = f.Close()
|
||||
return err
|
||||
}, ctxext.Send(ctx), ctxext.GetMessage(ctx))
|
||||
}, ctxext.Send(ctx))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
|
||||
@ -21,7 +21,7 @@ type joke struct {
|
||||
Text string `db:"text"`
|
||||
}
|
||||
|
||||
var db = &sql.Sqlite{}
|
||||
var db sql.Sqlite
|
||||
|
||||
func init() {
|
||||
en := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
@ -32,7 +32,7 @@ func init() {
|
||||
})
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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()
|
||||
target := datapath + `materials/` + name
|
||||
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 {
|
||||
_ = os.Remove(target)
|
||||
exit(err)
|
||||
@ -48,7 +48,7 @@ func dlchan(name string, s *string, wg *sync.WaitGroup, exit func(error)) {
|
||||
func dlblock(name string) (string, error) {
|
||||
target := datapath + `materials/` + name
|
||||
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 {
|
||||
_ = os.Remove(target)
|
||||
return "", err
|
||||
@ -87,13 +87,13 @@ func dlrange(prefix string, end int, wg *sync.WaitGroup, exit func(error)) []str
|
||||
}
|
||||
|
||||
// 新的上下文
|
||||
func newContext(user int64) *context {
|
||||
func newContext(user int64, atUser int64) *context {
|
||||
c := new(context)
|
||||
c.usrdir = datapath + "users/" + strconv.FormatInt(user, 10) + `/`
|
||||
c.usrdir = datapath + "users/" + strconv.FormatInt(atUser, 10) + `/`
|
||||
_ = os.MkdirAll(c.usrdir, 0755)
|
||||
c.headimgsdir = make([]string, 2)
|
||||
c.headimgsdir[0] = c.usrdir + "0.gif"
|
||||
c.headimgsdir[1] = c.usrdir + "1.gif"
|
||||
c.headimgsdir[0] = datapath + "users/" + strconv.FormatInt(atUser, 10) + ".gif"
|
||||
c.headimgsdir[1] = datapath + "users/" + strconv.FormatInt(user, 10) + ".gif"
|
||||
return c
|
||||
}
|
||||
|
||||
|
||||
@ -14,9 +14,9 @@ func (cc *context) prepareLogos(s ...string) error {
|
||||
for i, v := range s {
|
||||
_, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
err = file.DownloadTo("https://gchat.qpic.cn/gchatpic_new//--"+strings.ToUpper(v)+"/0", cc.usrdir+strconv.Itoa(i)+".gif")
|
||||
err = file.DownloadTo("https://gchat.qpic.cn/gchatpic_new//--"+strings.ToUpper(v)+"/0", cc.headimgsdir[i])
|
||||
} else {
|
||||
err = file.DownloadTo("http://q4.qlogo.cn/g?b=qq&nk="+v+"&s=640", cc.usrdir+strconv.Itoa(i)+".gif")
|
||||
err = file.DownloadTo("https://q4.qlogo.cn/g?b=qq&nk="+v+"&s=640", cc.headimgsdir[i])
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -150,10 +150,11 @@ func init() { // 插件主体
|
||||
PrivateDataFolder: "gif",
|
||||
}).ApplySingle(ctxext.DefaultSingle)
|
||||
datapath = file.BOTPATH + "/" + en.DataFolder()
|
||||
en.OnRegex(`^(` + strings.Join(cmd, "|") + `)[\s\S]*?(\[CQ:(image\,file=([0-9a-zA-Z]{32}).*|at.+?(\d{5,11}))\].*|(\d+))$`).
|
||||
en.OnRegex(`^(` + strings.Join(cmd, "|") + `)[\s\S]*?(\[CQ:(image\,file=([0-9a-zA-Z]{32}).*|at.+?qq=(\d{5,11})).*\].*|(\d+))$`).
|
||||
SetBlock(true).Handle(func(ctx *zero.Ctx) {
|
||||
c := newContext(ctx.Event.UserID)
|
||||
list := ctx.State["regex_matched"].([]string)
|
||||
atUserID, _ := strconv.ParseInt(list[4]+list[5]+list[6], 10, 64)
|
||||
c := newContext(ctx.Event.UserID, atUserID)
|
||||
err := c.prepareLogos(list[4]+list[5]+list[6], strconv.FormatInt(ctx.Event.UserID, 10))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
|
||||
@ -2,15 +2,14 @@
|
||||
package github
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/fumiama/terasu/http2"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
@ -26,14 +25,14 @@ func init() { // 插件主体
|
||||
}).OnRegex(`^>github\s(-.{1,10}? )?(.*)$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
// 发送请求
|
||||
header := http.Header{
|
||||
"User-Agent": []string{"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36"},
|
||||
}
|
||||
api, _ := url.Parse("https://api.github.com/search/repositories")
|
||||
api.RawQuery = url.Values{
|
||||
"q": []string{ctx.State["regex_matched"].([]string)[2]},
|
||||
}.Encode()
|
||||
body, err := netGet(api.String(), header)
|
||||
body, err := web.RequestDataWithHeaders(&http2.DefaultClient, api.String(), "GET", func(r *http.Request) error {
|
||||
r.Header.Set("User-Agent", web.RandUA())
|
||||
return nil
|
||||
}, nil)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
}
|
||||
@ -96,36 +95,9 @@ func init() { // 插件主体
|
||||
}
|
||||
|
||||
// notnull 如果传入文本为空,则返回默认值
|
||||
|
||||
func notnull(text string) string {
|
||||
if text == "" {
|
||||
return "None"
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
// netGet 返回请求结果
|
||||
func netGet(dest string, header http.Header) ([]byte, error) {
|
||||
client := &http.Client{}
|
||||
|
||||
req, err := http.NewRequest("GET", dest, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header = header
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if code := resp.StatusCode; code != 200 {
|
||||
// 如果返回不是200则立刻抛出错误
|
||||
errmsg := fmt.Sprintf("code %d", code)
|
||||
return nil, errors.New(errmsg)
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
@ -246,11 +246,7 @@ func init() {
|
||||
ctx.SendChain(message.Text(serviceErr, err))
|
||||
return
|
||||
}
|
||||
if err == nil {
|
||||
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).
|
||||
|
||||
@ -11,16 +11,28 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/pkg/errors"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/liuzl/gocc"
|
||||
)
|
||||
|
||||
var cuttime = [...]string{"00:00:05", "00:00:30", "00:01:00"} // 音乐切割时间点,可自行调节时间(时:分:秒)
|
||||
var t2s *gocc.OpenCC
|
||||
|
||||
func init() {
|
||||
// 初始化简繁体转换变量
|
||||
var err1 error
|
||||
t2s, err1 = gocc.New("t2s")
|
||||
if err1 != nil {
|
||||
log.Infof("[guessmusic]:%s", err1)
|
||||
}
|
||||
|
||||
engine.OnRegex(`^(个人|团队)猜歌(-(.*))?$`, zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByGroup).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
mode := ctx.State["regex_matched"].([]string)[3]
|
||||
@ -97,6 +109,12 @@ func init() {
|
||||
ctx.SendChain(message.Text(err))
|
||||
return
|
||||
}
|
||||
// 猜歌环节-提供猜歌选项
|
||||
files, err := os.ReadDir(pathOfMusic)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
getMusicSelect(ctx, files, musicName)
|
||||
// 进行猜歌环节
|
||||
ctx.SendChain(message.Record("file:///" + file.BOTPATH + "/" + outputPath + "0.wav"))
|
||||
var next *zero.FutureEvent
|
||||
@ -112,7 +130,7 @@ func init() {
|
||||
after := time.NewTimer(120 * time.Second)
|
||||
wg := sync.WaitGroup{}
|
||||
var (
|
||||
messageStr message.MessageSegment // 文本信息
|
||||
messageStr message.Segment // 文本信息
|
||||
tickCount = 0 // 音频数量
|
||||
answerCount = 0 // 问答次数
|
||||
win bool // 是否赢得游戏
|
||||
@ -209,26 +227,8 @@ func musicLottery(musicPath, listName string) (pathOfMusic, musicName string, er
|
||||
}
|
||||
return
|
||||
}
|
||||
// 进行随机抽取
|
||||
if playlistID == 0 || !cfg.API {
|
||||
// 只猜本地已经下好的歌曲
|
||||
musicName = getLocalMusic(files, 10)
|
||||
} else {
|
||||
switch rand.Intn(3) { // 三分二概率抽取API的
|
||||
case 1:
|
||||
musicName = getLocalMusic(files, 10)
|
||||
default:
|
||||
if cfg.APIURL == "" {
|
||||
// 如果没有配置过API地址,尝试连接独角兽
|
||||
musicName, err = downloadByOvooa(playlistID, pathOfMusic)
|
||||
} else {
|
||||
// 从API中抽取歌曲
|
||||
musicName, err = drawByAPI(playlistID, pathOfMusic)
|
||||
}
|
||||
if err != nil {
|
||||
musicName = getLocalMusic(files, 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
if musicName == "" {
|
||||
err = errors.New("抽取歌曲轮空了,请重试")
|
||||
}
|
||||
@ -281,12 +281,15 @@ 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 = ConvertText(answer)
|
||||
|
||||
switch {
|
||||
case answer == "取消":
|
||||
if c.Event.UserID == beginner {
|
||||
return message.Text("游戏已取消,猜歌答案是\n", musicInfo[len(musicInfo)-1], "\n\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
|
||||
return message.Text("游戏已取消,猜歌答案是\n", musicInfo[len(musicInfo)-1], "\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
|
||||
}
|
||||
return message.Text("你无权限取消"), answerTimes, tickTimes, false
|
||||
case answer == "提示":
|
||||
@ -295,11 +298,11 @@ func gameMatch(c *zero.Ctx, beginner int64, musicInfo []string, answerTimes, tic
|
||||
return message.Text("已经没有提示了哦"), answerTimes, tickTimes, false
|
||||
}
|
||||
return message.Text("再听这段音频,要仔细听哦"), answerTimes, tickTimes, false
|
||||
case strings.Contains(musicInfo[0], answer) || strings.EqualFold(musicInfo[0], answer):
|
||||
case strings.Contains(ConvertText(musicInfo[0]), answer) || strings.EqualFold(ConvertText(musicInfo[0]), answer):
|
||||
return message.Text("太棒了,你猜对歌曲名了!答案是\n", musicInfo[len(musicInfo)-1], "\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
|
||||
case strings.Contains(musicInfo[1], answer) || strings.EqualFold(musicInfo[1], answer):
|
||||
case strings.Contains(ConvertText(musicInfo[1]), answer) || strings.EqualFold(ConvertText(musicInfo[1]), answer):
|
||||
return message.Text("太棒了,你猜对歌手名了!答案是\n", musicInfo[len(musicInfo)-1], "\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
|
||||
case len(musicInfo) == 4 && (strings.Contains(musicInfo[2], answer) || strings.EqualFold(musicInfo[2], answer)):
|
||||
case len(musicInfo) == 4 && (strings.Contains(ConvertText(musicInfo[2]), answer) || strings.EqualFold(ConvertText(musicInfo[2]), answer)):
|
||||
return message.Text("太棒了,你猜对相关信息了!答案是\n", musicInfo[len(musicInfo)-1], "\n\n下面欣赏猜歌的歌曲"), answerTimes, tickTimes, true
|
||||
default:
|
||||
answerTimes++
|
||||
@ -314,3 +317,51 @@ func gameMatch(c *zero.Ctx, beginner int64, musicInfo []string, answerTimes, tic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ConvertText 将传入字符串中的英文转为小写,繁体中文转为简体中文
|
||||
func ConvertText(input string) string {
|
||||
// 将字符串中的英文转为小写
|
||||
toLower := strings.ToLower(input)
|
||||
toLower, err := t2s.Convert(toLower)
|
||||
if err != nil {
|
||||
message.Text("简繁转换失败")
|
||||
return toLower
|
||||
}
|
||||
return toLower
|
||||
}
|
||||
|
||||
func getMusicSelect(ctx *zero.Ctx, files []fs.DirEntry, musicName string) {
|
||||
// 生成音乐选项
|
||||
var musicInfo []string
|
||||
musicInfo = append(musicInfo, musicName)
|
||||
for i := 1; i < 4; i++ {
|
||||
musicInfo = append(musicInfo, getLocalMusic(files, 10))
|
||||
for musicInfo[0] == musicInfo[i] {
|
||||
musicInfo[i] = getLocalMusic(files, 10)
|
||||
}
|
||||
}
|
||||
// 对调正确答案
|
||||
j := rand.Intn(len(musicInfo))
|
||||
musicInfo[0], musicInfo[j] = musicInfo[j], musicInfo[0]
|
||||
|
||||
musicNameSelect := "请选出正确歌曲:\n"
|
||||
for i := 0; i < len(musicInfo); i++ {
|
||||
// 解析歌曲信息
|
||||
music := strings.Split(musicInfo[i], ".")
|
||||
// 获取音乐后缀
|
||||
musicType := music[len(music)-1]
|
||||
if !strings.Contains(musictypelist, musicType) {
|
||||
ctx.SendChain(message.Text("抽取到了歌曲:\n",
|
||||
musicInfo[i], "\n该歌曲不是音乐后缀,请联系bot主人修改"))
|
||||
}
|
||||
// 获取音乐信息
|
||||
musicInfo := strings.Split(strings.ReplaceAll(musicInfo[i], "."+musicType, ""), " - ")
|
||||
infoNum := len(musicInfo)
|
||||
if infoNum == 1 {
|
||||
ctx.SendChain(message.Text("抽取到了歌曲:\n",
|
||||
musicInfo[i], "\n该歌曲命名不符合命名规则,请联系bot主人修改"))
|
||||
}
|
||||
musicNameSelect += musicInfo[0] + " 歌手:" + musicInfo[1] + "\n"
|
||||
}
|
||||
ctx.SendChain(message.Text(musicNameSelect))
|
||||
}
|
||||
|
||||
@ -15,7 +15,6 @@ import (
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
"github.com/pkg/errors"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/extension/single"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
// 图片输出
|
||||
@ -32,7 +31,7 @@ var (
|
||||
cfg config
|
||||
// 插件主体
|
||||
engine = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
DisableOnDefault: true,
|
||||
Brief: "猜歌插件",
|
||||
Help: "------bot主人指令------\n" +
|
||||
"- 设置猜歌歌库路径 [绝对路径]\n" +
|
||||
@ -65,17 +64,7 @@ var (
|
||||
"- 下载歌单[网易云歌单链接/ID]到[歌单名称]\n" +
|
||||
"- 解除绑定 [歌单名称]",
|
||||
PrivateDataFolder: "guessmusic",
|
||||
}).ApplySingle(single.New(
|
||||
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("已经有正在进行的游戏..."),
|
||||
),
|
||||
)
|
||||
}),
|
||||
))
|
||||
}).ApplySingle(ctxext.NewGroupSingle("已经有正在进行的游戏..."))
|
||||
// 用于存放歌曲三个片段的缓存文件夹
|
||||
cachePath = engine.DataFolder() + "cache/"
|
||||
// 用于存放用户的配置
|
||||
@ -535,7 +524,7 @@ func getFileURLbyFileName(ctx *zero.Ctx, fileName string) (fileSearchName, fileU
|
||||
for _, fileNameOflist := range files {
|
||||
if strings.Contains(fileNameOflist.Get("file_name").String(), fileName) {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -561,7 +550,7 @@ func getFileURLbyfolderID(ctx *zero.Ctx, fileName, folderid string) (fileSearchN
|
||||
for _, fileNameOflist := range files {
|
||||
if strings.Contains(fileNameOflist.Get("file_name").String(), fileName) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,9 +241,9 @@ type listInfoOfAPI struct {
|
||||
PublishTime int64 `json:"publishTime"`
|
||||
Tns []string `json:"tns,omitempty"`
|
||||
} `json:"tracks"`
|
||||
VideoIds interface{} `json:"videoIds"`
|
||||
VideoIDs interface{} `json:"videoIds"`
|
||||
Videos interface{} `json:"videos"`
|
||||
TrackIds []struct {
|
||||
TrackIDs []struct {
|
||||
ID int `json:"id"`
|
||||
V int `json:"v"`
|
||||
T int `json:"t"`
|
||||
|
||||
@ -1,119 +0,0 @@
|
||||
// Package heisi 黑丝
|
||||
package heisi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/FloatTech/AnimeAPI/setu"
|
||||
fbctxext "github.com/FloatTech/floatbox/ctxext"
|
||||
"github.com/FloatTech/floatbox/file"
|
||||
"github.com/FloatTech/floatbox/web"
|
||||
ctrl "github.com/FloatTech/zbpctrl"
|
||||
"github.com/FloatTech/zbputils/control"
|
||||
"github.com/FloatTech/zbputils/ctxext"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
var (
|
||||
heisiPic []item
|
||||
baisiPic []item
|
||||
jkPic []item
|
||||
jurPic []item
|
||||
zukPic []item
|
||||
mcnPic []item
|
||||
fileList = [...]string{"heisi.bin", "baisi.bin", "jk.bin", "jur.bin", "zuk.bin", "mcn.bin"}
|
||||
)
|
||||
|
||||
func init() { // 插件主体
|
||||
p, err := setu.NewPool(setu.DefaultPoolDir,
|
||||
func(s string) (string, error) {
|
||||
if s != "黑丝" && s != "白丝" && s != "jk" && s != "巨乳" && s != "足控" && s != "网红" {
|
||||
return "", errors.New("invalid call")
|
||||
}
|
||||
typ := setu.DefaultPoolDir + "/" + s
|
||||
if file.IsNotExist(typ) {
|
||||
err := os.MkdirAll(typ, 0755)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
var pic item
|
||||
switch s {
|
||||
case "黑丝":
|
||||
pic = heisiPic[rand.Intn(len(heisiPic))]
|
||||
case "白丝":
|
||||
pic = baisiPic[rand.Intn(len(baisiPic))]
|
||||
case "jk":
|
||||
pic = jkPic[rand.Intn(len(jkPic))]
|
||||
case "巨乳":
|
||||
pic = jurPic[rand.Intn(len(jurPic))]
|
||||
case "足控":
|
||||
pic = zukPic[rand.Intn(len(zukPic))]
|
||||
case "网红":
|
||||
pic = mcnPic[rand.Intn(len(mcnPic))]
|
||||
}
|
||||
return pic.String(), nil
|
||||
}, func(s string) ([]byte, error) {
|
||||
return web.RequestDataWith(web.NewTLS12Client(), s, "GET", "http://hs.heisiwu.com/", web.RandUA(), nil)
|
||||
}, time.Minute)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
|
||||
DisableOnDefault: false,
|
||||
Brief: "黑丝",
|
||||
Help: "- 来点黑丝\n- 来点白丝\n- 来点jk\n- 来点巨乳\n- 来点足控\n- 来点网红",
|
||||
PublicDataFolder: "Heisi",
|
||||
})
|
||||
|
||||
engine.OnFullMatchGroup([]string{"来点黑丝", "来点白丝", "来点jk", "来点巨乳", "来点足控", "来点网红"}, zero.OnlyGroup, fbctxext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
|
||||
for i, filePath := range fileList {
|
||||
data, err := engine.GetLazyData(filePath, true)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return false
|
||||
}
|
||||
if len(data)%10 != 0 {
|
||||
ctx.SendChain(message.Text("ERROR: invalid data " + strconv.Itoa(i)))
|
||||
return false
|
||||
}
|
||||
s := (*slice)(unsafe.Pointer(&data))
|
||||
s.len /= 10
|
||||
s.cap /= 10
|
||||
switch i {
|
||||
case 0:
|
||||
heisiPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 1:
|
||||
baisiPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 2:
|
||||
jkPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 3:
|
||||
jurPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 4:
|
||||
zukPic = *(*[]item)(unsafe.Pointer(s))
|
||||
case 5:
|
||||
mcnPic = *(*[]item)(unsafe.Pointer(s))
|
||||
}
|
||||
}
|
||||
return true
|
||||
})).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
matched := ctx.State["matched"].(string)
|
||||
pic, err := p.Roll(matched[3*2:])
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR: ", err))
|
||||
return
|
||||
}
|
||||
m := message.Message{ctxext.FakeSenderForwardNode(ctx, message.Image("file:///"+file.BOTPATH+"/"+pic))}
|
||||
if id := ctx.Send(m).ID(); id == 0 {
|
||||
ctx.SendChain(message.Text("ERROR: 可能被风控或下载图片用时过长,请耐心等待"))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
package heisi
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
const (
|
||||
template2021 = "http://hs.heisiwu.com/wp-content/uploads/%4d/%02d/%4d%02d16%06d-611a3%8s.jpg"
|
||||
templategeneral = "http://hs.heisiwu.com/wp-content/uploads/%4d/%02d/%015x"
|
||||
)
|
||||
|
||||
type item [10]byte
|
||||
|
||||
// String item to url
|
||||
func (it item) String() string {
|
||||
year, month := int((it[0]>>4)&0x0f), int(it[0]&0x0f)
|
||||
year += 2021
|
||||
if year == 2021 {
|
||||
num := binary.BigEndian.Uint32(it[1:5])
|
||||
dstr := hex.EncodeToString(it[5:9])
|
||||
return fmt.Sprintf(template2021, year, month, year, month, num, dstr)
|
||||
}
|
||||
d := binary.BigEndian.Uint64(it[1:9])
|
||||
isscaled := it[9]&0x80 > 0
|
||||
num := int(it[9] & 0x7f)
|
||||
trestore := fmt.Sprintf(templategeneral, year, month, d&0x0fffffff_ffffffff)
|
||||
if num > 0 {
|
||||
trestore += fmt.Sprintf("-%d", num)
|
||||
}
|
||||
if isscaled {
|
||||
trestore += "-scaled"
|
||||
}
|
||||
d = bits.RotateLeft64(d, 4) & 0x0f
|
||||
switch d {
|
||||
case 0:
|
||||
trestore += ".jpg"
|
||||
case 1:
|
||||
trestore += ".png"
|
||||
case 2:
|
||||
trestore += ".webp"
|
||||
default:
|
||||
return "invalid ext"
|
||||
}
|
||||
return trestore
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package heisi
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// slice is the runtime representation of a slice.
|
||||
// It cannot be used safely or portably and its representation may
|
||||
// change in a later release.
|
||||
//
|
||||
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
|
||||
// data it references will not be garbage collected.
|
||||
type slice struct {
|
||||
data unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user