更换api版bilibiliparse (#255)

* Update bilibili_parse.go

* make lint happy

* 改进提出的问题
This commit is contained in:
Jiang-Red 2022-06-10 12:54:53 +08:00 committed by GitHub
parent 9ac276767d
commit 706d54db76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -2,76 +2,190 @@
package bilibiliparse package bilibiliparse
import ( import (
"encoding/json"
"errors" "errors"
"net/http"
"regexp" "regexp"
"strings" "strconv"
"time"
ctrl "github.com/FloatTech/zbpctrl" ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control" "github.com/FloatTech/zbputils/control"
"github.com/antchfx/htmlquery" "github.com/FloatTech/zbputils/ctxext"
"github.com/FloatTech/zbputils/web"
zero "github.com/wdvxdr1123/ZeroBot" zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message" "github.com/wdvxdr1123/ZeroBot/message"
) )
type result struct {
Data struct {
Bvid string `json:"bvid"`
Aid int `json:"aid"`
Copyright int `json:"copyright"`
Pic string `json:"pic"`
Title string `json:"title"`
Pubdate int `json:"pubdate"`
Ctime int `json:"ctime"`
Rights struct {
IsCooperation int `json:"is_cooperation"`
} `json:"rights"`
Owner struct {
Mid int `json:"mid"`
Name string `json:"name"`
} `json:"owner"`
Stat struct {
Aid int `json:"aid"`
View int `json:"view"`
Danmaku int `json:"danmaku"`
Reply int `json:"reply"`
Favorite int `json:"favorite"`
Coin int `json:"coin"`
Share int `json:"share"`
Like int `json:"like"`
} `json:"stat"`
Staff []struct {
Title string `json:"title"`
Name string `json:"name"`
Follower int `json:"follower"`
} `json:"staff"`
} `json:"data"`
}
type owner struct {
Data struct {
Card struct {
Fans int `json:"fans"`
} `json:"data"`
}
}
const ( const (
validRe = "https://www.bilibili.com/video/(BV[0-9a-zA-Z]+)" videoapi = "https://api.bilibili.com/x/web-interface/view?"
cardapi = "http://api.bilibili.com/x/web-interface/card?"
origin = "https://www.bilibili.com/video/"
) )
var re = regexp.MustCompile(validRe) var (
reg = regexp.MustCompile(`https://www.bilibili.com/video/([0-9a-zA-Z]+)`)
limit = ctxext.NewLimiterManager(time.Second*10, 1)
)
// 插件主体
func init() { func init() {
engine := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{ en := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false, DisableOnDefault: false,
Help: "b站视频链接解析\n" + Help: "b站视频链接解析\n" +
"- https://www.bilibili.com/video/BV1xx411c7BF | https://www.bilibili.com/video/av1605 | https://b23.tv/I8uzWCA | https://www.bilibili.com/video/bv1xx411c7BF", "- https://www.bilibili.com/video/BV1xx411c7BF | https://www.bilibili.com/video/av1605 | https://b23.tv/I8uzWCA | https://www.bilibili.com/video/bv1xx411c7BF",
}) })
en.OnRegex(`(av[0-9]+|BV[0-9a-zA-Z]{10}){1}`).SetBlock(true).Limit(limit.LimitByGroup).
engine.OnRegex("(av[0-9]+|BV[0-9a-zA-Z]+|https://b23.tv/[0-9a-zA-Z]+|bv[0-9a-zA-Z]+){1}").SetBlock(true).Handle(func(ctx *zero.Ctx) { Handle(func(ctx *zero.Ctx) {
bilibiliURL := ctx.State["regex_matched"].([]string)[1] id := ctx.State["regex_matched"].([]string)[1]
if bilibiliURL[0] != 'h' { m, err := parse(id)
bilibiliURL = "https://www.bilibili.com/video/" + bilibiliURL
}
m, err := parseURL(bilibiliURL)
if err != nil { if err != nil {
ctx.SendChain(message.Text("ERROR:", err)) ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.Send(m)
})
en.OnRegex(`https://www.bilibili.com/video/([0-9a-zA-Z]+)`).SetBlock(true).Limit(limit.LimitByGroup).
Handle(func(ctx *zero.Ctx) {
id := ctx.State["regex_matched"].([]string)[1]
m, err := parse(id)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.Send(m)
})
en.OnRegex(`(https://b23.tv/[0-9a-zA-Z]+)`).SetBlock(true).Limit(limit.LimitByGroup).
Handle(func(ctx *zero.Ctx) {
url := ctx.State["regex_matched"].([]string)[1]
realurl, err := getrealurl(url)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
id, err := cuturl(realurl)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
m, err := parse(id)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return return
} }
ctx.Send(m) ctx.Send(m)
}) })
} }
func parseURL(bilibiliURL string) (m message.Message, err error) { // parse 解析视频数据
doc, err := htmlquery.LoadURL(bilibiliURL) func parse(id string) (m message.Message, err error) {
var vid string
switch id[:2] {
case "av":
vid = "aid=" + id[2:]
case "BV":
vid = "bvid=" + id
}
data, err := web.GetData(videoapi + vid)
if err != nil { if err != nil {
return return
} }
videoURL := htmlquery.FindOne(doc, "/html/head/meta[@itemprop='url']").Attr[2].Val var r result
if !re.MatchString(videoURL) { err = json.Unmarshal(data, &r)
err = errors.New("parse html error: invalid video url") if err != nil {
return return
} }
m = make(message.Message, 0, 9) m = make(message.Message, 0, 16)
title := htmlquery.FindOne(doc, "//*[@id='viewbox_report']/h1/span/text()").Data m = append(m, message.Text("标题:", r.Data.Title, "\n"))
m = append(m, message.Text(title, "\n")) if r.Data.Rights.IsCooperation == 1 {
upName := strings.TrimSpace(htmlquery.FindOne(doc, "//*[@id='v_upinfo']/div[2]/div[1]/a[1]/text()").Data) for i := 0; i < len(r.Data.Staff); i++ {
fanNumber := htmlquery.InnerText(htmlquery.FindOne(doc, "//i[@class='van-icon-general_addto_s']").NextSibling.NextSibling) if i != len(r.Data.Staff) {
m = append(m, message.Text("UP: ", upName, ", 粉丝: ", fanNumber, "\n")) m = append(m, message.Text(r.Data.Staff[i].Title, "", r.Data.Staff[i].Name, ",粉丝:", r.Data.Staff[i].Follower, "\n"))
view := htmlquery.FindOne(doc, "//*[@id='viewbox_report']/div/span[@class='view']/text()").Data } else {
dm := htmlquery.FindOne(doc, "//*[@id='viewbox_report']/div/span[@class='dm']/text()").Data m = append(m, message.Text(r.Data.Staff[i].Title, "", r.Data.Staff[i].Name, ",粉丝:", r.Data.Staff[i].Follower))
m = append(m, message.Text(view, dm, "\n")) }
t := htmlquery.FindOne(doc, "//*[@id='viewbox_report']/div/span[3]/text()").Data }
m = append(m, message.Text(t)) } else {
image := htmlquery.FindOne(doc, "/html/head/meta[@itemprop='image']").Attr[2].Val o, err := getcard(r.Data.Owner.Mid)
m = append(m, message.Image(image)) if err != nil {
like := htmlquery.FindOne(doc, "//*[@id='arc_toolbar_report']/div[1]/span[@class='like']/text()").Data return m, err
coin := htmlquery.FindOne(doc, "//*[@id='arc_toolbar_report']/div[1]/span[@class='coin']/text()").Data }
m = append(m, message.Text("\n点赞: ", strings.TrimSpace(like), ", 投币: ", strings.TrimSpace(coin), "\n")) m = append(m, message.Text("\nUP主", r.Data.Owner.Name, ",粉丝:", o.Data.Card.Fans, "\n"))
collect := htmlquery.FindOne(doc, "//*[@id='arc_toolbar_report']/div[1]/span[@class='collect']/text()").Data }
share := htmlquery.FindOne(doc, "//*[@id='arc_toolbar_report']/div[1]/span[@class='share']/text()").Data m = append(m, message.Text("播放:", r.Data.Stat.View, ",弹幕:", r.Data.Stat.Danmaku, "\n"),
m = append(m, message.Text("收藏: ", strings.TrimSpace(collect), ", 分享: ", strings.TrimSpace(share), "\n")) message.Image(r.Data.Pic),
play := htmlquery.FindOne(doc, "//*[@id='viewbox_report']/div/span[1]/text()").Data message.Text("\n点赞", r.Data.Stat.Like, ",投币:", r.Data.Stat.Coin, "\n收藏", r.Data.Stat.Favorite, ",分享:", r.Data.Stat.Share, "\n", origin, id))
danmaku := htmlquery.FindOne(doc, "//*[@id='viewbox_report']/div/span[2]/text()").Data return
m = append(m, message.Text(strings.TrimSpace(play), "播放, ", strings.TrimSpace(danmaku), "弹幕\n")) }
m = append(m, message.Text(videoURL))
// getrealurl 获取跳转后的链接
func getrealurl(url string) (realurl string, err error) {
data, err := http.Head(url)
if err != nil {
return
}
realurl = data.Request.URL.String()
return
}
// cuturl 获取aid或者bvid
func cuturl(url string) (id string, err error) {
if !reg.MatchString(url) {
err = errors.New("invalid video url")
return
}
id = reg.FindStringSubmatch(url)[1]
return
}
// getcard 获取个人信息
func getcard(mid int) (o owner, err error) {
data, err := web.GetData(cardapi + "mid=" + strconv.Itoa(mid))
if err != nil {
return
}
err = json.Unmarshal(data, &o)
return return
} }