Compare commits

...

51 Commits

Author SHA1 Message Date
github-actions[bot]
9cb3a5019f
chore(nix): bump deps (#1282)
Some checks failed
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
PushLint / lint (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-01 01:13:50 +08:00
源文雨
d5729b4e27 🔖 v1.10.18 2026-02-01 01:08:32 +08:00
github-actions[bot]
7f4830d50f
chore(nix): bump deps (#1279)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-01 00:46:18 +08:00
源文雨
39d319bf70 🔖 v1.10.17 2026-02-01 00:40:20 +08:00
源文雨
1dd94c2d37 fix(aichat): concurrent map write 2026-02-01 00:39:20 +08:00
Nobody6825
f6934709cc
fix: fix nix build error (#1280)
Some checks are pending
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
2026-01-30 23:18:10 +08:00
源文雨
1c8ff7b143 fix(aichat): possible panic when save mem err
Some checks failed
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2026-01-28 21:33:41 +08:00
github-actions[bot]
79080cc2f0
chore(nix): bump deps (#1278)
Some checks failed
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
PushLint / lint (push) Has been cancelled
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-24 14:29:55 +08:00
himawari
e59ab9f798
🐛修复点歌 (#1277) 2026-01-24 14:26:53 +08:00
源文雨
37dfad9a29 optimize: move console into ab
Some checks failed
自动更新 nix 依赖 / gomod2nix update (push) Has been cancelled
最新版 / Build binary CI (386, linux) (push) Has been cancelled
最新版 / Build binary CI (386, windows) (push) Has been cancelled
最新版 / Build binary CI (amd64, linux) (push) Has been cancelled
最新版 / Build binary CI (amd64, windows) (push) Has been cancelled
最新版 / Build binary CI (arm, linux) (push) Has been cancelled
最新版 / Build binary CI (arm64, linux) (push) Has been cancelled
PushLint / lint (push) Has been cancelled
2026-01-17 21:33:39 +08:00
github-actions[bot]
d84a4a57a8
chore(nix): bump deps (#1274)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-17 21:25:57 +08:00
源文雨
bb14767829 chore: make lint happy? 2026-01-17 21:25:33 +08:00
源文雨
dcb83bbeee fix(aichat): concurrent map w/r 2026-01-17 21:21:39 +08:00
github-actions[bot]
add70383c9
chore(nix): bump deps (#1271)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-17 21:04:49 +08:00
源文雨
d43239841d 🔖1.10.16 2026-01-17 21:01:05 +08:00
github-actions[bot]
a3115da138
chore(lint): 改进代码样式 (#1270)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-17 18:46:01 +08:00
github-actions[bot]
454425daf2
chore(nix): bump deps (#1269)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-17 18:44:02 +08:00
源文雨
d8c4aa82e3 🔖1.10.15 2026-01-17 18:43:44 +08:00
源文雨
6fe621fbfe chore: make lint happy 2026-01-17 18:43:16 +08:00
源文雨
f27e603e39 feat(aichat): agent +more configs & fix too long log evs 2026-01-17 18:37:56 +08:00
github-actions[bot]
ec8c402593
chore(lint): 改进代码样式 (#1268)
Some checks are pending
自动更新 nix 依赖 / gomod2nix update (push) Waiting to run
最新版 / Build binary CI (386, linux) (push) Waiting to run
最新版 / Build binary CI (386, windows) (push) Waiting to run
最新版 / Build binary CI (amd64, linux) (push) Waiting to run
最新版 / Build binary CI (amd64, windows) (push) Waiting to run
最新版 / Build binary CI (arm, linux) (push) Waiting to run
最新版 / Build binary CI (arm64, linux) (push) Waiting to run
PushLint / lint (push) Waiting to run
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-17 12:26:02 +08:00
github-actions[bot]
be42865c2a
chore(lint): 改进代码样式 (#1267)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-17 12:13:31 +08:00
github-actions[bot]
ac2d9bb596
chore(nix): bump deps (#1266)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-17 12:13:08 +08:00
源文雨
b025ca5738 🔖1.10.14 2026-01-17 12:00:28 +08:00
源文雨
4fd22ee7c7 fix(aichat): agent may consume too many tokens 2026-01-17 11:59:45 +08:00
fumiama
e4fede7a75
feat(aichat): remove unnecessary ensure cfg (#1265) 2026-01-13 18:01:29 +08:00
github-actions[bot]
4fa79497da
chore(nix): bump deps (#1264)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-11 23:57:24 +08:00
源文雨
8bf1f0b221 🔖 v1.10.13 2026-01-11 23:54:12 +08:00
源文雨
7d231dfd8d fix(aichat): agent may panic on logev 2026-01-11 23:51:04 +08:00
github-actions[bot]
c8d30b9f06
chore(nix): bump deps (#1263)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-09 21:16:42 +08:00
github-actions[bot]
1e6bc9abdd
chore(nix): bump deps (#1261)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-09 21:10:20 +08:00
github-actions[bot]
625ed39d13
chore(lint): 改进代码样式 (#1262)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-09 21:10:03 +08:00
源文雨
55e538cdb6 🔖 v1.10.12 2026-01-09 21:09:33 +08:00
fumiama
b432731c9b
feat(aichat): agent reduce log evs (#1260) 2026-01-09 14:14:34 +08:00
github-actions[bot]
d14e1be92b
chore(nix): bump deps (#1259)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-09 00:14:26 +08:00
源文雨
6c4c4770f9 🔖 v1.10.11 2026-01-09 00:11:55 +08:00
源文雨
213b4e21ad fix(aichat): agent eventt log 2026-01-09 00:11:32 +08:00
github-actions[bot]
fafbc8165e
chore(nix): bump deps (#1258)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-08 23:14:34 +08:00
源文雨
981f4c5dd7 🔖 v1.10.10 2026-01-08 23:10:33 +08:00
源文雨
d1abd3e1d5 fix(aichat): log message may panic 2026-01-08 23:09:57 +08:00
github-actions[bot]
6d30750f42
chore(nix): bump deps (#1257)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-07 00:47:03 +08:00
源文雨
78e1aa6783 feat(aichat): force cut multi calls 2026-01-07 00:45:12 +08:00
源文雨
9bfaa0c195 feat(aichat): force cut multi calls 2026-01-06 23:29:48 +08:00
源文雨
36397fb583 feat(aichat): force cut multi calls 2026-01-06 23:16:41 +08:00
源文雨
ae165349b9 feat(aichat): add iter to agent 2026-01-06 22:28:11 +08:00
源文雨
1584ab8b11 🔖 v1.10.9 2026-01-06 21:25:08 +08:00
源文雨
5283e6de61 feat(aichat): add more options 2026-01-06 21:24:31 +08:00
Kajiekazz
caa66d6715
feat(wife): game use Gaussian blur (#1254) 2026-01-06 00:47:53 +08:00
github-actions[bot]
f77d9b3509
chore(nix): bump deps (#1252)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-01-05 00:51:49 +08:00
源文雨
afc1e034e0 🔖1.10.8 2026-01-05 00:50:54 +08:00
源文雨
67c36aab29 fix(aichat): agent cannot stop 2026-01-05 00:49:16 +08:00
27 changed files with 417 additions and 409 deletions

View File

@ -20,10 +20,10 @@ jobs:
fetch-depth: 0
submodules: 'recursive'
- name: Tidy Modules
- name: Prepare Necessary Runtime Files
run: |
go mod tidy
go generate main.go
go mod tidy
- name: Run Lint
uses: golangci/golangci-lint-action@master

View File

@ -1633,6 +1633,12 @@ print("run[CQ:image,file="+j["img"]+"]")
- [x] 设置AI聊天最大长度4096
- [x] 设置AI聊天TopP 0.9
- [x] 设置AI聊天(不)以AI语音输出
- [x] 设置AI聊天Agent性格
- [x] 查看AI聊天Agent性格
- [x] 设置AI聊天Agent性别
- [x] 查看AI聊天Agent性别
- [x] 重置AI聊天Agent性格性别
- [x] 重置AI聊天Agent
- [x] 查看AI聊天配置
- [x] 重置AI聊天

View File

@ -1,7 +1,6 @@
//go:build !windows
// Package console sets console's behavior on init
package console
package abineundo
import (
"fmt"

View File

@ -1,5 +1,4 @@
// Package console sets console's behavior on init
package console
package abineundo
import (
"bytes"

View File

@ -9,7 +9,7 @@
//
// 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.
// plugin priority and setup console properties.
//
// Typical usage:
//

View File

@ -18,9 +18,9 @@ buildGoApplication {
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;
go = pkgs.go_1_24;
preBuild = ''
go generate main.go
'';
modules = ./gomod2nix.toml;
}

View File

@ -28,11 +28,11 @@
]
},
"locked": {
"lastModified": 1742209644,
"narHash": "sha256-jMy1XqXqD0/tJprEbUmKilTkvbDY/C0ZGSsJJH4TNCE=",
"lastModified": 1767019875,
"narHash": "sha256-NodN+lhWTD59b44Q2bPjE1edINfjfRkQYdZsrxifCeU=",
"owner": "nix-community",
"repo": "gomod2nix",
"rev": "8f3534eb8f6c5c3fce799376dc3b91bae6b11884",
"rev": "49662a44272806ff785df2990a420edaaca15db4",
"type": "github"
},
"original": {
@ -43,11 +43,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1745391562,
"narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
"lastModified": 1769461804,
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
"type": "github"
},
"original": {
@ -57,28 +57,11 @@
"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"
"nixpkgs": "nixpkgs"
}
},
"systems": {

109
flake.nix
View File

@ -1,7 +1,6 @@
{
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";
@ -11,53 +10,85 @@
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;
}: (flake-utils.lib.eachDefaultSystem (
system: let
pkgs = nixpkgs.legacyPackages.${system};
overlays = [
(_: _: {
go_1_20 = old-nixpkgs.go_1_20;
})
callPackage = pkgs.callPackage;
# Simple test check added to nix flake check
go-test = pkgs.stdenvNoCC.mkDerivation {
name = "go-test";
dontBuild = true;
src = ./.;
doCheck = true;
nativeBuildInputs = with pkgs; [
go
writableTmpDirAsHomeHook
];
checkPhase = ''
go test -v ./...
'';
installPhase = ''
mkdir "$out"
'';
};
# 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
];
# Simple lint check added to nix flake check
go-lint = pkgs.stdenvNoCC.mkDerivation {
name = "go-lint";
dontBuild = true;
src = ./.;
doCheck = true;
nativeBuildInputs = with pkgs; [
golangci-lint
go
writableTmpDirAsHomeHook
];
checkPhase = ''
golangci-lint run
'';
installPhase = ''
mkdir "$out"
'';
};
# doCheck will fail at download files
ZeroBot-Plugin = (callPackage ./. {
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
}).overrideAttrs (_: {doCheck = false;});
# Build container layered image, useful overtime to save storage on duplicated layers
containerImage = pkgs.dockerTools.buildLayeredImage {
name = "ZeroBot-Plugin";
tag = "latest";
created = "now";
contents = [
pkgs.cacert
pkgs.openssl
];
config = {
Cmd = ["${ZeroBot-Plugin}/bin/ZeroBot-Plugin"];
};
};
in {
inherit containerImage;
checks = {
inherit go-test go-lint;
};
packages.default = ZeroBot-Plugin;
devShells.default = callPackage ./shell.nix {
inherit (gomod2nix.legacyPackages.${system}) mkGoEnv gomod2nix;
};
# Custom application to build and load container image into the docker daemon
# For now docker is a requirement
apps.build-and-load = {
type = "app";
program = "${pkgs.writeShellScriptBin "build-and-load" ''
nix build .#containerImage.${system}
docker load < result
echo "Container image loaded"
''}/bin/build-and-load";
};
formatter = pkgs.alejandra;
})
);
}
));
}

9
go.mod
View File

@ -12,7 +12,7 @@ require (
github.com/FloatTech/sqlite v1.7.2
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d
github.com/FloatTech/zbpctrl v1.7.1
github.com/FloatTech/zbputils v1.7.2-0.20260103151557-34c60f3591d5
github.com/FloatTech/zbputils v1.7.2-0.20260131170726-494cb1776a47
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
@ -24,7 +24,7 @@ require (
github.com/fumiama/cron v1.3.0
github.com/fumiama/deepinfra v0.0.0-20251221163610-e98ee3ba437a
github.com/fumiama/go-base16384 v1.7.1
github.com/fumiama/go-onebot-agent v0.0.0-20260103153303-915960b3a069
github.com/fumiama/go-onebot-agent v0.0.0-20260128132028-05e6b4809f0a
github.com/fumiama/go-registry v0.2.7
github.com/fumiama/gotracemoe v0.0.3
github.com/fumiama/imgsz v0.0.4
@ -34,6 +34,7 @@ require (
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/guohuiyuan/music-lib v1.0.2-0.20260121020416-53f6cb24629d
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
@ -44,10 +45,10 @@ require (
github.com/notnil/chess v1.10.0
github.com/pkg/errors v0.9.1
github.com/shirou/gopsutil/v4 v4.25.12
github.com/sirupsen/logrus v1.9.3
github.com/sirupsen/logrus v1.9.4
github.com/tidwall/gjson v1.18.0
github.com/wcharczuk/go-chart/v2 v2.1.2
github.com/wdvxdr1123/ZeroBot v1.8.3-0.20260103120253-8a8f1347f983
github.com/wdvxdr1123/ZeroBot v1.8.3-0.20260117102541-393033a35adb
gitlab.com/gomidi/midi/v2 v2.3.18
golang.org/x/image v0.34.0
golang.org/x/sys v0.39.0

20
go.sum
View File

@ -16,8 +16,8 @@ github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d h1:mUQ/c3wXKsUGa4Sg9
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
github.com/FloatTech/zbpctrl v1.7.1 h1:0yPEmCForhyMbnhTckmjDUFFDZgQp1RjO2bVF4ZVqOs=
github.com/FloatTech/zbpctrl v1.7.1/go.mod h1:xmM4dSwHA02Gei3ogCRiG+RTrw/7Z69PfrN5NYf8BPE=
github.com/FloatTech/zbputils v1.7.2-0.20260103151557-34c60f3591d5 h1:kN8EtrKmcK1g+WMb2czOLpiNyagljO7f9BqdK6KcAaY=
github.com/FloatTech/zbputils v1.7.2-0.20260103151557-34c60f3591d5/go.mod h1:1qUet9ztj6DMabvtCNl4vVwb6mVSYUHeAbpkY3CBMvk=
github.com/FloatTech/zbputils v1.7.2-0.20260131170726-494cb1776a47 h1:slMr6r4XDKnYCFmWhcHA02O3MTAUnU8p2gEe843JyQA=
github.com/FloatTech/zbputils v1.7.2-0.20260131170726-494cb1776a47/go.mod h1:W2kaR/A5oUtEb7DnveXCc0T374VjI+f3KmOWH9FE5vU=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
@ -67,8 +67,8 @@ github.com/fumiama/deepinfra v0.0.0-20251221163610-e98ee3ba437a h1:a0+2vaXajfxsN
github.com/fumiama/deepinfra v0.0.0-20251221163610-e98ee3ba437a/go.mod h1:uqsWK/GM9OvKV0pXZOQB63rWugBbiXInY8E1JoRKhkg=
github.com/fumiama/go-base16384 v1.7.1 h1:1P1x6FWRvd7PtbH4idDAGWAjKKcVxggxlROYKRXbw58=
github.com/fumiama/go-base16384 v1.7.1/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
github.com/fumiama/go-onebot-agent v0.0.0-20260103153303-915960b3a069 h1:s+0YH5thC576Lggf7v3SBN3RQYDMytS5ZtKCMMtuY1E=
github.com/fumiama/go-onebot-agent v0.0.0-20260103153303-915960b3a069/go.mod h1:rTrS23rvTYuZcSngENJTvcBFTz1nGsImSv+bW7yfhqs=
github.com/fumiama/go-onebot-agent v0.0.0-20260128132028-05e6b4809f0a h1:8GYo5nctK2si5WDNX0WmZTxY7TWXRjAOBu5pjK7GDW0=
github.com/fumiama/go-onebot-agent v0.0.0-20260128132028-05e6b4809f0a/go.mod h1:rTrS23rvTYuZcSngENJTvcBFTz1nGsImSv+bW7yfhqs=
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=
@ -117,6 +117,8 @@ 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/guohuiyuan/music-lib v1.0.2-0.20260121020416-53f6cb24629d h1:6Cw52c4JaYvq55yAa9ZgUQeBL6b3ZWErQqkbeMZiAYw=
github.com/guohuiyuan/music-lib v1.0.2-0.20260121020416-53f6cb24629d/go.mod h1:D/6kQDwhQFDNZEMjN8y760DQSVYpOGlQXrYzhKz0rCQ=
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=
@ -182,11 +184,10 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/shirou/gopsutil/v4 v4.25.12 h1:e7PvW/0RmJ8p8vPGJH4jvNkOyLmbkXgXW4m6ZPic6CY=
github.com/shirou/gopsutil/v4 v4.25.12/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/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
@ -206,8 +207,8 @@ github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9R
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.3-0.20260103120253-8a8f1347f983 h1:hb2FUDooAf3u32wCTgJcBBuGPZF1sjgj8NfJaSy529s=
github.com/wdvxdr1123/ZeroBot v1.8.3-0.20260103120253-8a8f1347f983/go.mod h1:trueIIVRywKJa3ov4QphzVvzYzgCNrlXdf9JvPJOFW8=
github.com/wdvxdr1123/ZeroBot v1.8.3-0.20260117102541-393033a35adb h1:pwmyrnnMzb0WygAwUgXoZckzJkusK4WSaXxXqsIJYmU=
github.com/wdvxdr1123/ZeroBot v1.8.3-0.20260117102541-393033a35adb/go.mod h1:kCLja2sXXgbBTsEOyBNCuT4z9tI+URQ2y0q/GGXprzU=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
@ -268,7 +269,6 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -29,8 +29,8 @@ schema = 3
version = "v1.7.1"
hash = "sha256-wkeiaUTpPVbpH7fcXeoLtG+aGIMJbvoc/9sbi2IXK0I="
[mod."github.com/FloatTech/zbputils"]
version = "v1.7.2-0.20260103151557-34c60f3591d5"
hash = "sha256-kcGgD6boOTkZ+x0lXwgkuNY3zJfh+L867gK9SkhyKk4="
version = "v1.7.2-0.20260131170726-494cb1776a47"
hash = "sha256-KLhPEHoJiq2qVkK+7OVy7Wc2wpCFEJOqa/0zZGQ8TnM="
[mod."github.com/PuerkitoBio/goquery"]
version = "v1.8.0"
hash = "sha256-I3QaPWATvBOL/F26fIiYWKS13yBUYo+9o3tcsGIu8tY="
@ -92,8 +92,8 @@ schema = 3
version = "v1.7.1"
hash = "sha256-Fd1QaeYx+3q4C3XQXlPFnDmKPsoZH6837fN/7rn8i9s="
[mod."github.com/fumiama/go-onebot-agent"]
version = "v0.0.0-20260103153303-915960b3a069"
hash = "sha256-hJHJXk9axVTKl4IwkIx+0jxZfTXRX1NcFzugfepSCbM="
version = "v0.0.0-20260128132028-05e6b4809f0a"
hash = "sha256-ratY7o52v0KuxgZC4wqHNXdgGXzliEecs8egE3SBLeo="
[mod."github.com/fumiama/go-registry"]
version = "v0.2.7"
hash = "sha256-Rjl+z0Hlp2LMi8+pnFe5HrxctyHMi7UPiK33g/OgLdA="
@ -142,6 +142,9 @@ schema = 3
[mod."github.com/gopxl/beep/v2"]
version = "v2.1.1"
hash = "sha256-JLCUJCG+VvNlVF296JWIOUvvUFHlqEAJvZfw853qwwU="
[mod."github.com/guohuiyuan/music-lib"]
version = "v1.0.2-0.20260121020416-53f6cb24629d"
hash = "sha256-juVJ/nh6zA5Gu5+dRzIx8tElXLscRQYwY9vLvVKh078="
[mod."github.com/jfreymuth/oggvorbis"]
version = "v1.0.5"
hash = "sha256-jphTCaPr34ZT9Id4ZZ6zU9Vnxzy6cTjCwjpQ819eGV0="
@ -224,8 +227,8 @@ schema = 3
version = "v4.25.12"
hash = "sha256-gzk9GW4+tXUWmxAVD3by/k4D/+l++TvajRVTkQJvwmM="
[mod."github.com/sirupsen/logrus"]
version = "v1.9.3"
hash = "sha256-EnxsWdEUPYid+aZ9H4/iMTs1XMvCLbXZRDyvj89Ebms="
version = "v1.9.4"
hash = "sha256-ltRvmtM3XTCAFwY0IesfRqYIivyXPPuvkFjL4ARh1wg="
[mod."github.com/tetratelabs/wazero"]
version = "v1.5.0"
hash = "sha256-fGdJM4LJrZA9jxHuYVo4EUQ3I1k0IVG3QQCBCgZkeZI="
@ -248,8 +251,8 @@ schema = 3
version = "v2.1.2"
hash = "sha256-GXWWea/u6BezTsPPrWhTYiTetPP/YW6P+Sj4YdocPaM="
[mod."github.com/wdvxdr1123/ZeroBot"]
version = "v1.8.3-0.20260103120253-8a8f1347f983"
hash = "sha256-/6biuhXUIYxyJ0uT1R5Yk8RD2cm9/SQWtFvcyQgnWJE="
version = "v1.8.3-0.20260117102541-393033a35adb"
hash = "sha256-Yz2OTU05kDZOHX8J04jX5Jg5ya9rwqsH0TySSBhMOp0="
[mod."github.com/yusufpapurcu/wmi"]
version = "v1.2.4"
hash = "sha256-N+YDBjOW59YOsZ2lRBVtFsEEi48KhNQRb63/0ZSU3bA="

View File

@ -3,13 +3,13 @@
package banner
// Version ...
var Version = "v1.10.7"
var Version = "v1.10.18"
// Copyright ...
var Copyright = "© 2020 - 2026 FloatTech"
// Banner ...
var Banner = "* OneBot + ZeroBot + Golang\n" +
"* Version " + Version + " - 2026-01-03 23:41:53 +0800 CST\n" +
"* Version " + Version + " - 2026-02-01 01:08:19 +0800 CST\n" +
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"

View File

@ -14,8 +14,7 @@ import (
"strings"
"time"
_ "github.com/FloatTech/ZeroBot-Plugin/abineundo" // 设置插件优先级
_ "github.com/FloatTech/ZeroBot-Plugin/console" // 更改控制台属性
_ "github.com/FloatTech/ZeroBot-Plugin/abineundo" // 设置插件优先级&更改控制台属性
"github.com/FloatTech/ZeroBot-Plugin/kanban" // 打印 banner
// ---------以下插件均可通过前面加 // 注释,注释后停用并不加载插件--------- //

View File

@ -6,6 +6,7 @@ import (
"math/rand"
"strings"
"github.com/RomiChan/syncx"
"github.com/fumiama/deepinfra"
goba "github.com/fumiama/go-onebot-agent"
"github.com/sirupsen/logrus"
@ -52,6 +53,11 @@ func init() {
logrus.Warnln("ERROR: cannot get stor")
return false
}
mp := ctx.State[control.StateKeySyncxState].(*syncx.Map[string, any])
if _, ok := mp.Load(chat.StateKeyAgentHooked); !ok && !stor.NoAgent() {
logrus.Infoln("[aichat] skip agent for ctx has not been hooked by agent")
return false
}
if !(ctx.ExtractPlainText() != "" &&
(!stor.NoReplyAt() || (stor.NoReplyAt() && !ctx.Event.IsToMe))) {
return false
@ -60,10 +66,6 @@ func init() {
if !ctx.Event.IsToMe && rand.Intn(100) >= int(rate) {
return false
}
if chat.AC.Key == "" {
logrus.Warnln("ERROR: get extra err: empty key")
return false
}
if ctx.Event.IsToMe {
ctx.Block()
}
@ -76,9 +78,10 @@ func init() {
stor := ctx.State[zero.StateKeyPrefixKeep+"aichatcfg_stor__"].(chat.Storage)
temperature := stor.Temp()
topp, maxn := chat.AC.MParams()
mp := ctx.State[control.StateKeySyncxState].(*syncx.Map[string, any])
logrus.Debugln("[aichat] agent mode test: noagent", stor.NoAgent(), "hasapi", chat.AC.AgentAPI != "", "hasmodel", chat.AC.AgentModelName != "")
if !stor.NoAgent() && chat.AC.AgentAPI != "" && chat.AC.AgentModelName != "" {
if !stor.NoAgent() && chat.AC.AgentAPI != "" && chat.AC.AgentModelName != "" && chat.AC.Key != "" {
logrus.Debugln("[aichat] enter agent mode")
x := deepinfra.NewAPI(chat.AC.AgentAPI, string(chat.AC.AgentKey))
mod, err := chat.AC.Type.Protocol(chat.AC.AgentModelName, temperature, topp, maxn)
@ -111,25 +114,44 @@ func init() {
ctx.NoTimeout()
logrus.Debugln("[aichat] agent set no timeout")
hasresp := false
// ispuremsg := false
// hassavemem := false
for i := 0; i < 8; i++ { // 最大运行 8 轮因为问答上下文只有 16
reqs := chat.CallAgent(ag, zero.SuperUserPermission(ctx), x, mod, gid, role)
reqs := chat.CallAgent(ag, zero.SuperUserPermission(ctx), i+1, x, mod, gid, role)
if len(reqs) == 0 {
logrus.Debugln("[aichat] agent call got empty response")
break
}
hasresp = true
mp.Store(chat.StateKeyAgentTriggered, struct{}{})
for _, req := range reqs {
if req.Action == goba.SVM { // is a fake action
/*if hassavemem {
ag.AddTerminus(gid)
logrus.Warnln("[aichat] agent call save mem multi times, force inserting EOA")
return
}
hassavemem = true*/
continue
}
resp := ctx.CallAction(req.Action, req.Params)
logrus.Infoln("[aichat] agent get resp:", reqs)
/*if req.Action == "send_private_msg" || req.Action == "send_group_msg" {
if ispuremsg {
ag.AddTerminus(gid)
logrus.Warnln("[aichat] agent call send msg multi times, force inserting EOA")
return
}
ispuremsg = true
}*/
logrus.Debugln("[chat] agent triggered", gid, "add requ:", &req)
ag.AddRequest(gid, &req)
rsp := ctx.CallAction(req.Action, req.Params)
logrus.Debugln("[chat] agent triggered", gid, "add resp:", &rsp)
ag.AddResponse(gid, &goba.APIResponse{
Status: resp.Status,
Data: json.RawMessage(resp.Data.Raw),
Message: resp.Message,
Wording: resp.Wording,
RetCode: resp.RetCode,
Status: rsp.Status,
Data: json.RawMessage(rsp.Data.Raw),
Message: rsp.Message,
Wording: rsp.Wording,
RetCode: rsp.RetCode,
})
}
}
@ -166,7 +188,7 @@ func init() {
if t == "" {
continue
}
logrus.Infoln("[aichat] 回复内容:", t)
logrus.Debugln("[aichat] 回复内容:", t)
recCfg := airecord.GetConfig()
record := ""
if !fastfailnorecord && !stor.NoRecord() {

View File

@ -29,18 +29,28 @@ var (
"- 查看AI聊天系统提示词\n" +
"- 重置AI聊天系统提示词\n" +
"- 设置AI聊天系统提示词xxx\n" +
"- 设置AI聊天Agent性格xxx" +
"- 查看AI聊天Agent性格" +
"- 设置AI聊天Agent性别xxx" +
"- 查看AI聊天Agent性别" +
"- 重置AI聊天Agent性格性别\n" +
"- 设置AI聊天分隔符</think>(留空则清除)\n" +
"- 设置AI聊天(不)响应AT\n" +
"- 设置AI聊天最大长度4096\n" +
"- 设置AI聊天TopP 0.9\n" +
"- 设置AI聊天(不)以AI语音输出\n" +
"- 查看AI聊天配置\n" +
"- 重置AI聊天Agent\n" +
"- 重置AI聊天\n",
})
)
func init() {
en.UsePreHandler(func(ctx *zero.Ctx) bool {
en.UsePreHandler(chat.EnsureConfig, func(ctx *zero.Ctx) bool {
k := zero.StateKeyPrefixKeep + "aichatcfg_stor__"
if _, ok := ctx.State[k]; ok {
return true
}
gid := ctx.Event.GroupID
if gid == 0 {
gid = -ctx.Event.UserID
@ -50,7 +60,7 @@ func init() {
logrus.Warnln("ERROR: ", err)
return false
}
ctx.State[zero.StateKeyPrefixKeep+"aichatcfg_stor__"] = stor
ctx.State[k] = stor
return true
})
en.OnPrefix("设置AI聊天触发概率", zero.AdminPermission).SetBlock(true).
@ -83,9 +93,20 @@ func init() {
Handle(chat.NewExtraSetStr(&chat.AC.AgentModelName))
en.OnPrefix("设置AI聊天系统提示词", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(chat.NewExtraSetStr(&chat.AC.SystemP))
en.OnPrefix("设置AI聊天Agent性格", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(chat.NewExtraSetStr(&chat.AC.AgentChar), func(_ *zero.Ctx) {
chat.AgentCharConfig.Chars = chat.AC.AgentChar
})
en.OnPrefix("设置AI聊天Agent性别", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(chat.NewExtraSetStr(&chat.AC.AgentSex), func(_ *zero.Ctx) {
chat.AgentCharConfig.Sex = chat.AC.AgentSex
})
en.OnFullMatch("查看AI聊天系统提示词", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text(chat.AC.SystemP))
})
en.OnFullMatch("查看AI聊天Agent性格", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
ctx.SendChain(message.Text(chat.AC.AgentChar))
})
en.OnFullMatch("重置AI聊天系统提示词", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
c, ok := ctx.State["manager"].(*ctrl.Control[*zero.Ctx])
if !ok {
@ -100,19 +121,33 @@ func init() {
}
ctx.SendChain(message.Text("成功"))
})
en.OnFullMatch("重置AI聊天Agent性格性别", chat.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
}
chat.ResetAgentCharConfig()
err := c.SetExtra(&chat.AC)
if err != nil {
ctx.SendChain(message.Text("ERROR: set extra err: ", err))
return
}
ctx.SendChain(message.Text("成功, 请重置AI聊天Agent"))
})
en.OnPrefix("设置AI聊天分隔符", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(chat.NewExtraSetStr(&chat.AC.Separator))
en.OnRegex("^设置AI聊天(不)?响应AT$", chat.EnsureConfig, zero.SuperUserPermission).SetBlock(true).
en.OnRegex("^设置AI聊天(不)?响应AT$", zero.SuperUserPermission).SetBlock(true).
Handle(ctxext.NewStorageSaveBoolHandler(chat.BitmapNrat))
en.OnRegex("^设置AI聊天(不)?支持系统提示词$", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(chat.NewExtraSetBool(&chat.AC.NoSystemP))
en.OnRegex("^设置AI聊天(不)?使用Agent模式$", chat.EnsureConfig, zero.SuperUserPermission).SetBlock(true).
en.OnRegex("^设置AI聊天(不)?使用Agent模式$", zero.SuperUserPermission).SetBlock(true).
Handle(ctxext.NewStorageSaveBoolHandler(chat.BitmapNagt))
en.OnPrefix("设置AI聊天最大长度", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(chat.NewExtraSetUint(&chat.AC.MaxN))
en.OnPrefix("设置AI聊天TopP", chat.EnsureConfig, zero.OnlyPrivate, zero.SuperUserPermission).SetBlock(true).
Handle(chat.NewExtraSetFloat32(&chat.AC.TopP))
en.OnRegex("^设置AI聊天(不)?以AI语音输出$", chat.EnsureConfig, zero.AdminPermission).SetBlock(true).
en.OnRegex("^设置AI聊天(不)?以AI语音输出$", zero.AdminPermission).SetBlock(true).
Handle(ctxext.NewStorageSaveBoolHandler(chat.BitmapNrec))
en.OnFullMatch("查看AI聊天配置", chat.EnsureConfig, zero.SuperUserPermission).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
@ -137,6 +172,10 @@ func init() {
message.Text("【当前AI聊天全局配置】\n", &chat.AC),
)
})
en.OnFullMatch("重置AI聊天Agent", chat.EnsureConfig, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
chat.ResetAgents()
ctx.SendChain(message.Text("成功"))
})
en.OnFullMatch("重置AI聊天", chat.EnsureConfig, zero.SuperUserPermission).SetBlock(true).Handle(func(ctx *zero.Ctx) {
chat.ResetChat()
ctx.SendChain(message.Text("成功"))

View File

@ -3,7 +3,6 @@ package crypter
import (
"github.com/FloatTech/AnimeAPI/airecord"
"github.com/sirupsen/logrus"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
@ -12,7 +11,6 @@ import (
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 != "" {

View File

@ -36,7 +36,7 @@ var (
lotsList = func() map[string]info {
lotsList, err := getList()
if err != nil {
logrus.Infoln("[drawlots]加载失败:", err)
logrus.Infoln("[drawlots]加载失败:", err, "(如果从未使用过该插件, 这是正常现象)")
} else {
logrus.Infoln("[drawlots]加载", len(lotsList), "个抽签")
}

View File

@ -11,8 +11,6 @@ import (
"sync"
"time"
log "github.com/sirupsen/logrus"
"github.com/FloatTech/floatbox/file"
"github.com/FloatTech/zbputils/ctxext"
"github.com/pkg/errors"
@ -30,7 +28,7 @@ func init() {
var err1 error
t2s, err1 = gocc.New("t2s")
if err1 != nil {
log.Infof("[guessmusic]:%s", err1)
panic(err1)
}
engine.OnRegex(`^(个人|团队)猜歌(-(.*))?$`, zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByGroup).

View File

@ -3,8 +3,9 @@ package minecraftobserver
import (
"errors"
"fmt"
"github.com/jinzhu/gorm"
"testing"
"github.com/jinzhu/gorm"
)
func cleanTestData(t *testing.T) {

View File

@ -1,35 +1,36 @@
// Package music QQ音乐、网易云、酷狗、酷我、咪咕 点歌
// Package music 整合多平台音乐点播能力
package music
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"time"
"github.com/FloatTech/floatbox/web"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
"github.com/tidwall/gjson"
"github.com/guohuiyuan/music-lib/kugou"
"github.com/guohuiyuan/music-lib/kuwo"
"github.com/guohuiyuan/music-lib/migu"
"github.com/guohuiyuan/music-lib/netease"
"github.com/guohuiyuan/music-lib/qq"
"github.com/pkg/errors"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
var (
longZhuURL = "https://www.hhlqilongzhu.cn/api/joox/juhe_music.php?msg=%v"
)
var platformMap = map[string]func(string) (message.Segment, error){
"咪咕": getMiguMusic,
"酷我": getKuwoMusic,
"酷狗": getKugouMusic,
"网易": getNeteaseMusic,
"qq": getQQMusic,
"": getKuwoMusic, // 默认点歌指向酷我
}
func init() {
control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "点歌",
Help: "- 点歌[xxx]\n" +
Help: "- 点歌[xxx] (默认酷我)\n" +
"- 网易点歌[xxx]\n" +
"- 酷我点歌[xxx]\n" +
"- 酷狗点歌[xxx]\n" +
@ -37,203 +38,146 @@ func init() {
"- qq点歌[xxx]\n",
}).OnRegex(`^(.{0,2})点歌\s?(.{1,25})$`).SetBlock(true).Limit(ctxext.LimitByUser).
Handle(func(ctx *zero.Ctx) {
// switch 平台
switch ctx.State["regex_matched"].([]string)[1] {
case "咪咕":
ctx.SendChain(migu(ctx.State["regex_matched"].([]string)[2]))
case "酷我":
ctx.SendChain(kuwo(ctx.State["regex_matched"].([]string)[2]))
case "酷狗":
ctx.SendChain(kugou(ctx.State["regex_matched"].([]string)[2]))
case "网易":
ctx.SendChain(cloud163(ctx.State["regex_matched"].([]string)[2]))
case "qq":
ctx.SendChain(qqmusic(ctx.State["regex_matched"].([]string)[2]))
default: // 默认聚合点歌
ctx.SendChain(longzhu(ctx.State["regex_matched"].([]string)[2]))
matches := ctx.State["regex_matched"].([]string)
platformPrefix := matches[1]
keyword := matches[2]
processFunc, ok := platformMap[platformPrefix]
if !ok {
ctx.SendChain(message.Text("不支持的点播平台:", platformPrefix))
return
}
seg, err := processFunc(keyword)
if err != nil {
ctx.SendChain(message.Text("点歌失败:", err))
return
}
ctx.SendChain(seg)
})
}
// longzhu 聚合平台
func longzhu(keyword string) message.Segment {
data, _ := web.GetData(fmt.Sprintf(longZhuURL, url.QueryEscape(keyword)))
// 假设 data 是包含整个 JSON 数组的字节切片
results := gjson.ParseBytes(data).Array()
for _, result := range results {
if strings.Contains(strings.ToLower(result.Get("title").String()), strings.ToLower(keyword)) {
if musicURL := result.Get("full_track").String(); musicURL != "" {
return message.Record(musicURL)
}
}
}
results = gjson.GetBytes(data, "#.full_track").Array()
if len(results) > 0 {
if musicURL := results[0].String(); musicURL != "" {
return message.Record(musicURL)
}
}
return message.Text("点歌失败, 找不到 ", keyword, " 的相关结果")
}
// migu 返回咪咕音乐卡片
func migu(keyword string) message.Segment {
headers := http.Header{
"Cookie": []string{"audioplayer_exist=1; audioplayer_open=0; migu_cn_cookie_id=3ad476db-f021-4bda-ab91-c485ac3d56a0; Hm_lvt_ec5a5474d9d871cb3d82b846d861979d=1671119573; Hm_lpvt_ec5a5474d9d871cb3d82b846d861979d=1671119573; WT_FPC=id=279ef92eaf314cbb8d01671116477485:lv=1671119583092:ss=1671116477485"},
"csrf": []string{"LWKACV45JSQ"},
"User-Agent": []string{"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36"},
"Referer": []string{"http://m.music.migu.cn"},
"proxy": []string{"false"},
}
// 搜索音乐信息 第一首歌
search, _ := url.Parse("http://m.music.migu.cn/migu/remoting/scr_search_tag")
search.RawQuery = url.Values{
"keyword": []string{keyword},
"type": []string{"2"},
"pgc": []string{"1"},
"rows": []string{"10"},
}.Encode()
info := gjson.ParseBytes(netGet(search.String(), headers)).Get("musics.0")
// 返回音乐卡片
return message.CustomMusic(
fmt.Sprintf("https://music.migu.cn/v3/music/song/%s", info.Get("copyrightId").String()),
info.Get("mp3").String(),
info.Get("songName").String(),
).Add("content", info.Get("artist").Str).Add("image", info.Get("cover").Str).Add("subtype", "migu")
}
// kuwo 返回酷我音乐卡片
func kuwo(keyword string) message.Segment {
headers := http.Header{
"Cookie": []string{"Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1610284708,1610699237; _ga=GA1.2.1289529848.1591618534; kw_token=LWKACV45JSQ; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1610699468; _gid=GA1.2.1868980507.1610699238; _gat=1"},
"csrf": []string{"LWKACV45JSQ"},
"User-Agent": []string{"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"},
"Referer": []string{"https://www.kuwo.cn/search/list?key="},
}
// 搜索音乐信息 第一首歌
search, _ := url.Parse("https://www.kuwo.cn/api/www/search/searchMusicBykeyWord")
search.RawQuery = url.Values{
"key": []string{keyword},
"pn": []string{"1"},
"rn": []string{"1"},
"httpsStatus": []string{"1"},
}.Encode()
info := gjson.ParseBytes(netGet(search.String(), headers)).Get("data.list.0")
// 获得音乐直链
music, _ := url.Parse("http://www.kuwo.cn/api/v1/www/music/playUrl")
music.RawQuery = url.Values{
"mid": []string{fmt.Sprintf("%d", info.Get("rid").Int())},
"type": []string{"convert_url3"},
"br": []string{"320kmp3"},
"httpsStatus": []string{"1"},
}.Encode()
audio := gjson.ParseBytes(netGet(music.String(), headers))
// 返回音乐卡片
return message.CustomMusic(
fmt.Sprintf("https://www.kuwo.cn/play_detail/%d", info.Get("rid").Int()),
audio.Get("data.url").Str,
info.Get("name").Str,
).Add("content", info.Get("artist").Str).Add("image", info.Get("pic").Str).Add("subtype", "kuwo")
}
// kugou 返回酷狗音乐卡片
func kugou(keyword string) message.Segment {
stamp := time.Now().UnixNano() / 1e6
hash := md5str(
fmt.Sprintf(
"NVPh5oo715z5DIWAeQlhMDsWXXQV4hwtbitrate=0callback=callback123clienttime=%dclientver=2000dfid=-inputtype=0iscorrection=1isfuzzy=0keyword=%smid=%dpage=1pagesize=30platform=WebFilterprivilege_filter=0srcappid=2919tag=emuserid=-1uuid=%dNVPh5oo715z5DIWAeQlhMDsWXXQV4hwt",
stamp, keyword, stamp, stamp,
),
)
// 搜索音乐信息 第一首歌
h1 := http.Header{
"User-Agent": []string{"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"},
}
search, _ := url.Parse("https://complexsearch.kugou.com/v2/search/song")
search.RawQuery = url.Values{
"callback": []string{"callback123"},
"keyword": []string{keyword},
"page": []string{"1"},
"pagesize": []string{"30"},
"bitrate": []string{"0"},
"isfuzzy": []string{"0"},
"tag": []string{"em"},
"inputtype": []string{"0"},
"platform": []string{"WebFilter"},
"userid": []string{"-1"},
"clientver": []string{"2000"},
"iscorrection": []string{"1"},
"privilege_filter": []string{"0"},
"srcappid": []string{"2919"},
"clienttime": []string{fmt.Sprintf("%d", stamp)},
"mid": []string{fmt.Sprintf("%d", stamp)},
"uuid": []string{fmt.Sprintf("%d", stamp)},
"dfid": []string{"-"},
"signature": []string{hash},
}.Encode()
res := netGet(search.String(), h1)
info := gjson.ParseBytes(res[12 : len(res)-2]).Get("data.lists.0")
// 获得音乐直链
h2 := http.Header{
"Cookie": []string{"kg_mid=d8e70a262c93d47599c6196c612d6f4f; Hm_lvt_aedee6983d4cfc62f509129360d6bb3d=1610278505,1611631363,1611722252; kg_dfid=33ZWee1kircl0jcJ1h0WF1fX; Hm_lpvt_aedee6983d4cfc62f509129360d6bb3d=1611727348; kg_dfid_collect=d41d8cd98f00b204e9800998ecf8427e"},
"Host": []string{"wwwapi.kugou.com"},
"TE": []string{"Trailers"},
"User-Agent": []string{"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"},
}
music := "https://wwwapi.kugou.com/yy/index.php?r=play%2Fgetdata&hash=" + info.Get("FileHash").Str + "&album_id=" + info.Get("AlbumID").Str
audio := gjson.ParseBytes(netGet(music, h2)).Get("data")
// 返回音乐卡片
return message.CustomMusic(
"https://www.kugou.com/song/#hash="+audio.Get("hash").Str+"&album_id="+audio.Get("album_id").Str,
strings.ReplaceAll(audio.Get("play_backup_url").Str, "\\/", "/"),
audio.Get("audio_name").Str,
).Add("content", audio.Get("author_name").Str).Add("image", audio.Get("img").Str).Add("subtype", "kugou")
}
// cloud163 返回网易云音乐卡片
func cloud163(keyword string) (msg message.Segment) {
requestURL := "http://music.163.com/api/search/get/web?type=1&limit=1&s=" + url.QueryEscape(keyword)
data, err := web.GetData(requestURL)
func getMiguMusic(keyword string) (message.Segment, error) {
songs, err := migu.Search(keyword)
if err != nil {
msg = message.Text("ERROR: ", err)
return
return message.Segment{}, errors.Wrap(err, "咪咕音乐搜索失败")
}
msg = message.Music("163", gjson.ParseBytes(data).Get("result.songs.0.id").Int())
return
}
if len(songs) == 0 {
return message.Segment{}, errors.New("咪咕音乐未找到相关歌曲:" + keyword)
}
song := songs[0]
// qqmusic 返回QQ音乐卡片
func qqmusic(keyword string) (msg message.Segment) {
requestURL := "https://c.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg?platform=yqq.json&key=" + url.QueryEscape(keyword)
data, err := web.RequestDataWith(web.NewDefaultClient(), requestURL, "GET", "", web.RandUA(), nil)
playURL, err := migu.GetDownloadURL(&song)
if err != nil {
msg = message.Text("ERROR: ", err)
return
return message.Segment{}, errors.Wrap(err, "获取咪咕播放链接失败")
}
msg = message.Music("qq", gjson.ParseBytes(data).Get("data.song.itemlist.0.id").Int())
return
if playURL == "" {
return message.Segment{}, errors.New("获取咪咕播放链接失败:链接为空")
}
return message.CustomMusic(
fmt.Sprintf("https://music.migu.cn/v3/music/song/%s", song.ID),
playURL,
song.Name,
).Add("content", song.Artist).Add("image", song.Cover).Add("subtype", "migu"), nil
}
// md5str 返回字符串 MD5
func md5str(s string) string {
h := md5.New()
h.Write([]byte(s))
result := strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
return result
}
// netGet 返回请求数据
func netGet(url string, header http.Header) []byte {
client := &http.Client{}
request, _ := http.NewRequest("GET", url, nil)
request.Header = header
res, err := client.Do(request)
func getKuwoMusic(keyword string) (message.Segment, error) {
songs, err := kuwo.Search(keyword)
if err != nil {
return nil
return message.Segment{}, errors.Wrap(err, "酷我音乐搜索失败")
}
defer res.Body.Close()
result, _ := io.ReadAll(res.Body)
return result
if len(songs) == 0 {
return message.Segment{}, errors.New("酷我音乐未找到相关歌曲:" + keyword)
}
song := songs[0]
playURL, err := kuwo.GetDownloadURL(&song)
if err != nil {
return message.Segment{}, errors.Wrap(err, "获取酷我播放链接失败")
}
if playURL == "" {
return message.Segment{}, errors.New("获取酷我播放链接失败:链接为空")
}
return message.CustomMusic(
fmt.Sprintf("https://www.kuwo.cn/play_detail/%s", song.ID),
playURL,
song.Name,
).Add("content", song.Artist).Add("image", song.Cover).Add("subtype", "kuwo"), nil
}
func getKugouMusic(keyword string) (message.Segment, error) {
songs, err := kugou.Search(keyword)
if err != nil {
return message.Segment{}, errors.Wrap(err, "酷狗音乐搜索失败")
}
if len(songs) == 0 {
return message.Segment{}, errors.New("酷狗音乐未找到相关歌曲:" + keyword)
}
song := songs[0]
playURL, err := kugou.GetDownloadURL(&song)
if err != nil {
return message.Segment{}, errors.Wrap(err, "获取酷狗播放链接失败")
}
if playURL == "" {
return message.Segment{}, errors.New("获取酷狗播放链接失败:链接为空")
}
return message.CustomMusic(
"https://www.kugou.com/",
playURL,
song.Name,
).Add("content", song.Artist).Add("image", song.Cover).Add("subtype", "kugou"), nil
}
func getNeteaseMusic(keyword string) (message.Segment, error) {
songs, err := netease.Search(keyword)
if err != nil {
return message.Segment{}, errors.Wrap(err, "网易云音乐搜索失败")
}
if len(songs) == 0 {
return message.Segment{}, errors.New("网易云音乐未找到相关歌曲:" + keyword)
}
song := songs[0]
playURL, err := netease.GetDownloadURL(&song)
if err != nil {
return message.Segment{}, errors.Wrap(err, "获取网易云播放链接失败")
}
if playURL == "" {
return message.Segment{}, errors.New("获取网易云播放链接失败:链接为空")
}
return message.CustomMusic(
fmt.Sprintf("https://music.163.com/#/song?id=%s", song.ID),
playURL,
song.Name,
).Add("content", song.Artist).Add("image", song.Cover).Add("subtype", "163"), nil
}
func getQQMusic(keyword string) (message.Segment, error) {
songs, err := qq.Search(keyword)
if err != nil {
return message.Segment{}, errors.Wrap(err, "QQ音乐搜索失败")
}
if len(songs) == 0 {
return message.Segment{}, errors.New("QQ音乐未找到相关歌曲" + keyword)
}
song := songs[0]
playURL, err := qq.GetDownloadURL(&song)
if err != nil {
return message.Segment{}, errors.Wrap(err, "获取QQ音乐播放链接失败")
}
if playURL == "" {
return message.Segment{}, errors.New("获取QQ音乐播放链接失败链接为空")
}
return message.CustomMusic(
fmt.Sprintf("https://y.qq.com/n/ryqq/songDetail/%s", song.ID),
playURL,
song.Name,
).Add("content", song.Artist).Add("image", song.Cover).Add("subtype", "qq"), nil
}

View File

@ -28,7 +28,7 @@ func (repo *RssDomain) syncRss(ctx context.Context) (updated map[int64]*RssClien
feed, err = repo.rssHubClient.FetchFeed(channel.RssHubFeedPath)
// 如果获取失败,则跳过
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] fetch path(%+v) error: %v", channel.RssHubFeedPath, err)
logrus.WithContext(ctx).Warnf("[rsshub syncRss] fetch path(%+v) error: %v", channel.RssHubFeedPath, err)
continue
}
rv := convertFeedToRssView(0, channel.RssHubFeedPath, feed)
@ -42,27 +42,27 @@ func (repo *RssDomain) syncRss(ctx context.Context) (updated map[int64]*RssClien
var needUpdate bool
needUpdate, err = repo.checkSourceNeedUpdate(ctx, cv.Source)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] checkSourceNeedUpdate error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub syncRss] checkSourceNeedUpdate error: %v", err)
err = nil
continue
}
// 保存
logrus.WithContext(ctx).Infof("[rsshub syncRss] cv %+v, need update(real): %v", cv.Source, needUpdate)
logrus.WithContext(ctx).Debugf("[rsshub syncRss] cv %+v, need update(real): %v", cv.Source, needUpdate)
// 如果需要更新更新channel 和 content
if needUpdate {
err = repo.storage.UpsertSource(ctx, cv.Source)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] upsert source error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub syncRss] upsert source error: %v", err)
}
}
var updateChannelView = &RssClientView{Source: cv.Source, Contents: []*RssContent{}}
err = repo.processContentsUpdate(ctx, cv, updateChannelView)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] processContentsUpdate error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub syncRss] processContentsUpdate error: %v", err)
continue
}
if len(updateChannelView.Contents) == 0 {
logrus.WithContext(ctx).Infof("[rsshub syncRss] cv %s, no new content", cv.Source.RssHubFeedPath)
logrus.WithContext(ctx).Debugf("[rsshub syncRss] cv %s, no new content", cv.Source.RssHubFeedPath)
continue
}
updateChannelView.Sort()
@ -80,7 +80,7 @@ func (repo *RssDomain) checkSourceNeedUpdate(ctx context.Context, source *RssSou
return
}
if sourceInDB == nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] source not found: %v", source.RssHubFeedPath)
logrus.WithContext(ctx).Warnf("[rsshub syncRss] source not found: %v", source.RssHubFeedPath)
return
}
source.ID = sourceInDB.ID
@ -102,13 +102,13 @@ func (repo *RssDomain) processContentsUpdate(ctx context.Context, cv *RssClientV
var existed bool
existed, err = repo.processContentItemUpdate(ctx, content)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] upsert content error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub syncRss] upsert content error: %v", err)
err = nil
continue
}
if !existed {
updateChannelView.Contents = append(updateChannelView.Contents, content)
logrus.WithContext(ctx).Infof("[rsshub syncRss] cv %s, add new content: %v", cv.Source.RssHubFeedPath, content.Title)
logrus.WithContext(ctx).Debugf("[rsshub syncRss] cv %s, add new content: %v", cv.Source.RssHubFeedPath, content.Title)
}
}
return err
@ -127,7 +127,7 @@ func (repo *RssDomain) processContentItemUpdate(ctx context.Context, content *Rs
// 保存
err = repo.storage.UpsertContent(ctx, content)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] upsert content error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub syncRss] upsert content error: %v", err)
return
}
return

View File

@ -36,11 +36,11 @@ func (c *RssHubClient) FetchFeed(path string) (feed *gofeed.Feed, err error) {
}
}
if err != nil {
logrus.Errorf("[rsshub FetchFeed] fetch feed error: %v", err)
logrus.Warnf("[rsshub FetchFeed] fetch feed error: %v", err)
return nil, err
}
if len(data) == 0 {
logrus.Errorf("[rsshub FetchFeed] fetch feed error: data is empty")
logrus.Warnf("[rsshub FetchFeed] fetch feed error: data is empty")
return nil, errors.New("feed data is empty")
}
feed, err = gofeed.NewParser().Parse(bytes.NewBuffer(data))

View File

@ -33,7 +33,7 @@ func newRssDomain(dbPath string) (*RssDomain, error) {
}
orm, err := gorm.Open("sqlite3", dbPath)
if err != nil {
logrus.Errorf("[rsshub NewRssDomain] open db error: %v", err)
logrus.Warnf("[rsshub NewRssDomain] open db error: %v", err)
panic(err)
}
repo := &RssDomain{
@ -42,7 +42,7 @@ func newRssDomain(dbPath string) (*RssDomain, error) {
}
err = repo.storage.initDB()
if err != nil {
logrus.Errorf("[rsshub NewRssDomain] open db error: %v", err)
logrus.Warnf("[rsshub NewRssDomain] open db error: %v", err)
panic(err)
}
return repo, nil
@ -54,15 +54,15 @@ func (repo *RssDomain) Subscribe(ctx context.Context, gid int64, feedPath string
// 验证
feed, err := repo.rssHubClient.FetchFeed(feedPath)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] add source error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Subscribe] add source error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub Subscribe] try get source success: %v", len(feed.Title))
logrus.WithContext(ctx).Debugf("[rsshub Subscribe] try get source success: %v", len(feed.Title))
// 新建source结构体
rv = convertFeedToRssView(0, feedPath, feed)
feedChannel, err := repo.storage.GetSourceByRssHubFeedLink(ctx, feedPath)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] query source by feedPath error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Subscribe] query source by feedPath error: %v", err)
return
}
// 如果已经存在
@ -76,30 +76,30 @@ func (repo *RssDomain) Subscribe(ctx context.Context, gid int64, feedPath string
// 保存
err = repo.storage.UpsertSource(ctx, rv.Source)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] save source error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Subscribe] save source error: %v", err)
return
}
logrus.Infof("[rsshub Subscribe] save/update source success %v", rv.Source.ID)
logrus.Debugf("[rsshub Subscribe] save/update source success %v", rv.Source.ID)
// 添加群号到订阅
subscribe, err := repo.storage.GetSubscribeByID(ctx, gid, rv.Source.ID)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] query subscribe error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Subscribe] query subscribe error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub Subscribe] query subscribe success: %v", subscribe)
logrus.WithContext(ctx).Debugf("[rsshub Subscribe] query subscribe success: %v", subscribe)
// 如果已经存在,直接返回
if subscribe != nil {
isSubExisted = true
logrus.WithContext(ctx).Infof("[rsshub Subscribe] subscribe existed: %v", subscribe)
logrus.WithContext(ctx).Debugf("[rsshub Subscribe] subscribe existed: %v", subscribe)
return
}
// 如果不存在,保存
err = repo.storage.CreateSubscribe(ctx, gid, rv.Source.ID)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] save subscribe error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Subscribe] save subscribe error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub Subscribe] success: %v", len(rv.Contents))
logrus.WithContext(ctx).Debugf("[rsshub Subscribe] success: %v", len(rv.Contents))
return
}
@ -107,31 +107,31 @@ func (repo *RssDomain) Subscribe(ctx context.Context, gid int64, feedPath string
func (repo *RssDomain) Unsubscribe(ctx context.Context, gid int64, feedPath string) (err error) {
existedSubscribes, ifExisted, err := repo.storage.GetIfExistedSubscribe(ctx, gid, feedPath)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] query sub by route error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Subscribe] query sub by route error: %v", err)
return errors.New("数据库错误")
}
logrus.WithContext(ctx).Infof("[rsshub Subscribe] query source by route success: %v", existedSubscribes)
logrus.WithContext(ctx).Debugf("[rsshub Subscribe] query source by route success: %v", existedSubscribes)
// 如果不存在订阅关系,直接返回
if !ifExisted || existedSubscribes == nil {
logrus.WithContext(ctx).Infof("[rsshub Subscribe] source existed: %v", ifExisted)
logrus.WithContext(ctx).Debugf("[rsshub Subscribe] source existed: %v", ifExisted)
return errors.New("频道不存在")
}
err = repo.storage.DeleteSubscribe(ctx, existedSubscribes.ID)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] delete source error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Subscribe] delete source error: %v", err)
return errors.New("删除失败")
}
// 查询是否还有群订阅这个频道
subscribesNeedsToDel, err := repo.storage.GetSubscribesBySource(ctx, feedPath)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] query source by route error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Subscribe] query source by route error: %v", err)
return
}
// 没有群订阅的时候,把频道删除
if len(subscribesNeedsToDel) == 0 {
err = repo.storage.DeleteSource(ctx, existedSubscribes.RssSourceID)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Subscribe] delete source error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Subscribe] delete source error: %v", err)
return errors.New("清除频道信息失败")
}
}
@ -142,11 +142,11 @@ func (repo *RssDomain) Unsubscribe(ctx context.Context, gid int64, feedPath stri
func (repo *RssDomain) GetSubscribedChannelsByGroupID(ctx context.Context, gid int64) ([]*RssClientView, error) {
channels, err := repo.storage.GetSubscribedChannelsByGroupID(ctx, gid)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub GetSubscribedChannelsByGroupID] GetSubscribedChannelsByGroupID error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub GetSubscribedChannelsByGroupID] GetSubscribedChannelsByGroupID error: %v", err)
return nil, err
}
rv := make([]*RssClientView, len(channels))
logrus.WithContext(ctx).Infof("[rsshub GetSubscribedChannelsByGroupID] query subscribe success: %v", len(channels))
logrus.WithContext(ctx).Debugf("[rsshub GetSubscribedChannelsByGroupID] query subscribe success: %v", len(channels))
for i, cn := range channels {
rv[i] = &RssClientView{
Source: cn,
@ -162,13 +162,13 @@ func (repo *RssDomain) Sync(ctx context.Context) (groupView map[int64][]*RssClie
// 获取所有频道
updatedViews, err := repo.syncRss(ctx)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Sync] sync rss feed error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Sync] sync rss feed error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub Sync] updated channels: %v", len(updatedViews))
logrus.WithContext(ctx).Debugf("[rsshub Sync] updated channels: %v", len(updatedViews))
subscribes, err := repo.storage.GetSubscribes(ctx)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub Sync] get subscribes error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub Sync] get subscribes error: %v", err)
return
}
for _, subscribe := range subscribes {

View File

@ -19,7 +19,7 @@ type repoStorage struct {
func (s *repoStorage) initDB() (err error) {
err = s.orm.AutoMigrate(&RssSource{}, &RssContent{}, &RssSubscribe{}).Error
if err != nil {
logrus.Errorf("[rsshub initDB] error: %v", err)
logrus.Warnf("[rsshub initDB] error: %v", err)
return err
}
return nil
@ -28,7 +28,7 @@ func (s *repoStorage) initDB() (err error) {
// GetSubscribesBySource Impl
func (s *repoStorage) GetSubscribesBySource(ctx context.Context, feedPath string) ([]*RssSubscribe, error) {
logrus.WithContext(ctx).Infof("[rsshub GetSubscribesBySource] feedPath: %s", feedPath)
logrus.WithContext(ctx).Debugf("[rsshub GetSubscribesBySource] feedPath: %s", feedPath)
rs := make([]*RssSubscribe, 0)
err := s.orm.Model(&RssSubscribe{}).Joins(fmt.Sprintf("%s left join %s on %s.rss_source_id=%s.id", tableNameRssSubscribe, tableNameRssSource, tableNameRssSubscribe, tableNameRssSource)).
Where("rss_source.rss_hub_feed_path = ?", feedPath).Select("rss_subscribe.*").Find(&rs).Error
@ -36,7 +36,7 @@ func (s *repoStorage) GetSubscribesBySource(ctx context.Context, feedPath string
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
logrus.WithContext(ctx).Errorf("[rsshub GetSubscribesBySource] error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub GetSubscribesBySource] error: %v", err)
return nil, err
}
return rs, nil
@ -56,7 +56,7 @@ func (s *repoStorage) GetIfExistedSubscribe(ctx context.Context, gid int64, feed
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
logrus.WithContext(ctx).Errorf("[rsshub GetIfExistedSubscribe] error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub GetIfExistedSubscribe] error: %v", err)
return nil, false, err
}
if rs.ID == 0 {
@ -76,14 +76,14 @@ func (s *repoStorage) UpsertSource(ctx context.Context, source *RssSource) (err
if errors.Is(err, gorm.ErrRecordNotFound) {
err = s.orm.Create(source).Omit("id").Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] add source error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] add source error: %v", err)
return
}
}
return
}
source.ID = querySource.ID
logrus.WithContext(ctx).Infof("[rsshub] update source: %+v", source.UpdatedParsed)
logrus.WithContext(ctx).Debugf("[rsshub] update source: %+v", source.UpdatedParsed)
err = s.orm.Model(&source).Where(&RssSource{ID: source.ID}).
Updates(&RssSource{
Title: source.Title,
@ -94,7 +94,7 @@ func (s *repoStorage) UpsertSource(ctx context.Context, source *RssSource) (err
Mtime: time.Now(),
}).Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] update source error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] update source error: %v", err)
return
}
logrus.Println("[rsshub] add source success: ", source.ID)
@ -109,10 +109,10 @@ func (s *repoStorage) GetSources(ctx context.Context) (sources []RssSource, err
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("source not found")
}
logrus.WithContext(ctx).Errorf("[rsshub] get sources error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] get sources error: %v", err)
return
}
logrus.WithContext(ctx).Infof("[rsshub] get sources success: %d", len(sources))
logrus.WithContext(ctx).Debugf("[rsshub] get sources success: %d", len(sources))
return
}
@ -124,7 +124,7 @@ func (s *repoStorage) GetSourceByRssHubFeedLink(ctx context.Context, rssHubFeedL
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
logrus.WithContext(ctx).Errorf("[rsshub] get source error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] get source error: %v", err)
return
}
return
@ -134,7 +134,7 @@ func (s *repoStorage) GetSourceByRssHubFeedLink(ctx context.Context, rssHubFeedL
func (s *repoStorage) DeleteSource(ctx context.Context, fID int64) (err error) {
err = s.orm.Delete(&RssSource{}, "id = ?", fID).Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.DeleteSource: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] storage.DeleteSource: %v", err)
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("source not found")
}
@ -161,7 +161,7 @@ func (s *repoStorage) UpsertContent(ctx context.Context, content *RssContent) (e
}
err = s.orm.Create(content).Omit("id").Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.UpsertContent: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] storage.UpsertContent: %v", err)
return
}
return
@ -171,7 +171,7 @@ func (s *repoStorage) UpsertContent(ctx context.Context, content *RssContent) (e
func (s *repoStorage) DeleteSourceContents(ctx context.Context, channelID int64) (rows int64, err error) {
err = s.orm.Delete(&RssSubscribe{}).Where(&RssSubscribe{RssSourceID: channelID}).Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.DeleteSourceContents: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] storage.DeleteSourceContents: %v", err)
return
}
return
@ -185,7 +185,7 @@ func (s *repoStorage) IsContentHashIDExist(ctx context.Context, hashID string) (
if errors.Is(err, gorm.ErrRecordNotFound) {
return false, nil
}
logrus.WithContext(ctx).Errorf("[rsshub] storage.IsContentHashIDExist: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] storage.IsContentHashIDExist: %v", err)
return false, err
}
return true, nil
@ -204,7 +204,7 @@ func (s *repoStorage) CreateSubscribe(ctx context.Context, gid, rssSourceID int6
}
err = s.orm.Create(&RssSubscribe{GroupID: gid, RssSourceID: rssSourceID}).Omit("id").Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.CreateSubscribe: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] storage.CreateSubscribe: %v", err)
return
}
return
@ -214,7 +214,7 @@ func (s *repoStorage) CreateSubscribe(ctx context.Context, gid, rssSourceID int6
func (s *repoStorage) DeleteSubscribe(ctx context.Context, subscribeID int64) (err error) {
err = s.orm.Delete(&RssSubscribe{}, "id = ?", subscribeID).Error
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub] storage.DeleteSubscribe error: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] storage.DeleteSubscribe error: %v", err)
return
}
return
@ -228,7 +228,7 @@ func (s *repoStorage) GetSubscribeByID(ctx context.Context, gid int64, subscribe
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
logrus.WithContext(ctx).Errorf("[rsshub] storage.GetSubscribeByID: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] storage.GetSubscribeByID: %v", err)
return nil, err
}
return
@ -247,7 +247,7 @@ func (s *repoStorage) GetSubscribedChannelsByGroupID(ctx context.Context, gid in
err = nil
return
}
logrus.WithContext(ctx).Errorf("[rsshub] storage.GetSubscribedChannelsByGroupID: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] storage.GetSubscribedChannelsByGroupID: %v", err)
return
}
return
@ -262,7 +262,7 @@ func (s *repoStorage) GetSubscribes(ctx context.Context) (res []*RssSubscribe, e
err = nil
return
}
logrus.WithContext(ctx).Errorf("[rsshub] storage.GetSubscribes: %v", err)
logrus.WithContext(ctx).Warnf("[rsshub] storage.GetSubscribes: %v", err)
return
}
return

