mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 13:59:39 +08:00
👍 添加查成分功能,修改bilibili插件的正则 (#171)
* ✨添加查成分功能 * 🚨修lint * 🚨减少空格 * 🐛修改网址 * 🐛修改vup数量错误问题 * 🐛图片读取不了,就不读了 * 🐛 固定头像大小,bilibilipush调公有库 * 🎨 修改json转换 Co-authored-by: Guohuiyuan <haibaraguo@yeahka.com>
This commit is contained in:
parent
7be1a61347
commit
006ef6f672
11
README.md
11
README.md
@ -268,8 +268,11 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- [x] 个人猜单词
|
||||
- [x] 团队猜单词
|
||||
- **bilibili** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"`
|
||||
- [x] >vup info [名字 | uid]
|
||||
- [x] >user info [名字 | uid]
|
||||
- [x] >vup info [xxx]
|
||||
- [x] >user info [xxx]
|
||||
- [x] 查成分 [xxx]
|
||||
- [x] 设置b站cookie SESSDATA=82da790d,1663822823,06ecf*31
|
||||
- [x] 更新vup
|
||||
- **嘉然** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana"`
|
||||
- [x] 小作文
|
||||
- [x] 发大病
|
||||
@ -371,12 +374,12 @@ print("run[CQ:image,file="+j["img"]+"]")
|
||||
- api早上8点更新,推荐定时在8点30后。配合插件`job`中的记录在"cron"触发的指令使用
|
||||
- [x] /启用 zaobao
|
||||
- [x] /禁用 zaobao
|
||||
- **舔狗日记** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou"`
|
||||
- [x] 舔狗日记
|
||||
```
|
||||
记录在"00 9 * * *"触发的指令
|
||||
今日早报
|
||||
```
|
||||
- **舔狗日记** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou"`
|
||||
- [x] 舔狗日记
|
||||
- **TODO...**
|
||||
|
||||
## 使用方法
|
||||
|
||||
179
plugin/bilibili/api.go
Normal file
179
plugin/bilibili/api.go
Normal file
@ -0,0 +1,179 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/tidwall/gjson"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var (
|
||||
errNeedCookie = errors.New("该api需要设置b站cookie,请发送命令设置cookie,例如\"设置b站cookie SESSDATA=82da790d,1663822823,06ecf*31\"")
|
||||
)
|
||||
|
||||
type searchResult struct {
|
||||
Mid int64 `json:"mid"`
|
||||
Uname string `json:"uname"`
|
||||
Gender int64 `json:"gender"`
|
||||
Usign string `json:"usign"`
|
||||
Level int64 `json:"level"`
|
||||
}
|
||||
|
||||
// 搜索api:通过把触发指令传入的昵称找出uid返回
|
||||
func search(keyword string) (r []searchResult, err error) {
|
||||
searchURL := "http://api.bilibili.com/x/web-interface/search/type?search_type=bili_user&keyword=" + keyword
|
||||
data, err := web.GetData(searchURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
j := gjson.ParseBytes(data)
|
||||
if j.Get("data.numResults").Int() == 0 {
|
||||
err = errors.New("查无此人")
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(binary.StringToBytes(j.Get("data.result").Raw), &r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type follower struct {
|
||||
Mid int `json:"mid"`
|
||||
Uname string `json:"uname"`
|
||||
Video int `json:"video"`
|
||||
Roomid int `json:"roomid"`
|
||||
Rise int `json:"rise"`
|
||||
Follower int `json:"follower"`
|
||||
GuardNum int `json:"guardNum"`
|
||||
AreaRank int `json:"areaRank"`
|
||||
}
|
||||
|
||||
// 请求api
|
||||
func fansapi(uid string) (result follower, err error) {
|
||||
fanURL := "https://api.vtbs.moe/v1/detail/" + uid
|
||||
data, err := web.GetData(fanURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(data, &result); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func followings(uid string) (s string, err error) {
|
||||
followingURL := "https://api.bilibili.com/x/relation/same/followings?vmid=" + uid
|
||||
method := "GET"
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest(method, followingURL, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c := vdb.getBilibiliCookie()
|
||||
req.Header.Add("cookie", c.Value)
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
json := gjson.ParseBytes(body)
|
||||
s = json.Get("data.list.#.uname").Raw
|
||||
if json.Get("code").Int() == -101 {
|
||||
err = errNeedCookie
|
||||
return
|
||||
}
|
||||
if json.Get("code").Int() != 0 {
|
||||
err = errors.New(json.Get("message").String())
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type userinfo struct {
|
||||
Name string `json:"name"`
|
||||
Mid string `json:"mid"`
|
||||
Face string `json:"face"`
|
||||
Fans int64 `json:"fans"`
|
||||
Attentions []int64 `json:"attentions"`
|
||||
}
|
||||
|
||||
type medalInfo struct {
|
||||
Mid int64 `json:"target_id"`
|
||||
MedalName string `json:"medal_name"`
|
||||
Level int64 `json:"level"`
|
||||
MedalColorStart int64 `json:"medal_color_start"`
|
||||
MedalColorEnd int64 `json:"medal_color_end"`
|
||||
MedalColorBorder int64 `json:"medal_color_border"`
|
||||
}
|
||||
type medal struct {
|
||||
Uname string `json:"target_name"`
|
||||
medalInfo `json:"medal_info"`
|
||||
}
|
||||
|
||||
type medalSlice []medal
|
||||
|
||||
func (m medalSlice) Len() int {
|
||||
return len(m)
|
||||
}
|
||||
func (m medalSlice) Swap(i, j int) {
|
||||
m[i], m[j] = m[j], m[i]
|
||||
}
|
||||
func (m medalSlice) Less(i, j int) bool {
|
||||
return m[i].Level > m[j].Level
|
||||
}
|
||||
|
||||
// 获取详情
|
||||
func card(uid string) (result userinfo, err error) {
|
||||
cardURL := "https://account.bilibili.com/api/member/getCardByMid?mid=" + uid
|
||||
data, err := web.GetData(cardURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("card").Raw), &result)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获得牌子
|
||||
func medalwall(uid string) (result []medal, err error) {
|
||||
medalwallURL := "https://api.live.bilibili.com/xlive/web-ucenter/user/MedalWall?target_id=" + uid
|
||||
method := "GET"
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest(method, medalwallURL, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c := vdb.getBilibiliCookie()
|
||||
req.Header.Add("cookie", c.Value)
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
data, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println("medalwall:", binary.BytesToString(data))
|
||||
j := gjson.ParseBytes(data)
|
||||
if j.Get("code").Int() == -101 {
|
||||
err = errNeedCookie
|
||||
return
|
||||
}
|
||||
if j.Get("code").Int() != 0 {
|
||||
err = errors.New(j.Get("message").String())
|
||||
}
|
||||
_ = json.Unmarshal(binary.StringToBytes(j.Get("data.list").Raw), &result)
|
||||
return
|
||||
}
|
||||
@ -2,64 +2,290 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
control "github.com/FloatTech/zbputils/control"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/FloatTech/zbputils/control/order"
|
||||
"github.com/FloatTech/zbputils/file"
|
||||
"github.com/FloatTech/zbputils/img"
|
||||
"github.com/FloatTech/zbputils/img/text"
|
||||
"github.com/FloatTech/zbputils/img/writer"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/fogleman/gg"
|
||||
log "github.com/sirupsen/logrus"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
|
||||
"github.com/FloatTech/zbputils/control/order"
|
||||
)
|
||||
|
||||
var engine = control.Register("bilibili", order.AcquirePrio(), &control.Options{
|
||||
DisableOnDefault: false,
|
||||
Help: "bilibili\n" +
|
||||
"- >vup info [名字 | uid]\n" +
|
||||
"- >user info [名字 | uid]",
|
||||
"- >vup info [xxx]\n" +
|
||||
"- >user info [xxx]\n" +
|
||||
"- 查成分 [xxx]\n" +
|
||||
"- 设置b站cookie SESSDATA=82da790d,1663822823,06ecf*31\n" +
|
||||
"- 更新vup",
|
||||
PublicDataFolder: "Bilibili",
|
||||
})
|
||||
|
||||
// 查成分的
|
||||
func init() {
|
||||
engine.OnRegex(`^>(?:user|vup)\s?info\s?(.{1,25})$`).SetBlock(true).
|
||||
cachePath := engine.DataFolder() + "cache/"
|
||||
dbfile := engine.DataFolder() + "bilibili.db"
|
||||
go func() {
|
||||
_ = os.MkdirAll(cachePath, 0755)
|
||||
_, _ = file.GetLazyData(dbfile, false, false)
|
||||
vdb = initialize(dbfile)
|
||||
}()
|
||||
|
||||
engine.OnRegex(`^>user info\s?(.{1,25})$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
rest, err := uid(keyword)
|
||||
uidRes, err := search(keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
id := rest.Get("data.result.0.mid").String()
|
||||
url := "https://api.bilibili.com/x/relation/same/followings?vmid=" + id
|
||||
method := "GET"
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest(method, url, nil)
|
||||
id := strconv.FormatInt(uidRes[0].Mid, 10)
|
||||
follwings, err := followings(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
req.Header.Add("cookie", "CURRENT_FNVAL=80; _uuid=772B88E8-3ED1-D589-29BB-F6CB5214239A06137infoc; blackside_state=1; bfe_id=6f285c892d9d3c1f8f020adad8bed553; rpdid=|(umY~Jkl|kJ0J'uYkR|)lu|); fingerprint=0ec2b1140fb30b56d7b5e415bc3b5fb1; buvid_fp=C91F5265-3DF4-4D5A-9FF3-C546370B14C0143096infoc; buvid_fp_plain=C91F5265-3DF4-4D5A-9FF3-C546370B14C0143096infoc; SESSDATA=9e0266f6%2C1639637127%2Cb0172%2A61; bili_jct=96ddbd7e22d527abdc0501339a12d4d3; DedeUserID=695737880; DedeUserID__ckMd5=0117660e75db7b01; sid=5labuhaf; PVID=1; bfe_id=1e33d9ad1cb29251013800c68af42315")
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
data := string(body)
|
||||
ctx.SendChain(message.Text(
|
||||
"uid: ", rest.Get("data.result.0.mid").Int(), "\n",
|
||||
"name: ", rest.Get("data.result.0.uname").Str, "\n",
|
||||
"sex: ", []string{"", "", "女", "男"}[rest.Get("data.result.0.gender").Int()], "\n",
|
||||
"sign: ", rest.Get("data.result.0.usign").Str, "\n",
|
||||
"level: ", rest.Get("data.result.0.level").Int(), "\n",
|
||||
"follow: ", gjson.Get(data, "data.list.#.uname"),
|
||||
"search: ", uidRes[0].Mid, "\n",
|
||||
"name: ", uidRes[0].Uname, "\n",
|
||||
"sex: ", []string{"", "男", "女", "未知"}[uidRes[0].Gender], "\n",
|
||||
"sign: ", uidRes[0].Usign, "\n",
|
||||
"level: ", uidRes[0].Level, "\n",
|
||||
"follow: ", follwings,
|
||||
))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^>vup info\s?(.{1,25})$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
res, err := search(keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
id := strconv.FormatInt(res[0].Mid, 10)
|
||||
// 获取详情
|
||||
fo, err := fansapi(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(
|
||||
"search: ", fo.Mid, "\n",
|
||||
"名字: ", fo.Uname, "\n",
|
||||
"当前粉丝数: ", fo.Follower, "\n",
|
||||
"24h涨粉数: ", fo.Rise, "\n",
|
||||
"视频投稿数: ", fo.Video, "\n",
|
||||
"直播间id: ", fo.Roomid, "\n",
|
||||
"舰队: ", fo.GuardNum, "\n",
|
||||
"直播总排名: ", fo.AreaRank, "\n",
|
||||
"数据来源: ", "https://vtbs.moe/detail/", fo.Mid, "\n",
|
||||
"数据获取时间: ", time.Now().Format("2006-01-02 15:04:05"),
|
||||
))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^查成分\s?(.{1,25})$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
searchRes, err := search(keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
id := strconv.FormatInt(searchRes[0].Mid, 10)
|
||||
today := time.Now().Format("20060102")
|
||||
drawedFile := cachePath + id + today + "vupLike.png"
|
||||
if file.IsExist(drawedFile) {
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
return
|
||||
}
|
||||
u, err := card(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
vups, err := vdb.filterVup(u.Attentions)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
vupLen := len(vups)
|
||||
medals, err := medalwall(id)
|
||||
sort.Sort(medalSlice(medals))
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
}
|
||||
frontVups := make([]vup, 0)
|
||||
medalMap := make(map[int64]medal)
|
||||
for _, v := range medals {
|
||||
up := vup{
|
||||
Mid: v.Mid,
|
||||
Uname: v.Uname,
|
||||
}
|
||||
frontVups = append(frontVups, up)
|
||||
medalMap[v.Mid] = v
|
||||
}
|
||||
vups = append(vups, frontVups...)
|
||||
copy(vups[len(frontVups):], vups[:])
|
||||
copy(vups[:], frontVups)
|
||||
for i := len(frontVups); i < len(vups); i++ {
|
||||
if _, ok := medalMap[vups[i].Mid]; ok {
|
||||
vups = append(vups[:i], vups[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
facePath := cachePath + id + "vupFace.png"
|
||||
initFacePic(facePath, u.Face)
|
||||
var backX int
|
||||
var backY int
|
||||
back, err := gg.LoadImage(facePath)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
backX = 500
|
||||
backY = 500
|
||||
} else {
|
||||
back = img.Limit(back, 500, 500)
|
||||
backX = back.Bounds().Size().X
|
||||
backY = back.Bounds().Size().Y
|
||||
}
|
||||
if len(vups) > 50 {
|
||||
ctx.SendChain(message.Text(u.Name + "关注的up主太多了,只展示前50个up"))
|
||||
vups = vups[:50]
|
||||
}
|
||||
canvas := gg.NewContext(backX*3, int(float64(backY)*(1.1+float64(len(vups))/3)))
|
||||
fontSize := float64(backX) * 0.1
|
||||
canvas.SetColor(color.White)
|
||||
canvas.Clear()
|
||||
if back != nil {
|
||||
canvas.DrawImage(back, 0, 0)
|
||||
}
|
||||
canvas.SetColor(color.Black)
|
||||
if err = canvas.LoadFontFace(text.BoldFontFile, fontSize); err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
sl, _ := canvas.MeasureString("好")
|
||||
length, h := canvas.MeasureString(u.Mid)
|
||||
n, _ := canvas.MeasureString(u.Name)
|
||||
canvas.DrawString(u.Name, float64(backX)*1.1, float64(backY)/3-h)
|
||||
canvas.DrawRoundedRectangle(float64(backX)*1.2+n-length*0.1, float64(backY)/3-h*2.5, length*1.2, h*2, fontSize*0.2)
|
||||
canvas.SetRGB255(221, 221, 221)
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.Black)
|
||||
canvas.DrawString(u.Mid, float64(backX)*1.2+n, float64(backY)/3-h)
|
||||
canvas.DrawString(fmt.Sprintf("粉丝:%d", u.Fans), float64(backX)*1.1, float64(backY)/3*2-2.5*h)
|
||||
canvas.DrawString(fmt.Sprintf("关注:%d", len(u.Attentions)), float64(backX)*2, float64(backY)/3*2-2.5*h)
|
||||
canvas.DrawString(fmt.Sprintf("管人痴成分:%.2f%%(%d/%d)", float64(vupLen)/float64(len(u.Attentions))*100, vupLen, len(u.Attentions)), float64(backX)*1.1, float64(backY)-4*h)
|
||||
canvas.DrawString("日期:"+time.Now().Format("2006-01-02"), float64(backX)*1.1, float64(backY)-h)
|
||||
for i, v := range vups {
|
||||
if i%2 == 1 {
|
||||
canvas.SetRGB255(245, 245, 245)
|
||||
canvas.DrawRectangle(0, float64(backY)*1.1+float64(i)*float64(backY)/3, float64(backX*3), float64(backY)/3)
|
||||
canvas.Fill()
|
||||
}
|
||||
canvas.SetColor(color.Black)
|
||||
nl, _ := canvas.MeasureString(v.Uname)
|
||||
canvas.DrawString(v.Uname, float64(backX)*0.1, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
ml, _ := canvas.MeasureString(strconv.FormatInt(v.Mid, 10))
|
||||
canvas.DrawRoundedRectangle(nl-0.1*ml+float64(backX)*0.2, float64(backY)*1.1+float64(i+1)*float64(backY)/3-h*3.5, ml*1.2, h*2, fontSize*0.2)
|
||||
canvas.SetRGB255(221, 221, 221)
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.Black)
|
||||
canvas.DrawString(strconv.FormatInt(v.Mid, 10), nl+float64(backX)*0.2, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
if m, ok := medalMap[v.Mid]; ok {
|
||||
mnl, _ := canvas.MeasureString(m.MedalName)
|
||||
grad := gg.NewLinearGradient(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h, nl+ml+mnl+sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
r, g, b := int2rbg(m.MedalColorStart)
|
||||
grad.AddColorStop(0, color.RGBA{uint8(r), uint8(g), uint8(b), 255})
|
||||
r, g, b = int2rbg(m.MedalColorEnd)
|
||||
grad.AddColorStop(1, color.RGBA{uint8(r), uint8(g), uint8(b), 255})
|
||||
canvas.SetFillStyle(grad)
|
||||
canvas.SetLineWidth(4)
|
||||
canvas.MoveTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.LineTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.ClosePath()
|
||||
canvas.Fill()
|
||||
canvas.SetColor(color.White)
|
||||
canvas.DrawString(m.MedalName, nl+ml+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
r, g, b = int2rbg(m.MedalColorBorder)
|
||||
canvas.SetRGB255(int(r), int(g), int(b))
|
||||
canvas.DrawString(strconv.FormatInt(m.Level, 10), nl+ml+mnl+sl+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-2*h)
|
||||
mll, _ := canvas.MeasureString(strconv.FormatInt(m.Level, 10))
|
||||
canvas.SetLineWidth(4)
|
||||
canvas.MoveTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+mll+sl/2+float64(backX)*0.5, float64(backY)*1.1+float64(i+1)*float64(backY)/3-3.5*h)
|
||||
canvas.LineTo(nl+ml+mnl+mll+sl/2+float64(backX)*0.5, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.LineTo(nl+ml-sl/2+float64(backX)*0.4, float64(backY)*1.1+float64(i+1)*float64(backY)/3-1.5*h)
|
||||
canvas.ClosePath()
|
||||
canvas.Stroke()
|
||||
}
|
||||
}
|
||||
f, err := os.Create(drawedFile)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
data, cl := writer.ToBytes(canvas.Image())
|
||||
ctx.SendChain(message.ImageBytes(data))
|
||||
cl()
|
||||
return
|
||||
}
|
||||
_, err = writer.WriteTo(canvas.Image(), f)
|
||||
_ = f.Close()
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
|
||||
})
|
||||
|
||||
engine.OnRegex(`^设置b站cookie?\s+(.{1,100})$`, zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
cookie := ctx.State["regex_matched"].([]string)[1]
|
||||
err := vdb.setBilibiliCookie(cookie)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text("成功设置b站cookie为" + cookie))
|
||||
})
|
||||
|
||||
engine.OnFullMatch("更新vup", zero.SuperUserPermission).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
ctx.SendChain(message.Text("少女祈祷中..."))
|
||||
updateVup()
|
||||
ctx.SendChain(message.Text("vup已更新"))
|
||||
})
|
||||
}
|
||||
|
||||
func initFacePic(filename, faceURL string) {
|
||||
if file.IsNotExist(filename) {
|
||||
data, err := web.GetData(faceURL)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
}
|
||||
err = os.WriteFile(filename, data, 0666)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func int2rbg(t int64) (int64, int64, int64) {
|
||||
var buf [8]byte
|
||||
binary.LittleEndian.PutUint64(buf[:], uint64(t))
|
||||
b, g, r := int64(buf[0]), int64(buf[1]), int64(buf[2])
|
||||
return r, g, b
|
||||
}
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
"github.com/tidwall/gjson"
|
||||
zero "github.com/wdvxdr1123/ZeroBot"
|
||||
"github.com/wdvxdr1123/ZeroBot/message"
|
||||
)
|
||||
|
||||
// 查vup粉丝数据
|
||||
func init() {
|
||||
engine.OnRegex(`^>vup info\s?(.{1,25})$`).SetBlock(true).
|
||||
Handle(func(ctx *zero.Ctx) {
|
||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||
res, err := uid(keyword)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
id := res.Get("data.result.0.mid").String()
|
||||
// 获取详情
|
||||
fo, err := fansapi(id)
|
||||
if err != nil {
|
||||
ctx.SendChain(message.Text("ERROR:", err))
|
||||
return
|
||||
}
|
||||
ctx.SendChain(message.Text(
|
||||
"uid: ", fo.Mid, "\n",
|
||||
"名字: ", fo.Uname, "\n",
|
||||
"当前粉丝数: ", fo.Follower, "\n",
|
||||
"24h涨粉数: ", fo.Rise, "\n",
|
||||
"视频投稿数: ", fo.Video, "\n",
|
||||
"直播间id: ", fo.Roomid, "\n",
|
||||
"舰队: ", fo.GuardNum, "\n",
|
||||
"直播总排名: ", fo.AreaRank, "\n",
|
||||
"数据来源: ", "https://vtbs.moe/detail/", fo.Mid, "\n",
|
||||
"数据获取时间: ", time.Now().Format("2006-01-02 15:04:05"),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
// 搜索api:通过把触发指令传入的昵称找出uid返回
|
||||
func uid(keyword string) (*gjson.Result, error) {
|
||||
api := "http://api.bilibili.com/x/web-interface/search/type?search_type=bili_user&&user_type=1&keyword=" + keyword
|
||||
data, err := web.GetData(api)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
json := gjson.ParseBytes(data)
|
||||
if json.Get("data.numResults").Int() == 0 {
|
||||
return nil, errors.New("查无此人")
|
||||
}
|
||||
return &json, nil
|
||||
}
|
||||
|
||||
type follower struct {
|
||||
Mid int `json:"mid"`
|
||||
Uname string `json:"uname"`
|
||||
Video int `json:"video"`
|
||||
Roomid int `json:"roomid"`
|
||||
Rise int `json:"rise"`
|
||||
Follower int `json:"follower"`
|
||||
GuardNum int `json:"guardNum"`
|
||||
AreaRank int `json:"areaRank"`
|
||||
}
|
||||
|
||||
// 请求api
|
||||
func fansapi(uid string) (*follower, error) {
|
||||
url := "https://api.vtbs.moe/v1/detail/" + uid
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
result := &follower{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
129
plugin/bilibili/model.go
Normal file
129
plugin/bilibili/model.go
Normal file
@ -0,0 +1,129 @@
|
||||
package bilibili
|
||||
|
||||
import (
|
||||
"github.com/FloatTech/zbputils/binary"
|
||||
"github.com/FloatTech/zbputils/web"
|
||||
_ "github.com/fumiama/sqlite3" // use sql
|
||||
"github.com/jinzhu/gorm"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/tidwall/gjson"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
bilibiliCookie = "bilbili_cookie"
|
||||
)
|
||||
|
||||
var (
|
||||
vtbURLs = [...]string{"https://api.vtbs.moe/v1/short", "https://api.tokyo.vtbs.moe/v1/short", "https://vtbs.musedash.moe/v1/short"}
|
||||
vdb *vupdb
|
||||
)
|
||||
|
||||
// vupdb 分数数据库
|
||||
type vupdb gorm.DB
|
||||
|
||||
type vup struct {
|
||||
Mid int64 `gorm:"column:mid;primary_key"`
|
||||
Uname string `gorm:"column:uname"`
|
||||
Roomid int64 `gorm:"column:roomid"`
|
||||
}
|
||||
|
||||
func (vup) TableName() string {
|
||||
return "vup"
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Key string `gorm:"column:key;primary_key"`
|
||||
Value string `gorm:"column:value"`
|
||||
}
|
||||
|
||||
func (config) TableName() string {
|
||||
return "config"
|
||||
}
|
||||
|
||||
// initialize 初始化vtb数据库
|
||||
func initialize(dbpath string) *vupdb {
|
||||
if _, err := os.Stat(dbpath); err != nil || os.IsNotExist(err) {
|
||||
// 生成文件
|
||||
f, err := os.Create(dbpath)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
}
|
||||
gdb, err := gorm.Open("sqlite3", dbpath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gdb.Debug().AutoMigrate(&vup{}).AutoMigrate(&config{})
|
||||
return (*vupdb)(gdb)
|
||||
}
|
||||
|
||||
func (vdb *vupdb) insertVupByMid(mid int64, uname string, roomid int64) (err error) {
|
||||
db := (*gorm.DB)(vdb)
|
||||
v := vup{
|
||||
Mid: mid,
|
||||
Uname: uname,
|
||||
Roomid: roomid,
|
||||
}
|
||||
if err = db.Debug().Model(&vup{}).First(&v, "mid = ? ", mid).Error; err != nil {
|
||||
if gorm.IsRecordNotFoundError(err) {
|
||||
err = db.Debug().Model(&vup{}).Create(&v).Error
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// filterVup 筛选vup
|
||||
func (vdb *vupdb) filterVup(ids []int64) (vups []vup, err error) {
|
||||
db := (*gorm.DB)(vdb)
|
||||
if err = db.Debug().Model(&vup{}).Find(&vups, "mid in (?)", ids).Error; err != nil {
|
||||
return vups, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func updateVup() {
|
||||
for _, v := range vtbURLs {
|
||||
data, err := web.GetData(v)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]:", err)
|
||||
}
|
||||
gjson.Get(binary.BytesToString(data), "@this").ForEach(func(key, value gjson.Result) bool {
|
||||
mid := value.Get("mid").Int()
|
||||
uname := value.Get("uname").String()
|
||||
roomid := value.Get("roomid").Int()
|
||||
err = vdb.insertVupByMid(mid, uname, roomid)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibili]:", err)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (vdb *vupdb) setBilibiliCookie(cookie string) (err error) {
|
||||
db := (*gorm.DB)(vdb)
|
||||
c := config{
|
||||
Key: bilibiliCookie,
|
||||
Value: cookie,
|
||||
}
|
||||
if err = db.Debug().Model(&config{}).First(&c, "key = ? ", bilibiliCookie).Error; err != nil {
|
||||
// error handling...
|
||||
if gorm.IsRecordNotFoundError(err) {
|
||||
err = db.Debug().Model(&config{}).Create(&c).Error
|
||||
}
|
||||
} else {
|
||||
err = db.Debug().Model(&config{}).Where("key = ? ", bilibiliCookie).Update(
|
||||
map[string]interface{}{
|
||||
"value": cookie,
|
||||
}).Error
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (vdb *vupdb) getBilibiliCookie() (c config) {
|
||||
db := (*gorm.DB)(vdb)
|
||||
db.Debug().Model(&config{}).First(&c, "key = ?", bilibiliCookie)
|
||||
return
|
||||
}
|
||||
@ -5,8 +5,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@ -300,20 +298,7 @@ func getLiveList(uids ...int64) string {
|
||||
m := make(map[string]interface{})
|
||||
m["uids"] = uids
|
||||
b, _ := json.Marshal(m)
|
||||
client := &http.Client{}
|
||||
// 提交请求
|
||||
request, err := http.NewRequest("POST", liveListURL, bytes.NewBuffer(b))
|
||||
if err != nil {
|
||||
log.Errorln("[bilibilipush]:", err)
|
||||
}
|
||||
request.Header.Add("Referer", referer)
|
||||
request.Header.Add("User-Agent", ua)
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Errorln("[bilibilipush]:", err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
data, err := io.ReadAll(response.Body)
|
||||
data, err := web.PostData(liveListURL, "application/json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
log.Errorln("[bilibilipush]:", err)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user