diff --git a/README.md b/README.md index 7d68816f5b..d0e9a7a053 100644 --- a/README.md +++ b/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...** ## 使用方法 diff --git a/plugin/bilibili/api.go b/plugin/bilibili/api.go new file mode 100644 index 0000000000..3a72bb1165 --- /dev/null +++ b/plugin/bilibili/api.go @@ -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 +} diff --git a/plugin/bilibili/info.go b/plugin/bilibili/info.go index 31d02eb920..32ab7ddb08 100644 --- a/plugin/bilibili/info.go +++ b/plugin/bilibili/info.go @@ -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) + ctx.SendChain(message.Text( + "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 } - defer res.Body.Close() - - body, err := io.ReadAll(res.Body) + id := strconv.FormatInt(res[0].Mid, 10) + // 获取详情 + fo, err := fansapi(id) 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: ", 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 } diff --git a/plugin/bilibili/live_info.go b/plugin/bilibili/live_info.go deleted file mode 100644 index 6336a6f068..0000000000 --- a/plugin/bilibili/live_info.go +++ /dev/null @@ -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 -} diff --git a/plugin/bilibili/model.go b/plugin/bilibili/model.go new file mode 100644 index 0000000000..f49a32827c --- /dev/null +++ b/plugin/bilibili/model.go @@ -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 +} diff --git a/plugin/bilibili_push/bilibili_push.go b/plugin/bilibili_push/bilibili_push.go index 18b5c7fb76..c700b45e90 100644 --- a/plugin/bilibili_push/bilibili_push.go +++ b/plugin/bilibili_push/bilibili_push.go @@ -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) }