mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 22:00:11 +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] 个人猜单词
|
||||||
- [x] 团队猜单词
|
- [x] 团队猜单词
|
||||||
- **bilibili** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"`
|
- **bilibili** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"`
|
||||||
- [x] >vup info [名字 | uid]
|
- [x] >vup info [xxx]
|
||||||
- [x] >user info [名字 | uid]
|
- [x] >user info [xxx]
|
||||||
|
- [x] 查成分 [xxx]
|
||||||
|
- [x] 设置b站cookie SESSDATA=82da790d,1663822823,06ecf*31
|
||||||
|
- [x] 更新vup
|
||||||
- **嘉然** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana"`
|
- **嘉然** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/diana"`
|
||||||
- [x] 小作文
|
- [x] 小作文
|
||||||
- [x] 发大病
|
- [x] 发大病
|
||||||
@ -371,12 +374,12 @@ print("run[CQ:image,file="+j["img"]+"]")
|
|||||||
- api早上8点更新,推荐定时在8点30后。配合插件`job`中的记录在"cron"触发的指令使用
|
- api早上8点更新,推荐定时在8点30后。配合插件`job`中的记录在"cron"触发的指令使用
|
||||||
- [x] /启用 zaobao
|
- [x] /启用 zaobao
|
||||||
- [x] /禁用 zaobao
|
- [x] /禁用 zaobao
|
||||||
- **舔狗日记** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou"`
|
|
||||||
- [x] 舔狗日记
|
|
||||||
```
|
```
|
||||||
记录在"00 9 * * *"触发的指令
|
记录在"00 9 * * *"触发的指令
|
||||||
今日早报
|
今日早报
|
||||||
```
|
```
|
||||||
|
- **舔狗日记** `import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/tiangou"`
|
||||||
|
- [x] 舔狗日记
|
||||||
- **TODO...**
|
- **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
|
package bilibili
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"encoding/binary"
|
||||||
"net/http"
|
"fmt"
|
||||||
|
"image/color"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
control "github.com/FloatTech/zbputils/control"
|
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"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
|
|
||||||
"github.com/FloatTech/zbputils/control/order"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var engine = control.Register("bilibili", order.AcquirePrio(), &control.Options{
|
var engine = control.Register("bilibili", order.AcquirePrio(), &control.Options{
|
||||||
DisableOnDefault: false,
|
DisableOnDefault: false,
|
||||||
Help: "bilibili\n" +
|
Help: "bilibili\n" +
|
||||||
"- >vup info [名字 | uid]\n" +
|
"- >vup info [xxx]\n" +
|
||||||
"- >user info [名字 | uid]",
|
"- >user info [xxx]\n" +
|
||||||
|
"- 查成分 [xxx]\n" +
|
||||||
|
"- 设置b站cookie SESSDATA=82da790d,1663822823,06ecf*31\n" +
|
||||||
|
"- 更新vup",
|
||||||
|
PublicDataFolder: "Bilibili",
|
||||||
})
|
})
|
||||||
|
|
||||||
// 查成分的
|
// 查成分的
|
||||||
func init() {
|
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) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
keyword := ctx.State["regex_matched"].([]string)[1]
|
keyword := ctx.State["regex_matched"].([]string)[1]
|
||||||
rest, err := uid(keyword)
|
uidRes, err := search(keyword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR:", err))
|
ctx.SendChain(message.Text("ERROR:", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
id := rest.Get("data.result.0.mid").String()
|
id := strconv.FormatInt(uidRes[0].Mid, 10)
|
||||||
url := "https://api.bilibili.com/x/relation/same/followings?vmid=" + id
|
follwings, err := followings(id)
|
||||||
method := "GET"
|
|
||||||
client := &http.Client{}
|
|
||||||
req, err := http.NewRequest(method, url, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.SendChain(message.Text("ERROR:", err))
|
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(
|
ctx.SendChain(message.Text(
|
||||||
"uid: ", rest.Get("data.result.0.mid").Int(), "\n",
|
"search: ", uidRes[0].Mid, "\n",
|
||||||
"name: ", rest.Get("data.result.0.uname").Str, "\n",
|
"name: ", uidRes[0].Uname, "\n",
|
||||||
"sex: ", []string{"", "", "女", "男"}[rest.Get("data.result.0.gender").Int()], "\n",
|
"sex: ", []string{"", "男", "女", "未知"}[uidRes[0].Gender], "\n",
|
||||||
"sign: ", rest.Get("data.result.0.usign").Str, "\n",
|
"sign: ", uidRes[0].Usign, "\n",
|
||||||
"level: ", rest.Get("data.result.0.level").Int(), "\n",
|
"level: ", uidRes[0].Level, "\n",
|
||||||
"follow: ", gjson.Get(data, "data.list.#.uname"),
|
"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"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -300,20 +298,7 @@ func getLiveList(uids ...int64) string {
|
|||||||
m := make(map[string]interface{})
|
m := make(map[string]interface{})
|
||||||
m["uids"] = uids
|
m["uids"] = uids
|
||||||
b, _ := json.Marshal(m)
|
b, _ := json.Marshal(m)
|
||||||
client := &http.Client{}
|
data, err := web.PostData(liveListURL, "application/json", bytes.NewReader(b))
|
||||||
// 提交请求
|
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorln("[bilibilipush]:", err)
|
log.Errorln("[bilibilipush]:", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user