View File

@ -4,7 +4,6 @@ package wife
import (
"bytes"
"image"
"image/color"
"math/rand"
"strings"
"time"
@ -15,7 +14,6 @@ import (
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
zbmath "github.com/FloatTech/floatbox/math"
"github.com/FloatTech/imgfactory"
)
@ -134,24 +132,8 @@ func init() {
})
}
// 马赛克生成
// 高斯模糊生成
func mosaic(dst *imgfactory.Factory, level int) ([]byte, error) {
b := dst.Image().Bounds()
p := imgfactory.NewFactoryBG(dst.W(), dst.H(), color.NRGBA{255, 255, 255, 255})
markSize := zbmath.Max(b.Max.X, b.Max.Y) * sizeList[level] / 200
for yOfMarknum := 0; yOfMarknum <= zbmath.Ceil(b.Max.Y, markSize); yOfMarknum++ {
for xOfMarknum := 0; xOfMarknum <= zbmath.Ceil(b.Max.X, markSize); xOfMarknum++ {
a := dst.Image().At(xOfMarknum*markSize+markSize/2, yOfMarknum*markSize+markSize/2)
cc := color.NRGBAModel.Convert(a).(color.NRGBA)
for y := 0; y < markSize; y++ {
for x := 0; x < markSize; x++ {
xOfPic := xOfMarknum*markSize + x
yOfPic := yOfMarknum*markSize + y
p.Image().Set(xOfPic, yOfPic, cc)
}
}
}
}
return imgfactory.ToBytes(p.Blur(3).Image())
blurRadius := float64(sizeList[level] * 3)
return imgfactory.ToBytes(dst.Blur(blurRadius).Image())
}

