Compare commits

...

11 Commits

Author SHA1 Message Date
源文雨
961fbb098e 🔖 v1.9.7 2025-05-14 21:54:07 +09:00
github-actions[bot]
42fe124b09 chore(lint): 改进代码样式 (#1167)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-05-14 15:42:18 +09:00
Dodoj
076b113455 fix(wordcount): 修改分词模块至外部gse仓库 (#1165)
Co-authored-by: 源文雨 <41315874+fumiama@users.noreply.github.com>
2025-05-13 12:05:24 +00:00
github-actions[bot]
c888936489 chore: bump deps (#1166)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-05-13 20:58:41 +09:00
源文雨
e1d2dee881 feat: replace jieba with gse 2025-05-13 20:19:34 +09:00
Doordoorjay
39e1f56955 fix: 疯狂星期四 API (#1161) 2025-05-06 18:12:41 +09:00
Nobody6825
4151464bdc chore: use new nixpkgs with overlay which bring back go_1_20 instead of using old nixpkgs (#1162) 2025-05-06 18:11:46 +09:00
github-actions[bot]
0b89312d9d chore(lint): 改进代码样式 (#1159)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-23 18:36:41 +09:00
github-actions[bot]
2c607dedee chore: bump deps (#1158)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-04-23 18:36:20 +09:00
方柳煜
30e9d04f74 feat: 电影查询 (#1155) 2025-04-23 18:35:34 +09:00
himawari
4b90a0659b feat(bilibili): 添加视频下载 (#1157) 2025-04-23 18:33:15 +09:00
17 changed files with 646 additions and 61 deletions

View File

@@ -976,6 +976,14 @@ print("run[CQ:image,file="+j["img"]+"]")
- (机器人回答:您的下一条指令将被记录,在@@every 1m时触发
- mc服务器订阅拉取
</details>
<details>
<summary>Movies猫眼电影查询</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/movies"`
- [x] 今日电影
- [x] 预售电影
</details>
<details>
<summary>摸鱼</summary>

View File

@@ -11,6 +11,7 @@
}
),
buildGoApplication ? pkgs.buildGoApplication,
...
}:
buildGoApplication {
pname = "ZeroBot-Plugin";

25
flake.lock generated
View File

@@ -28,11 +28,11 @@
]
},
"locked": {
"lastModified": 1741396135,
"narHash": "sha256-wqmdLr7h4Bk8gyKutgaApJKOM8JVvywI5P48NuqJ9Jg=",
"lastModified": 1742209644,
"narHash": "sha256-jMy1XqXqD0/tJprEbUmKilTkvbDY/C0ZGSsJJH4TNCE=",
"owner": "nix-community",
"repo": "gomod2nix",
"rev": "0983848bf2a7ccbfe24d874065adb8fd0f23729b",
"rev": "8f3534eb8f6c5c3fce799376dc3b91bae6b11884",
"type": "github"
},
"original": {
@@ -42,6 +42,22 @@
}
},
"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=",
@@ -61,7 +77,8 @@
"inputs": {
"flake-utils": "flake-utils",
"gomod2nix": "gomod2nix",
"nixpkgs": "nixpkgs"
"nixpkgs": "nixpkgs",
"nixpkgs-with-go_1_20": "nixpkgs-with-go_1_20"
}
},
"systems": {

View File

@@ -1,8 +1,8 @@
{
description = " ZeroBot OneBot ";
# pin nixpkgs to preserve dropped go_1_20
inputs.nixpkgs.url = "github:NixOS/nixpkgs/33c51330782cb486764eb598d5907b43dc87b4c2";
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";
@@ -11,14 +11,25 @@
outputs = {
self,
nixpkgs,
nixpkgs-with-go_1_20,
flake-utils,
gomod2nix,
}: let
...
} @ inputs: let
allSystems = flake-utils.lib.allSystems;
in (
flake-utils.lib.eachSystem allSystems
(system: let
pkgs = nixpkgs.legacyPackages.${system};
old-nixpkgs = nixpkgs-with-go_1_20.legacyPackages.${system};
pkgs = import nixpkgs {
inherit system;
overlays = [
(_: _: {
go_1_20 = old-nixpkgs.go_1_20;
})
];
};
# The current default sdk for macOS fails to compile go projects, so we use a newer one for now.
# This has no effect on other platforms.
@@ -26,11 +37,10 @@
in {
# doCheck will fail at write files
packages = rec {
ZeroBot-Plugin =
(callPackage ./. {
ZeroBot-Plugin = (callPackage ./. (inputs
// {
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
})
}))
.overrideAttrs (_: {doCheck = false;});
default = ZeroBot-Plugin;
@@ -43,7 +53,6 @@
pkgs.cacert
];
};
};
devShells.default = callPackage ./shell.nix {
inherit (gomod2nix.legacyPackages.${system}) mkGoEnv gomod2nix;

6
go.mod
View File

@@ -4,8 +4,8 @@ go 1.20
require (
github.com/Baidu-AIP/golang-sdk v1.1.1
github.com/FloatTech/AnimeAPI v1.7.1-0.20250217140215-4856397458c9
github.com/FloatTech/floatbox v0.0.0-20241106130736-5aea0a935024
github.com/FloatTech/AnimeAPI v1.7.1-0.20250423082452-e16339a3962c
github.com/FloatTech/floatbox v0.0.0-20250513111443-adba80e84e80
github.com/FloatTech/gg v1.1.3
github.com/FloatTech/imgfactory v0.2.2-0.20230413152719-e101cc3606ef
github.com/FloatTech/rendercard v0.2.0
@@ -30,6 +30,7 @@ require (
github.com/fumiama/slowdo v0.0.0-20241001074058-27c4fe5259a4
github.com/fumiama/terasu v0.0.0-20241027183601-987ab91031ce
github.com/fumiama/unibase2n v0.0.0-20240530074540-ec743fd5a6d6
github.com/go-ego/gse v0.80.3
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/google/uuid v1.6.0
github.com/jinzhu/gorm v1.9.16
@@ -85,6 +86,7 @@ require (
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/vcaesar/cedar v0.20.2 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/exp/shiny v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/mobile v0.0.0-20231127183840-76ac6878050a // indirect

13
go.sum
View File

@@ -1,10 +1,10 @@
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/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/FloatTech/AnimeAPI v1.7.1-0.20250217140215-4856397458c9 h1:tI9GgG8fdMK2WazFiEbMXAXjwMCckIfDaXbig9B6DdA=
github.com/FloatTech/AnimeAPI v1.7.1-0.20250217140215-4856397458c9/go.mod h1:XXG1eBJf+eeWacQx5azsQKL5Gg7jDYTFyyZGIa/56js=
github.com/FloatTech/floatbox v0.0.0-20241106130736-5aea0a935024 h1:mrvWpiwfRklt9AyiQjKgDGJjf4YL6FZ3yC+ydbkuF2o=
github.com/FloatTech/floatbox v0.0.0-20241106130736-5aea0a935024/go.mod h1:+P3hs+Cvl10/Aj3SNE96TuBvKAXCe+XD1pKphTZyiwk=
github.com/FloatTech/AnimeAPI v1.7.1-0.20250423082452-e16339a3962c h1:bEe8VP2aHLR2NHk1BsBQFtP0XE3cxquvr0tW0CkKcDk=
github.com/FloatTech/AnimeAPI v1.7.1-0.20250423082452-e16339a3962c/go.mod h1:XXG1eBJf+eeWacQx5azsQKL5Gg7jDYTFyyZGIa/56js=
github.com/FloatTech/floatbox v0.0.0-20250513111443-adba80e84e80 h1:lFD1pd8NkYCrw0QpTX/T5pJ67I7AL5eGxQ4v0r9f81Q=
github.com/FloatTech/floatbox v0.0.0-20250513111443-adba80e84e80/go.mod h1:IWoFFqu+0FeaHHQdddyiTRL5z7gJME6qHC96qh0R2sc=
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=
@@ -92,6 +92,8 @@ github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebK
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-ego/gse v0.80.3 h1:YNFkjMhlhQnUeuoFcUEd1ivh6SOB764rT8GDsEbDiEg=
github.com/go-ego/gse v0.80.3/go.mod h1:Gt3A9Ry1Eso2Kza4MRaiZ7f2DTAvActmETY46Lxg0gU=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
@@ -192,6 +194,9 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/vcaesar/cedar v0.20.2 h1:TDx7AdZhilKcfE1WvdToTJf5VrC/FXcUOW+KY1upLZ4=
github.com/vcaesar/cedar v0.20.2/go.mod h1:lyuGvALuZZDPNXwpzv/9LyxW+8Y6faN7zauFezNsnik=
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
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.20250330133859-27c25d9412b5 h1:HsMcBsVpYuQv+W8pjX5WdwYROrFQP9c5Pbf4x4adDus=

View File

@@ -5,11 +5,11 @@ schema = 3
version = "v1.1.1"
hash = "sha256-hKshA0K92bKuK92mmtM0osVmqLJcSbeobeWSDpQoRCo="
[mod."github.com/FloatTech/AnimeAPI"]
version = "v1.7.1-0.20250217140215-4856397458c9"
hash = "sha256-7TkWoVslfzO/aTx+F7UwttrtBGGMMqe4GHN0aF4JUd0="
version = "v1.7.1-0.20250423082452-e16339a3962c"
hash = "sha256-pyv242GLfslHEgQN5TgYsdpJKWzWR8qc4mJ8NXF0I8s="
[mod."github.com/FloatTech/floatbox"]
version = "v0.0.0-20241106130736-5aea0a935024"
hash = "sha256-hSKmkzpNZwXRo0qm4G+1lXkNzWMwV9leYlYLQuzWx3M="
version = "v0.0.0-20250513111443-adba80e84e80"
hash = "sha256-Zt9zkUa3qqldrSttAq66YLPZPxrnkOR2MaU7oapIWEE="
[mod."github.com/FloatTech/gg"]
version = "v1.1.3"
hash = "sha256-7K/R2mKjUHVnoJ3b1wDObJ5Un2Htj59Y97G1Ja1tuPo="
@@ -112,6 +112,9 @@ schema = 3
[mod."github.com/gabriel-vasile/mimetype"]
version = "v1.0.4"
hash = "sha256-5hl9zBo3nkPt8dZfcLoOix8lAKLm3qIkWhopoS4V34E="
[mod."github.com/go-ego/gse"]
version = "v0.80.3"
hash = "sha256-uxTQN4cxE/ZReZqjlIEQ3WYD9w2Ec37LRHQftJXsSZQ="
[mod."github.com/go-ole/go-ole"]
version = "v1.2.6"
hash = "sha256-+oxitLeJxYF19Z6g+6CgmCHJ1Y5D8raMi2Cb3M6nXCs="
@@ -217,6 +220,9 @@ schema = 3
[mod."github.com/tklauser/numcpus"]
version = "v0.6.1"
hash = "sha256-8eFcw4YI0w6+GPhU5xMMQjiio94q/O5PpNO3QsvXve0="
[mod."github.com/vcaesar/cedar"]
version = "v0.20.2"
hash = "sha256-3WblBdkR9AZcvZCKSteBV5kdhahiFHG2dbLWfwrVkwM="
[mod."github.com/wcharczuk/go-chart/v2"]
version = "v2.1.2"
hash = "sha256-GXWWea/u6BezTsPPrWhTYiTetPP/YW6P+Sj4YdocPaM="

View File

@@ -3,13 +3,13 @@
package banner
// Version ...
var Version = "v1.9.6"
var Version = "v1.9.7"
// Copyright ...
var Copyright = "© 2020 - 2025 FloatTech"
// Banner ...
var Banner = "* OneBot + ZeroBot + Golang\n" +
"* Version " + Version + " - 2025-03-30 23:46:38 +0900 JST\n" +
"* Version " + Version + " - 2025-05-14 21:52:40 +0900 JST\n" +
"* Copyright " + Copyright + ". All Rights Reserved.\n" +
"* Project: https://github.com/FloatTech/ZeroBot-Plugin"

View File

@@ -110,6 +110,7 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/mcfish" // 钓鱼模拟器
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/midicreate" // 简易midi音乐制作
_ "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" // 点歌

View File

@@ -2,25 +2,31 @@
package bilibili
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 (
enableHex = 0x10
unableHex = 0x7fffffff_fffffffd
enableHex = 0x10
unableHex = 0x7fffffff_fffffffd
bilibiliparseReferer = "https://www.bilibili.com"
)
var (
@@ -33,6 +39,7 @@ var (
searchDynamicRe = regexp.MustCompile(searchDynamic)
searchArticleRe = regexp.MustCompile(searchArticle)
searchLiveRoomRe = regexp.MustCompile(searchLiveRoom)
cachePath string
)
// 插件主体
@@ -42,6 +49,9 @@ func init() {
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]
@@ -126,6 +136,12 @@ func handleVideo(ctx *zero.Ctx) {
}
}
ctx.SendChain(msg...)
downLoadMsg, err := getVideoDownload(cfg, card, cachePath)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(downLoadMsg...)
}
func handleDynamic(ctx *zero.Ctx) {
@@ -189,3 +205,47 @@ func getVideoSummary(cookiecfg *bz.CookieConfig, card bz.Card) (msg []message.Se
}
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
}

View File

@@ -2,10 +2,12 @@ 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"
)
@@ -303,7 +305,10 @@ func liveCard2msg(card bz.RoomCard) (msg []message.Segment) {
// videoCard2msg 视频卡片转消息
func videoCard2msg(card bz.Card) (msg []message.Segment, err error) {
var mCard bz.MemberCard
var (
mCard bz.MemberCard
onlineTotal bz.OnlineTotal
)
msg = make([]message.Segment, 0, 16)
mCard, err = bz.GetMemberCard(card.Owner.Mid)
msg = append(msg, message.Text("标题: ", card.Title, "\n"))
@@ -313,16 +318,25 @@ func videoCard2msg(card bz.Card) (msg []message.Segment, err error) {
}
} else {
if err != nil {
err = nil
msg = append(msg, message.Text("UP主: ", card.Owner.Name, "\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",
data, err := web.GetData(fmt.Sprintf(bz.OnlineTotalURL, card.BvID, card.CID))
if err != nil {
return
}
err = json.Unmarshal(data, &onlineTotal)
if err != nil {
return
}
msg = append(msg, message.Text("👀播放: ", bz.HumanNum(card.Stat.View), " 💬弹幕: ", bz.HumanNum(card.Stat.Danmaku),
"\n👍点赞: ", bz.HumanNum(card.Stat.Like), " 💰投币: ", bz.HumanNum(card.Stat.Coin),
"\n📁收藏: ", bz.HumanNum(card.Stat.Favorite), " 🔗分享: ", bz.HumanNum(card.Stat.Share),
"\n📝简介: ", card.Desc,
"\n🏄 总共 ", onlineTotal.Data.Total, " 人在观看,", onlineTotal.Data.Count, " 人在网页端观看\n",
bz.VURL, card.BvID, "\n\n"))
return
}

View File

@@ -2,7 +2,8 @@
package kfccrazythursday
import (
"github.com/FloatTech/floatbox/binary"
"encoding/json"
"github.com/FloatTech/floatbox/web"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
@@ -11,9 +12,15 @@ import (
)
const (
crazyURL = "http://api.jixs.cc/api/wenan-fkxqs/index.php"
crazyURL = "https://api.pearktrue.cn/api/kfc/"
)
type crazyResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
Text string `json:"text"`
}
func init() {
engine := control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
@@ -26,6 +33,18 @@ func init() {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.SendChain(message.Text(binary.BytesToString(data)))
var resp crazyResponse
if err := json.Unmarshal(data, &resp); err != nil {
ctx.SendChain(message.Text("JSON解析失败: ", err))
return
}
if resp.Code != 200 {
ctx.SendChain(message.Text("API返回错误: ", resp.Msg))
return
}
ctx.SendChain(message.Text(resp.Text))
})
}

435
plugin/movies/main.go Normal file
View File

@@ -0,0 +1,435 @@
// Package movies 电影查询
package movies
import (
"encoding/json"
"image"
"net/http"
"os"
"path/filepath"
"sort"
"strconv"
"sync"
"time"
"github.com/FloatTech/floatbox/file"
"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/img/text"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
const (
apiURL = "https://m.maoyan.com/ajax/"
ua = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Mobile Safari/537.36"
)
var (
mu sync.RWMutex
todayPic = make([][]byte, 2)
lasttime time.Time
en = control.AutoRegister(&ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Brief: "电影查询",
Help: "- 今日电影\n" +
"- 预售电影",
PrivateDataFolder: "movies",
})
)
func init() {
en.OnFullMatch("今日电影").SetBlock(true).Handle(func(ctx *zero.Ctx) {
if todayPic != nil && time.Since(lasttime) < 12*time.Hour {
ctx.SendChain(message.ImageBytes(todayPic[0]))
return
}
lasttime = time.Now()
movieComingList, err := getMovieList("今日电影")
if err != nil {
ctx.SendChain(message.Text("[ERROR]:", err))
return
}
if len(movieComingList) == 0 {
ctx.SendChain(message.Text("没有今日电影"))
return
}
pic, err := drawOnListPic(movieComingList)
if err != nil {
ctx.SendChain(message.Text("[ERROR]:", err))
return
}
todayPic[0] = pic
ctx.SendChain(message.ImageBytes(pic))
})
en.OnFullMatch("预售电影").SetBlock(true).Handle(func(ctx *zero.Ctx) {
if todayPic[1] != nil && time.Since(lasttime) < 12*time.Hour {
ctx.SendChain(message.ImageBytes(todayPic[1]))
return
}
lasttime = time.Now()
movieComingList, err := getMovieList("预售电影")
if err != nil {
ctx.SendChain(message.Text("[ERROR]:", err))
return
}
if len(movieComingList) == 0 {
ctx.SendChain(message.Text("没有预售电影"))
return
}
pic, err := drawComListPic(movieComingList)
if err != nil {
ctx.SendChain(message.Text("[ERROR]:", err))
return
}
todayPic[1] = pic
ctx.SendChain(message.ImageBytes(pic))
})
}
type movieInfo struct {
ID int64 `json:"id"` // 电影ID
Img string `json:"img"` // 海报
Nm string `json:"nm"` // 名称
Dir string `json:"dir"` // 导演
Star string `json:"star"` // 演员
OriLang string `json:"oriLang"` // 原语言
Cat string `json:"cat"` // 类型
Version string `json:"version"` // 电影格式
Rt string `json:"rt"` // 上映时间
ShowInfo string `json:"showInfo"` // 今日上映信息
ComingTitle string `json:"comingTitle"` // 预售信息
Sc float64 `json:"sc"` // 评分
Wish int64 `json:"wish"` // 观看人数
Watched int64 `json:"watched"` // 观看数
}
type movieOnList struct {
MovieList []movieInfo `json:"movieList"`
}
type comingList struct {
MovieList []movieInfo `json:"coming"`
}
type movieShow struct {
MovieInfo movieInfo `json:"detailMovie"`
}
type cardInfo struct {
Avatar image.Image
TopLeftText string
BottomLeftText []string
RightText string
Rank string
}
func getMovieList(mode string) (movieList []movieInfo, err error) {
var data []byte
if mode == "今日电影" {
data, err = web.RequestDataWith(web.NewDefaultClient(), apiURL+"movieOnInfoList", "", "GET", ua, nil)
if err != nil {
return
}
var parsed movieOnList
err = json.Unmarshal(data, &parsed)
if err != nil {
return
}
movieList = parsed.MovieList
} else {
data, err = web.RequestDataWith(web.NewDefaultClient(), apiURL+"comingList?token=", "", "GET", ua, nil)
if err != nil {
return
}
var parsed comingList
err = json.Unmarshal(data, &parsed)
if err != nil {
return
}
movieList = parsed.MovieList
}
if len(movieList) == 0 {
return
}
for i, info := range movieList {
movieID := strconv.FormatInt(info.ID, 10)
data, err = web.RequestDataWith(web.NewDefaultClient(), apiURL+"detailmovie?movieId="+movieID, "", "GET", ua, nil)
if err != nil {
return
}
var movieInfo movieShow
err = json.Unmarshal(data, &movieInfo)
if err != nil {
return
}
if mode != "今日电影" {
movieInfo.MovieInfo.ComingTitle = movieList[i].ComingTitle
}
movieList[i] = movieInfo.MovieInfo
}
// 整理数据,进行排序
sort.Slice(movieList, func(i, j int) bool {
if movieList[i].Sc != movieList[j].Sc {
return movieList[i].Sc > movieList[j].Sc
}
if mode == "今日电影" {
return movieList[i].Watched > movieList[j].Watched
}
return movieList[i].Wish > movieList[j].Wish
})
return movieList, nil
}
func drawOnListPic(lits []movieInfo) (data []byte, err error) {
rankinfo := make([]*cardInfo, len(lits))
wg := &sync.WaitGroup{}
wg.Add(len(lits))
for i := 0; i < len(lits); i++ {
go func(i int) {
info := lits[i]
defer wg.Done()
img, err := avatar(&info)
if err != nil {
return
}
movieType := "2D"
if info.Version != "" {
movieType = info.Version
}
watched := ""
switch {
case info.Watched > 100000000:
watched = strconv.FormatFloat(float64(info.Watched)/100000000, 'f', 2, 64) + "亿"
case info.Watched > 10000:
watched = strconv.FormatFloat(float64(info.Watched)/10000, 'f', 2, 64) + "万"
default:
watched = strconv.FormatInt(info.Watched, 10)
}
rankinfo[i] = &cardInfo{
TopLeftText: info.Nm + " (" + strconv.FormatInt(info.ID, 10) + ")",
BottomLeftText: []string{
"导演:" + info.Dir,
"演员:" + info.Star,
"标签:" + info.Cat,
"语言: " + info.OriLang + " 类型: " + movieType,
"上映时间: " + info.Rt,
},
RightText: watched + "人已看",
Avatar: img,
Rank: strconv.FormatFloat(info.Sc, 'f', 1, 64),
}
}(i)
}
wg.Wait()
fontbyte, err := file.GetLazyData(text.GlowSansFontFile, control.Md5File, true)
if err != nil {
return
}
img, err := drawRankingCard(fontbyte, "今日电影", rankinfo)
if err != nil {
return
}
data, err = imgfactory.ToBytes(img)
return
}
func drawComListPic(lits []movieInfo) (data []byte, err error) {
rankinfo := make([]*cardInfo, len(lits))
wg := &sync.WaitGroup{}
wg.Add(len(lits))
for i := 0; i < len(lits); i++ {
go func(i int) {
info := lits[i]
defer wg.Done()
img, err := avatar(&info)
if err != nil {
return
}
movieType := "2D"
if info.Version != "" {
movieType = info.Version
}
wish := ""
switch {
case info.Wish > 100000000:
wish = strconv.FormatFloat(float64(info.Wish)/100000000, 'f', 2, 64) + "亿"
case info.Wish > 10000:
wish = strconv.FormatFloat(float64(info.Wish)/10000, 'f', 2, 64) + "万"
default:
wish = strconv.FormatInt(info.Wish, 10)
}
rankinfo[i] = &cardInfo{
TopLeftText: info.Nm + " (" + strconv.FormatInt(info.ID, 10) + ")",
BottomLeftText: []string{
"导演:" + info.Dir,
"演员:" + info.Star,
"标签:" + info.Cat,
"语言: " + info.OriLang + " 类型: " + movieType,
"上映时间: " + info.Rt + " 播放时间: " + info.ComingTitle,
},
RightText: wish + "人期待",
Avatar: img,
Rank: strconv.Itoa(i + 1),
}
}(i)
}
wg.Wait()
fontbyte, err := file.GetLazyData(text.GlowSansFontFile, control.Md5File, true)
if err != nil {
return
}
img, err := drawRankingCard(fontbyte, "预售电影", rankinfo)
if err != nil {
return
}
data, err = imgfactory.ToBytes(img)
return
}
func drawRankingCard(fontdata []byte, title string, rankinfo []*cardInfo) (img image.Image, err error) {
line := len(rankinfo)
const lineh = 130
const w = 800
h := 64 + (lineh+14)*line + 20 - 14
canvas := gg.NewContext(w, h)
canvas.SetRGBA255(255, 255, 255, 255)
canvas.Clear()
cardh, cardw := lineh, 770
cardspac := 14
hspac, wspac := 64.0, 16.0
r := 16.0
wg := &sync.WaitGroup{}
wg.Add(line)
cardimgs := make([]image.Image, line)
for i := 0; i < line; i++ {
go func(i int) {
defer wg.Done()
card := gg.NewContext(w, cardh)
card.NewSubPath()
card.MoveTo(wspac+float64(cardh)/2, 0)
card.LineTo(wspac+float64(cardw)-r, 0)
card.DrawArc(wspac+float64(cardw)-r, r, r, gg.Radians(-90), gg.Radians(0))
card.LineTo(wspac+float64(cardw), float64(cardh)-r)
card.DrawArc(wspac+float64(cardw)-r, float64(cardh)-r, r, gg.Radians(0), gg.Radians(90))
card.LineTo(wspac+float64(cardh)/2, float64(cardh))
card.DrawArc(wspac+r, float64(cardh)-r, r, gg.Radians(90), gg.Radians(180))
card.LineTo(wspac, r)
card.DrawArc(wspac+r, r, r, gg.Radians(180), gg.Radians(270))
card.ClosePath()
card.ClipPreserve()
avatar := rankinfo[i].Avatar
PicH := cardh - 20
picW := int(float64(avatar.Bounds().Dx()) * float64(PicH) / float64(avatar.Bounds().Dy()))
card.DrawImageAnchored(imgfactory.Size(avatar, picW, PicH).Image(), int(wspac)+10+picW/2, cardh/2, 0.5, 0.5)
card.ResetClip()
card.SetRGBA255(0, 0, 0, 127)
card.Stroke()
card.SetRGBA255(240, 210, 140, 200)
card.DrawRoundedRectangle(wspac+float64(cardw-8-250), (float64(cardh)-50)/2, 250, 50, 25)
card.Fill()
card.SetRGB255(rendercard.RandJPColor())
card.DrawRoundedRectangle(wspac+float64(cardw-8-60), (float64(cardh)-50)/2, 60, 50, 25)
card.Fill()
cardimgs[i] = card.Image()
}(i)
}
canvas.SetRGBA255(0, 0, 0, 255)
err = canvas.ParseFontFace(fontdata, 32)
if err != nil {
return
}
canvas.DrawStringAnchored(title, w/2, 64/2, 0.5, 0.5)
err = canvas.ParseFontFace(fontdata, 22)
if err != nil {
return
}
wg.Wait()
for i := 0; i < line; i++ {
canvas.DrawImageAnchored(cardimgs[i], w/2, int(hspac)+((cardh+cardspac)*i), 0.5, 0)
canvas.DrawStringAnchored(rankinfo[i].TopLeftText, wspac+10+80+10, hspac+float64((cardspac+cardh)*i+cardh*3/16), 0, 0.5)
}
// canvas.SetRGBA255(63, 63, 63, 255)
err = canvas.ParseFontFace(fontdata, 14)
if err != nil {
return
}
for i := 0; i < line; i++ {
for j, text := range rankinfo[i].BottomLeftText {
canvas.DrawStringAnchored(text, wspac+10+80+10, hspac+float64((cardspac+cardh)*i+cardh*6/16)+float64(j*16), 0, 0.5)
}
}
canvas.SetRGBA255(0, 0, 0, 255)
err = canvas.ParseFontFace(fontdata, 20)
if err != nil {
return
}
for i := 0; i < line; i++ {
canvas.DrawStringAnchored(rankinfo[i].RightText, w-wspac-8-60-8, hspac+float64((cardspac+cardh)*i+cardh/2), 1, 0.5)
}
canvas.SetRGBA255(255, 255, 255, 255)
err = canvas.ParseFontFace(fontdata, 28)
if err != nil {
return
}
for i := 0; i < line; i++ {
canvas.DrawStringAnchored(rankinfo[i].Rank, w-wspac-8-30, hspac+float64((cardspac+cardh)*i+cardh/2), 0.5, 0.5)
}
img = canvas.Image()
return
}
// avatar 获取电影海报,图片大且多,存本地增加响应速度
func avatar(movieInfo *movieInfo) (pic image.Image, err error) {
mu.Lock()
defer mu.Unlock()
aimgfile := filepath.Join(en.DataFolder(), movieInfo.Nm+"("+strconv.FormatInt(movieInfo.ID, 10)+").jpg")
if file.IsNotExist(aimgfile) {
err = file.DownloadTo(movieInfo.Img, aimgfile)
if err != nil {
return urlToImg(movieInfo.Img)
}
}
f, err := os.Open(filepath.Join(file.BOTPATH, aimgfile))
if err != nil {
return urlToImg(movieInfo.Img)
}
defer f.Close()
pic, _, err = image.Decode(f)
return
}
func urlToImg(url string) (img image.Image, err error) {
resp, err := http.Get(url)
if err != nil {
return
}
defer resp.Body.Close()
img, _, err = image.Decode(resp.Body)
return
}

View File

@@ -2,11 +2,10 @@
package thesaurus
import (
"bytes"
"math/rand"
"strings"
"github.com/fumiama/jieba"
"github.com/go-ego/gse"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
@@ -55,11 +54,8 @@ func init() {
ctx.SendChain(message.Text("成功!"))
})
go func() {
data, err := engine.GetLazyData("dict.txt", false)
if err != nil {
panic(err)
}
seg, err := jieba.LoadDictionary(bytes.NewReader(data))
var seg gse.Segmenter
err := seg.LoadDictEmbed()
if err != nil {
panic(err)
}
@@ -102,10 +98,10 @@ func init() {
ctx.SendChain(message.Text(r.Reply))
}
})
engine.OnMessage(zero.OnlyToMe, canmatch(tDERE), match(chatListD, seg)).
engine.OnMessage(zero.OnlyToMe, canmatch(tDERE), match(chatListD, &seg)).
SetBlock(false).
Handle(randreply(sm.D))
engine.OnMessage(zero.OnlyToMe, canmatch(tKAWA), match(chatListK, seg)).
engine.OnMessage(zero.OnlyToMe, canmatch(tKAWA), match(chatListK, &seg)).
SetBlock(false).
Handle(randreply(sm.K))
}()
@@ -122,7 +118,7 @@ const (
tKAWA
)
func match(l []string, seg *jieba.Segmenter) zero.Rule {
func match(l []string, seg *gse.Segmenter) zero.Rule {
return func(ctx *zero.Ctx) bool {
return ctxext.JiebaSimilarity(0.66, seg, func(ctx *zero.Ctx) string {
return ctx.ExtractPlainText()

View File

@@ -11,6 +11,12 @@ import (
"sync"
"time"
"github.com/go-ego/gse"
"github.com/golang/freetype"
"github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
"github.com/wcharczuk/go-chart/v2"
"github.com/FloatTech/floatbox/binary"
fcext "github.com/FloatTech/floatbox/ctxext"
"github.com/FloatTech/floatbox/file"
@@ -18,17 +24,16 @@ import (
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
"github.com/FloatTech/zbputils/img/text"
"github.com/golang/freetype"
"github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
"github.com/wcharczuk/go-chart/v2"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
"github.com/wdvxdr1123/ZeroBot/utils/helper"
)
var (
re = regexp.MustCompile(`^[一-龥]+$`)
stopwords []string
seg gse.Segmenter
)
func init() {
@@ -39,6 +44,11 @@ func init() {
PublicDataFolder: "WordCount",
})
cachePath := engine.DataFolder() + "cache/"
// 读取gse内置中文词典
err := seg.LoadDictEmbed()
if err != nil {
panic(err)
}
_ = os.RemoveAll(cachePath)
_ = os.MkdirAll(cachePath, 0755)
engine.OnRegex(`^热词\s?(\d*)\s?(\d*)$`, zero.OnlyGroup, fcext.DoOnceOnSuccess(func(ctx *zero.Ctx) bool {
@@ -120,12 +130,14 @@ func init() {
if tex == "" {
continue
}
for _, t := range ctx.GetWordSlices(tex).Get("slices").Array() {
tex := strings.TrimSpace(t.Str)
i := sort.SearchStrings(stopwords, tex)
if re.MatchString(tex) && (i >= len(stopwords) || stopwords[i] != tex) {
segments := seg.Segment(helper.StringToBytes(tex))
words := gse.ToSlice(segments, true)
for _, word := range words {
word = strings.TrimSpace(word)
i := sort.SearchStrings(stopwords, word)
if re.MatchString(word) && (i >= len(stopwords) || stopwords[i] != word) {
mapmu.Lock()
messageMap[tex]++
messageMap[word]++
mapmu.Unlock()
}
}

View File

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

View File

@@ -12,7 +12,7 @@
"0409": {
"identity": {
"name": "ZeroBot-Plugin",
"version": "1.9.6.2202"
"version": "1.9.7.2217"
},
"description": "",
"minimum-os": "vista",
@@ -36,23 +36,23 @@
"#1": {
"0000": {
"fixed": {
"file_version": "1.9.6.2202",
"product_version": "v1.9.6",
"timestamp": "2025-03-30T23:46:55+08:00"
"file_version": "1.9.7.2217",
"product_version": "v1.9.7",
"timestamp": "2025-05-14T21:53:06+08:00"
},
"info": {
"0409": {
"Comments": "OneBot plugins based on ZeroBot",
"CompanyName": "FloatTech",
"FileDescription": "https://github.com/FloatTech/ZeroBot-Plugin",
"FileVersion": "1.9.6.2202",
"FileVersion": "1.9.7.2217",
"InternalName": "",
"LegalCopyright": "© 2020 - 2025 FloatTech. All Rights Reserved.",
"LegalTrademarks": "",
"OriginalFilename": "ZBP.EXE",
"PrivateBuild": "",
"ProductName": "ZeroBot-Plugin",
"ProductVersion": "v1.9.6",
"ProductVersion": "v1.9.7",
"SpecialBuild": ""
}
}