View File

@ -13,7 +13,10 @@
mkGoEnv ? pkgs.mkGoEnv,
gomod2nix ? pkgs.gomod2nix,
}: let
goEnv = mkGoEnv { pwd = ./.; go = pkgs.go_1_20; };
goEnv = mkGoEnv {
pwd = ./.;
go = pkgs.go_1_24;
};
in
pkgs.mkShell {
packages = [

View File

@ -12,7 +12,7 @@
"0409": {
"identity": {
"name": "ZeroBot-Plugin",
"version": "1.10.7.2332"
"version": "1.10.18.2382"
},
"description": "",
"minimum-os": "vista",
@ -36,23 +36,23 @@
"#1": {
"0000": {
"fixed": {
"file_version": "1.10.7.2332",
"product_version": "v1.10.7",
"timestamp": "2026-01-03T23:42:04+08:00"
"file_version": "1.10.18.2382",
"product_version": "v1.10.18",
"timestamp": "2026-02-01T01:08:28+08:00"
},
"info": {
"0409": {
"Comments": "OneBot plugins based on ZeroBot",
"CompanyName": "FloatTech",
"FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin",
"FileVersion": "1.10.7.2332",
"FileVersion": "1.10.18.2382",
"InternalName": "",
"LegalCopyright": "© 2020 - 2026 FloatTech. All Rights Reserved.",
"LegalTrademarks": "",
"OriginalFilename": "ZBP.EXE",
"PrivateBuild": "",
"ProductName": "ZeroBot-Plugin",
"ProductVersion": "v1.10.7",
"ProductVersion": "v1.10.18",
"SpecialBuild": ""
}
}