🎨 修改bilibili,bilibiliparse插件结构,添加bilibili动态直播专栏解析 (#319)

* 🎨 修改bilibili,bilibiliparse插件结构,添加bilibili动态直播专栏解析

* 💩 修改大小写

* 🎨 正则全局,错误处理

* 🎨 使用json.NewDecoder()

* 💚 空使用

* 💚 修lint
This commit is contained in:
himawari 2022-07-21 12:54:52 +08:00 committed by GitHub
parent 31555cbf2f
commit 1c9a7eb158
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 916 additions and 405 deletions

View File

@ -387,11 +387,11 @@ print("run[CQ:image,file="+j["img"]+"]")
</details>
<details>
<summary>b站视频链接解析</summary>
<summary>b站动态、专栏、视频、直播解析</summary>
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili_parse"`
`import _ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili"`
- [x] https://www.bilibili.com/video/BV1xx411c7BF | https://www.bilibili.com/video/av1605 | https://b23.tv/I8uzWCA | https://www.bilibili.com/video/bv1xx411c7BF
- [x] t.bilibili.com/642277677329285174 | bilibili.com/read/cv17134450 | bilibili.com/video/BV13B4y1x7pS | live.bilibili.com/22603245
</details>
<details>

View File

@ -59,8 +59,7 @@ import (
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/aiwife" // 随机老婆
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/b14" // base16384加解密
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/baidu" // 百度一下
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // 查询b站用户信息
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili_parse" // b站视频链接解析
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/bilibili" // b站相关
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/book_review" // 哀伤雪刃吧推书记录
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/cangtoushi" // 藏头诗
_ "github.com/FloatTech/ZeroBot-Plugin/plugin/choose" // 选择困难症帮手

View File

@ -3,8 +3,9 @@ package bilibili
import (
"encoding/json"
"errors"
"io"
"fmt"
"net/http"
"strconv"
"github.com/FloatTech/zbputils/binary"
"github.com/FloatTech/zbputils/web"
@ -15,18 +16,9 @@ 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)
// searchUser 查找b站用户
func searchUser(keyword string) (r []searchResult, err error) {
data, err := web.GetData(fmt.Sprintf(searchUserURL, keyword))
if err != nil {
return
}
@ -42,21 +34,9 @@ func search(keyword string) (r []searchResult, err error) {
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)
// getVtbDetail 查找vtb信息
func getVtbDetail(uid string) (result vtbDetail, err error) {
data, err := web.GetData(fmt.Sprintf(vtbDetailURL, uid))
if err != nil {
return
}
@ -66,76 +46,9 @@ func fansapi(uid string) (result follower, err error) {
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
}
j := gjson.ParseBytes(body)
s = j.Get("data.list.#.uname").Raw
if j.Get("code").Int() == -101 {
err = errNeedCookie
return
}
if j.Get("code").Int() != 0 {
err = errors.New(j.Get("message").String())
return
}
return
}
type userinfo struct {
Name string `json:"name"`
Mid string `json:"mid"`
Face string `json:"face"`
Fans int64 `json:"fans"`
Regtime int64 `json:"regtime"`
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)
// getMemberCard 获取b站个人详情
func getMemberCard(uid interface{}) (result memberCard, err error) {
data, err := web.GetData(fmt.Sprintf(memberCardURL, uid))
if err != nil {
return
}
@ -146,12 +59,10 @@ func card(uid string) (result userinfo, err error) {
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"
// getMedalwall 用b站uid获得牌子
func getMedalwall(uid string) (result []medal, err error) {
client := &http.Client{}
req, err := http.NewRequest(method, medalwallURL, nil)
req, err := http.NewRequest("GET", fmt.Sprintf(medalwallURL, uid), nil)
if err != nil {
return
}
@ -162,18 +73,56 @@ func medalwall(uid string) (result []medal, err error) {
return
}
defer res.Body.Close()
data, err := io.ReadAll(res.Body)
var md medalData
err = json.NewDecoder(res.Body).Decode(&md)
if err != nil {
return
}
j := gjson.ParseBytes(data)
if j.Get("code").Int() == -101 {
if md.Code == -101 {
err = errNeedCookie
return
}
if j.Get("code").Int() != 0 {
err = errors.New(j.Get("message").String())
if md.Code != 0 {
err = errors.New(md.Message)
}
_ = json.Unmarshal(binary.StringToBytes(j.Get("data.list").Raw), &result)
result = md.Data.List
return
}
// getArticleInfo 用id查专栏信息
func getArticleInfo(id string) (card Card, err error) {
var data []byte
data, err = web.GetData(fmt.Sprintf(articleInfoURL, id))
if err != nil {
return
}
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("data").Raw), &card)
return
}
// getLiveRoomInfo 用直播间id查直播间信息
func getLiveRoomInfo(roomID string) (card roomCard, err error) {
var data []byte
data, err = web.GetData(fmt.Sprintf(liveRoomInfoURL, roomID))
if err != nil {
return
}
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("data").Raw), &card)
return
}
// getVideoInfo 用av或bv查视频信息
func getVideoInfo(id string) (card Card, err error) {
var data []byte
_, err = strconv.Atoi(id)
if err == nil {
data, err = web.GetData(fmt.Sprintf(videoInfoURL, id, ""))
} else {
data, err = web.GetData(fmt.Sprintf(videoInfoURL, "", id))
}
if err != nil {
return
}
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("data").Raw), &card)
return
}

View File

@ -27,7 +27,11 @@ import (
"github.com/wdvxdr1123/ZeroBot/message"
)
var engine = control.Register("bilibili", &ctrl.Options[*zero.Ctx]{
var re = regexp.MustCompile(`^\d+$`)
// 查成分的
func init() {
engine := control.Register("bilibili", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Help: "bilibili\n" +
"- >vup info [xxx]\n" +
@ -36,11 +40,7 @@ var engine = control.Register("bilibili", &ctrl.Options[*zero.Ctx]{
"- 设置b站cookie SESSDATA=82da790d,1663822823,06ecf*31\n" +
"- 更新vup",
PublicDataFolder: "Bilibili",
})
var re = regexp.MustCompile(`^\d+$`)
// 查成分的
func init() {
})
cachePath := engine.DataFolder() + "cache/"
_ = os.RemoveAll(cachePath)
_ = os.MkdirAll(cachePath, 0755)
@ -55,46 +55,35 @@ func init() {
return true
})
engine.OnRegex(`^>user info\s?(.{1,25})$`, getdb).SetBlock(true).
engine.OnRegex(`^>user info\s?(.{1,25})$`, getPara).SetBlock(true).
Handle(func(ctx *zero.Ctx) {
keyword := ctx.State["regex_matched"].([]string)[1]
uidRes, err := search(keyword)
id := ctx.State["uid"].(string)
card, err := getMemberCard(id)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
id := strconv.FormatInt(uidRes[0].Mid, 10)
follwings, err := followings(id)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
}
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,
"uid: ", card.Mid, "\n",
"name: ", card.Name, "\n",
"sex: ", card.Sex, "\n",
"sign: ", card.Sign, "\n",
"level: ", card.LevelInfo.CurrentLevel, "\n",
"birthday: ", card.Birthday,
))
})
engine.OnRegex(`^>vup info\s?(.{1,25})$`).SetBlock(true).
engine.OnRegex(`^>vup info\s?(.{1,25})$`, getPara).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)
id := ctx.State["uid"].(string)
// 获取详情
fo, err := fansapi(id)
fo, err := getVtbDetail(id)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(message.Text(
"search: ", fo.Mid, "\n",
"b站id: ", fo.Mid, "\n",
"名字: ", fo.Uname, "\n",
"当前粉丝数: ", fo.Follower, "\n",
"24h涨粉数: ", fo.Rise, "\n",
@ -116,7 +105,7 @@ func init() {
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + drawedFile))
return
}
u, err := card(id)
u, err := getMemberCard(id)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
@ -127,7 +116,7 @@ func init() {
return
}
vupLen := len(vups)
medals, err := medalwall(id)
medals, err := getMedalwall(id)
sort.Sort(medalSlice(medals))
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
@ -312,7 +301,7 @@ func int2rbg(t int64) (int64, int64, int64) {
func getPara(ctx *zero.Ctx) bool {
keyword := ctx.State["regex_matched"].([]string)[1]
if !re.MatchString(keyword) {
searchRes, err := search(keyword)
searchRes, err := searchUser(keyword)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return false
@ -345,7 +334,7 @@ func getPara(ctx *zero.Ctx) bool {
ctx.State["uid"] = keyword
return true
} else if num == 1 {
searchRes, err := search(keyword)
searchRes, err := searchUser(keyword)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return false

View File

@ -0,0 +1,105 @@
package bilibili
import (
"regexp"
"time"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
zero "github.com/wdvxdr1123/ZeroBot"
"github.com/wdvxdr1123/ZeroBot/message"
)
var (
limit = ctxext.NewLimiterManager(time.Second*10, 1)
searchVideo = `bilibili.com/video/(?:av(\d+)|([bB][vV][0-9a-zA-Z]+))`
searchDynamic = `(t.bilibili.com|m.bilibili.com/dynamic)/(\d+)`
searchArticle = `bilibili.com/read/(?:cv|mobile/)(\d+)`
searchLiveRoom = `live.bilibili.com/(\d+)`
searchVideoRe = regexp.MustCompile(searchVideo)
searchDynamicRe = regexp.MustCompile(searchDynamic)
searchArticleRe = regexp.MustCompile(searchArticle)
searchLiveRoomRe = regexp.MustCompile(searchLiveRoom)
)
// 插件主体
func init() {
en := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
Help: "b站动态、专栏、视频、直播解析\n" +
"- t.bilibili.com/642277677329285174 | bilibili.com/read/cv17134450 | bilibili.com/video/BV13B4y1x7pS | live.bilibili.com/22603245 ",
})
en.OnRegex(`((b23|acg).tv|bili2233.cn)/[0-9a-zA-Z]+`).SetBlock(true).Limit(limit.LimitByGroup).
Handle(func(ctx *zero.Ctx) {
url := ctx.State["regex_matched"].([]string)[0]
realurl, err := getrealurl("https://" + url)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
switch {
case searchVideoRe.MatchString(realurl):
ctx.State["regex_matched"] = searchVideoRe.FindStringSubmatch(realurl)
handleVideo(ctx)
case searchDynamicRe.MatchString(realurl):
ctx.State["regex_matched"] = searchDynamicRe.FindStringSubmatch(realurl)
handleDynamic(ctx)
case searchArticleRe.MatchString(realurl):
ctx.State["regex_matched"] = searchArticleRe.FindStringSubmatch(realurl)
handleArticle(ctx)
case searchLiveRoomRe.MatchString(realurl):
ctx.State["regex_matched"] = searchLiveRoomRe.FindStringSubmatch(realurl)
handleLive(ctx)
}
})
en.OnRegex(searchVideo).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleVideo)
en.OnRegex(searchDynamic).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleDynamic)
en.OnRegex(searchArticle).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleArticle)
en.OnRegex(searchLiveRoom).SetBlock(true).Limit(limit.LimitByGroup).Handle(handleLive)
}
func handleVideo(ctx *zero.Ctx) {
id := ctx.State["regex_matched"].([]string)[1]
if id == "" {
id = ctx.State["regex_matched"].([]string)[2]
}
card, err := getVideoInfo(id)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
msg, err := videoCard2msg(card)
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(msg...)
}
func handleDynamic(ctx *zero.Ctx) {
msg, err := dynamicDetail(ctx.State["regex_matched"].([]string)[2])
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(msg...)
}
func handleArticle(ctx *zero.Ctx) {
card, err := getArticleInfo(ctx.State["regex_matched"].([]string)[1])
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(articleCard2msg(card, ctx.State["regex_matched"].([]string)[1])...)
}
func handleLive(ctx *zero.Ctx) {
card, err := getLiveRoomInfo(ctx.State["regex_matched"].([]string)[1])
if err != nil {
ctx.SendChain(message.Text("ERROR:", err))
return
}
ctx.SendChain(liveCard2msg(card)...)
}

233
plugin/bilibili/card2msg.go Normal file
View File

@ -0,0 +1,233 @@
package bilibili
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/FloatTech/zbputils/binary"
"github.com/FloatTech/zbputils/web"
"github.com/tidwall/gjson"
"github.com/wdvxdr1123/ZeroBot/message"
)
var (
typeMsg = map[int]string{
1: "转发了动态",
2: "有图营业",
4: "无图营业",
8: "投稿了视频",
16: "投稿了短视频",
64: "投稿了文章",
256: "投稿了音频",
2048: "发布了简报",
4200: "发布了直播",
4308: "发布了直播",
}
)
// dynamicCard2msg cType=0时,处理DynCard字符串,cType=1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308时,处理Card字符串,cType为card类型
func dynamicCard2msg(str string, cType int) (msg []message.MessageSegment, err error) {
var (
dynamicCard dynamicCard
card Card
vote Vote
)
msg = make([]message.MessageSegment, 0, 16)
// 初始化结构体
switch cType {
case 0:
err = json.Unmarshal(binary.StringToBytes(str), &dynamicCard)
if err != nil {
return
}
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Card), &card)
if err != nil {
return
}
if dynamicCard.Extension.Vote != "" {
err = json.Unmarshal(binary.StringToBytes(dynamicCard.Extension.Vote), &vote)
if err != nil {
return
}
}
cType = dynamicCard.Desc.Type
case 1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308:
err = json.Unmarshal(binary.StringToBytes(str), &card)
if err != nil {
return
}
default:
err = errors.New("只有0, 1, 2, 4, 8, 16, 64, 256, 2048, 4200, 4308模式")
return
}
// 生成消息
switch cType {
case 1:
msg = append(msg, message.Text(card.User.Uname, typeMsg[cType], "\n",
card.Item.Content, "\n",
"转发的内容: \n"))
var originMsg []message.MessageSegment
originMsg, err = dynamicCard2msg(card.Origin, card.Item.OrigType)
if err != nil {
return
}
msg = append(msg, originMsg...)
case 2:
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
card.Item.Description))
for i := 0; i < len(card.Item.Pictures); i++ {
msg = append(msg, message.Image(card.Item.Pictures[i].ImgSrc))
}
case 4:
msg = append(msg, message.Text(card.User.Uname, "在", time.Unix(int64(card.Item.Timestamp), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
card.Item.Content, "\n"))
if dynamicCard.Extension.Vote != "" {
msg = append(msg, message.Text("【投票】", vote.Desc, "\n",
"截止日期: ", time.Unix(int64(vote.Endtime), 0).Format("2006-01-02 15:04:05"), "\n",
"参与人数: ", humanNum(vote.JoinNum), "\n",
"投票选项( 最多选择", vote.ChoiceCnt, "项 )\n"))
for i := 0; i < len(vote.Options); i++ {
msg = append(msg, message.Text("- ", vote.Options[i].Idx, ". ", vote.Options[i].Desc, "\n"))
if vote.Options[i].ImgURL != "" {
msg = append(msg, message.Image(vote.Options[i].ImgURL))
}
}
}
case 8:
msg = append(msg, message.Text(card.Owner.Name, "在", time.Unix(int64(card.Pubdate), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
card.Title))
msg = append(msg, message.Image(card.Pic))
msg = append(msg, message.Text(card.Desc, "\n",
card.ShareSubtitle, "\n",
"视频链接: ", card.ShortLink, "\n"))
case 16:
msg = append(msg, message.Text(card.User.Name, "在", time.Unix(int64(card.Item.UploadTime), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
card.Item.Description))
msg = append(msg, message.Image(card.Item.Cover.Default))
case 64:
msg = append(msg, message.Text(card.Author.(map[string]interface{})["name"], "在", time.Unix(int64(card.PublishTime), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
card.Title, "\n",
card.Summary))
for i := 0; i < len(card.ImageUrls); i++ {
msg = append(msg, message.Image(card.ImageUrls[i]))
}
if card.ID != 0 {
msg = append(msg, message.Text("文章链接: https://www.bilibili.com/read/cv", card.ID, "\n"))
}
case 256:
msg = append(msg, message.Text(card.Upper, "在", time.Unix(int64(card.Ctime), 0).Format("2006-01-02 15:04:05"), typeMsg[cType], "\n",
card.Title))
msg = append(msg, message.Image(card.Cover))
msg = append(msg, message.Text(card.Intro, "\n"))
if card.ID != 0 {
msg = append(msg, message.Text("音频链接: https://www.bilibili.com/audio/au", card.ID, "\n"))
}
case 2048:
msg = append(msg, message.Text(card.User.Uname, typeMsg[cType], "\n",
card.Vest.Content, "\n",
card.Sketch.Title, "\n",
card.Sketch.DescText, "\n"))
msg = append(msg, message.Image(card.Sketch.CoverURL))
msg = append(msg, message.Text("分享链接: ", card.Sketch.TargetURL, "\n"))
case 4308:
if dynamicCard.Desc.UserProfile.Info.Uname != "" {
msg = append(msg, message.Text(dynamicCard.Desc.UserProfile.Info.Uname, typeMsg[cType], "\n"))
}
msg = append(msg, message.Image(card.LivePlayInfo.Cover))
msg = append(msg, message.Text(card.LivePlayInfo.Title, "\n",
"房间号: ", card.LivePlayInfo.RoomID, "\n",
"分区: ", card.LivePlayInfo.ParentAreaName))
if card.LivePlayInfo.ParentAreaName != card.LivePlayInfo.AreaName {
msg = append(msg, message.Text("-", card.LivePlayInfo.AreaName))
}
if card.LivePlayInfo.LiveStatus == 0 {
msg = append(msg, message.Text("未开播 \n"))
} else {
msg = append(msg, message.Text("直播中 ", card.LivePlayInfo.WatchedShow, "\n"))
}
msg = append(msg, message.Text("直播链接: ", card.LivePlayInfo.Link))
default:
msg = append(msg, message.Text("动态id: ", dynamicCard.Desc.DynamicIDStr, "未知动态类型: ", cType, "\n"))
}
if dynamicCard.Desc.DynamicIDStr != "" {
msg = append(msg, message.Text("动态链接: ", tURL, dynamicCard.Desc.DynamicIDStr))
}
return
}
// dynamicDetail 用动态id查动态信息
func dynamicDetail(dynamicIDStr string) (msg []message.MessageSegment, err error) {
var data []byte
data, err = web.GetData(fmt.Sprintf(dynamicDetailURL, dynamicIDStr))
if err != nil {
return
}
return dynamicCard2msg(gjson.ParseBytes(data).Get("data.card").Raw, 0)
}
// articleCard2msg 专栏转消息
func articleCard2msg(card Card, defaultID string) (msg []message.MessageSegment) {
msg = make([]message.MessageSegment, 0, 16)
for i := 0; i < len(card.OriginImageUrls); i++ {
msg = append(msg, message.Image(card.OriginImageUrls[i]))
}
msg = append(msg, message.Text(card.Title, "\n", "UP主: ", card.AuthorName, "\n",
"阅读: ", humanNum(card.Stats.View), " 评论: ", humanNum(card.Stats.Reply), "\n",
cvURL, defaultID))
return
}
// liveCard2msg 直播卡片转消息
func liveCard2msg(card roomCard) (msg []message.MessageSegment) {
msg = make([]message.MessageSegment, 0, 16)
msg = append(msg, message.Image(card.RoomInfo.Keyframe))
msg = append(msg, message.Text(card.RoomInfo.Title, "\n",
"主播: ", card.AnchorInfo.BaseInfo.Uname, "\n",
"房间号: ", card.RoomInfo.RoomID, "\n"))
if card.RoomInfo.ShortID != 0 {
msg = append(msg, message.Text("短号: ", card.RoomInfo.ShortID, "\n"))
}
msg = append(msg, message.Text("分区: ", card.RoomInfo.ParentAreaName))
if card.RoomInfo.ParentAreaName != card.RoomInfo.AreaName {
msg = append(msg, message.Text("-", card.RoomInfo.AreaName))
}
if card.RoomInfo.LiveStatus == 0 {
msg = append(msg, message.Text("未开播 \n"))
} else {
msg = append(msg, message.Text("直播中 ", humanNum(card.RoomInfo.Online), "人气\n"))
}
if card.RoomInfo.ShortID != 0 {
msg = append(msg, message.Text("直播间链接: ", lURL, card.RoomInfo.ShortID))
} else {
msg = append(msg, message.Text("直播间链接: ", lURL, card.RoomInfo.RoomID))
}
return
}
// videoCard2msg 视频卡片转消息
func videoCard2msg(card Card) (msg []message.MessageSegment, err error) {
var mCard memberCard
msg = make([]message.MessageSegment, 0, 16)
mCard, err = getMemberCard(card.Owner.Mid)
if err != nil {
return
}
msg = append(msg, message.Text("标题: ", card.Title, "\n"))
if card.Rights.IsCooperation == 1 {
for i := 0; i < len(card.Staff); i++ {
msg = append(msg, message.Text(card.Staff[i].Title, ": ", card.Staff[i].Name, " 粉丝: ", humanNum(card.Staff[i].Follower), "\n"))
}
} else {
msg = append(msg, message.Text("UP主: ", card.Owner.Name, " 粉丝: ", humanNum(mCard.Fans), "\n"))
}
msg = append(msg, message.Text("播放: ", humanNum(card.Stat.View), " 弹幕: ", humanNum(card.Stat.Danmaku)))
msg = append(msg, message.Image(card.Pic))
msg = append(msg, message.Text("点赞: ", humanNum(card.Stat.Like), " 投币: ", humanNum(card.Stat.Coin), "\n",
"收藏: ", humanNum(card.Stat.Favorite), " 分享: ", humanNum(card.Stat.Share), "\n",
vURL, card.BvID))
return
}

View File

@ -0,0 +1,82 @@
package bilibili
import (
"testing"
)
func TestArticleInfo(t *testing.T) {
card, err := getArticleInfo("17279244")
if err != nil {
t.Fatal(err)
}
t.Log(articleCard2msg(card, "17279244"))
}
func TestDynamicDetail(t *testing.T) {
t.Log("cType = 1")
t.Log(dynamicDetail("642279068898689029"))
t.Log("cType = 2")
t.Log(dynamicDetail("642470680290394121"))
t.Log("cType = 2048")
t.Log(dynamicDetail("642277677329285174"))
t.Log("cType = 4")
t.Log(dynamicDetail("642154347357011968"))
t.Log("cType = 8")
t.Log(dynamicDetail("675892999274627104"))
t.Log("cType = 4308")
t.Log(dynamicDetail("668598718656675844"))
t.Log("cType = 64")
t.Log(dynamicDetail("675966082178088963"))
t.Log("cType = 256")
t.Log(dynamicDetail("599253048535707632"))
t.Log("cType = 4,投票类型")
t.Log(dynamicDetail("677231070435868704"))
}
func TestMemberCard(t *testing.T) {
card, err := getMemberCard(2)
if err != nil {
t.Fatal(err)
}
t.Logf("%+v\n", card)
}
func TestVideoInfo(t *testing.T) {
card, err := getVideoInfo("10007")
if err != nil {
t.Fatal(err)
}
t.Log(videoCard2msg(card))
card, err = getVideoInfo("BV1xx411c7mD")
if err != nil {
t.Fatal(err)
}
t.Log(videoCard2msg(card))
card, err = getVideoInfo("bv1xx411c7mD")
if err != nil {
t.Fatal(err)
}
t.Log(videoCard2msg(card))
card, err = getVideoInfo("BV1mF411j7iU")
if err != nil {
t.Fatal(err)
}
t.Log(videoCard2msg(card))
}
func TestLiveRoomInfo(t *testing.T) {
card, err := getLiveRoomInfo("83171")
if err != nil {
t.Fatal(err)
}
t.Log(liveCard2msg(card))
}

267
plugin/bilibili/types.go Normal file
View File

@ -0,0 +1,267 @@
package bilibili
const (
// tURL bilibili动态前缀
tURL = "https://t.bilibili.com/"
// dynamicDetailURL 当前动态信息,一个card
dynamicDetailURL = "https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=%v"
// memberCardURL 个人信息
memberCardURL = "https://account.bilibili.com/api/member/getCardByMid?mid=%v"
// articleInfoURL 查看专栏信息
articleInfoURL = "https://api.bilibili.com/x/article/viewinfo?id=%v"
// cvURL b站专栏前缀
cvURL = "https://www.bilibili.com/read/cv"
// liveRoomInfoURL 查看直播间信息
liveRoomInfoURL = "https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=%v"
// lURL b站直播间前缀
lURL = "https://live.bilibili.com/"
// videoInfoURL 查看视频信息
videoInfoURL = "https://api.bilibili.com/x/web-interface/view?aid=%v&bvid=%v"
// vURL 视频网址前缀
vURL = "https://www.bilibili.com/video/"
// searchUserURL 查找b站用户
searchUserURL = "http://api.bilibili.com/x/web-interface/search/type?search_type=bili_user&keyword=%v"
// vtbDetailURL 查找vtb信息
vtbDetailURL = "https://api.vtbs.moe/v1/detail/%v"
// medalwallURL 查找牌子
medalwallURL = "https://api.live.bilibili.com/xlive/web-ucenter/user/MedalWall?target_id=%v"
)
// dynamicCard 总动态结构体,包括desc,card
type dynamicCard struct {
Desc Desc `json:"desc"`
Card string `json:"card"`
Extension struct {
VoteCfg struct {
VoteID int `json:"vote_id"`
Desc string `json:"desc"`
JoinNum int `json:"join_num"`
} `json:"vote_cfg"`
Vote string `json:"vote"`
} `json:"extension"`
}
// Card 卡片结构体
type Card struct {
Item struct {
Content string `json:"content"`
UploadTime int `json:"upload_time"`
Description string `json:"description"`
Pictures []struct {
ImgSrc string `json:"img_src"`
} `json:"pictures"`
Timestamp int `json:"timestamp"`
Cover struct {
Default string `json:"default"`
} `json:"cover"`
OrigType int `json:"orig_type"`
} `json:"item"`
AID interface{} `json:"aid"`
BvID interface{} `json:"bvid"`
Dynamic interface{} `json:"dynamic"`
Pic string `json:"pic"`
Title string `json:"title"`
ID int `json:"id"`
Summary string `json:"summary"`
ImageUrls []string `json:"image_urls"`
OriginImageUrls []string `json:"origin_image_urls"`
Sketch struct {
Title string `json:"title"`
DescText string `json:"desc_text"`
CoverURL string `json:"cover_url"`
TargetURL string `json:"target_url"`
} `json:"sketch"`
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"`
Stats 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:"stats"`
Owner struct {
Name string `json:"name"`
Pubdate int `json:"pubdate"`
Mid int `json:"mid"`
} `json:"owner"`
Cover string `json:"cover"`
ShortID interface{} `json:"short_id"`
LivePlayInfo struct {
ParentAreaName string `json:"parent_area_name"`
AreaName string `json:"area_name"`
Cover string `json:"cover"`
Link string `json:"link"`
Online int `json:"online"`
RoomID int `json:"room_id"`
LiveStatus int `json:"live_status"`
WatchedShow string `json:"watched_show"`
Title string `json:"title"`
} `json:"live_play_info"`
Intro string `json:"intro"`
Schema string `json:"schema"`
Author interface{} `json:"author"`
AuthorName string `json:"author_name"`
PlayCnt int `json:"play_cnt"`
ReplyCnt int `json:"reply_cnt"`
TypeInfo string `json:"type_info"`
User struct {
Name string `json:"name"`
Uname string `json:"uname"`
} `json:"user"`
Desc string `json:"desc"`
ShareSubtitle string `json:"share_subtitle"`
ShortLink string `json:"short_link"`
PublishTime int `json:"publish_time"`
BannerURL string `json:"banner_url"`
Ctime int `json:"ctime"`
Vest struct {
Content string `json:"content"`
} `json:"vest"`
Upper string `json:"upper"`
Origin string `json:"origin"`
Pubdate int `json:"pubdate"`
Rights struct {
IsCooperation int `json:"is_cooperation"`
} `json:"rights"`
Staff []struct {
Title string `json:"title"`
Name string `json:"name"`
Follower int `json:"follower"`
} `json:"staff"`
}
// Desc 描述结构体
type Desc struct {
Type int `json:"type"`
DynamicIDStr string `json:"dynamic_id_str"`
OrigType int `json:"orig_type"`
Timestamp int `json:"timestamp"`
Origin struct {
DynamicIDStr string `json:"dynamic_id_str"`
} `json:"origin"`
UserProfile struct {
Info struct {
Uname string `json:"uname"`
} `json:"info"`
} `json:"user_profile"`
}
// Vote 投票结构体
type Vote struct {
ChoiceCnt int `json:"choice_cnt"`
Desc string `json:"desc"`
Endtime int `json:"endtime"`
JoinNum int `json:"join_num"`
Options []struct {
Idx int `json:"idx"`
Desc string `json:"desc"`
ImgURL string `json:"img_url"`
} `json:"options"`
}
// memberCard 个人信息卡片
type memberCard struct {
Mid string `json:"mid"`
Name string `json:"name"`
Sex string `json:"sex"`
Face string `json:"face"`
Coins float64 `json:"coins"`
Regtime int64 `json:"regtime"`
Birthday string `json:"birthday"`
Sign string `json:"sign"`
Attentions []int64 `json:"attentions"`
Fans int `json:"fans"`
Friend int `json:"friend"`
Attention int `json:"attention"`
LevelInfo struct {
CurrentLevel int `json:"current_level"`
} `json:"level_info"`
}
// roomCard 直播间卡片
type roomCard struct {
RoomInfo struct {
RoomID int `json:"room_id"`
ShortID int `json:"short_id"`
Title string `json:"title"`
LiveStatus int `json:"live_status"`
AreaName string `json:"area_name"`
ParentAreaName string `json:"parent_area_name"`
Keyframe string `json:"keyframe"`
Online int `json:"online"`
} `json:"room_info"`
AnchorInfo struct {
BaseInfo struct {
Uname string `json:"uname"`
} `json:"base_info"`
} `json:"anchor_info"`
}
// searchResult 查找b站用户结果
type searchResult struct {
Mid int64 `json:"mid"`
Uname string `json:"uname"`
Gender int64 `json:"gender"`
Usign string `json:"usign"`
Level int64 `json:"level"`
}
// medalData 牌子接口返回结构体
type medalData struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
List []medal `json:"list"`
} `json:"data"`
}
// medalInfo b站牌子信息
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
}
// vtb信息
type vtbDetail 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"`
}

24
plugin/bilibili/util.go Normal file
View File

@ -0,0 +1,24 @@
package bilibili
import (
"net/http"
"strconv"
)
// humanNum 格式化人数
func humanNum(res int) string {
if res/10000 != 0 {
return strconv.FormatFloat(float64(res)/10000, 'f', 2, 64) + "万"
}
return strconv.Itoa(res)
}
// getrealurl 获取跳转后的链接
func getrealurl(url string) (realurl string, err error) {
data, err := http.Head(url)
if err != nil {
return
}
realurl = data.Request.URL.String()
return
}

View File

@ -1,190 +0,0 @@
// Package bilibiliparse b站视频链接解析
package bilibiliparse
import (
"encoding/json"
"net/http"
"regexp"
"strconv"
"strings"
"time"
ctrl "github.com/FloatTech/zbpctrl"
"github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/ctxext"
"github.com/FloatTech/zbputils/web"
zero "github.com/wdvxdr1123/ZeroBot"
"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:"card"`
} `json:"data"`
}
const (
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 (
reg = regexp.MustCompile(`https://www.bilibili.com/video/([0-9a-zA-Z]+)`)
limit = ctxext.NewLimiterManager(time.Second*10, 1)
)
// 插件主体
func init() {
en := control.Register("bilibiliparse", &ctrl.Options[*zero.Ctx]{
DisableOnDefault: false,
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",
})
en.OnRegex(`(av[0-9]+|BV[0-9a-zA-Z]{10}){1}`).SetBlock(true).Limit(limit.LimitByGroup).
Handle(func(ctx *zero.Ctx) {
if strings.Contains(ctx.MessageString(), "[CQ:forward") {
return
}
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://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
}
m, err := parse(cuturl(realurl))
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
ctx.Send(m)
})
}
// parse 解析视频数据
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 {
return
}
var r result
err = json.Unmarshal(data, &r)
if err != nil {
return
}
m = make(message.Message, 0, 16)
m = append(m, message.Text("标题: ", r.Data.Title, "\n"))
if r.Data.Rights.IsCooperation == 1 {
for i := 0; i < len(r.Data.Staff); i++ {
m = append(m, message.Text(r.Data.Staff[i].Title, ": ", r.Data.Staff[i].Name, ", 粉丝: ", row(r.Data.Staff[i].Follower), "\n"))
}
} else {
o, err := getcard(r.Data.Owner.Mid)
if err != nil {
return m, err
}
m = append(m, message.Text("UP主: ", r.Data.Owner.Name, ", 粉丝: ", row(o.Data.Card.Fans), "\n"))
}
m = append(m, message.Text("播放: ", row(r.Data.Stat.View), ", 弹幕: ", row(r.Data.Stat.Danmaku), "\n"),
message.Image(r.Data.Pic),
message.Text("\n点赞: ", row(r.Data.Stat.Like), ", 投币: ", row(r.Data.Stat.Coin), "\n收藏: ", row(r.Data.Stat.Favorite), ", 分享: ", row(r.Data.Stat.Share), "\n", origin, id))
return
}
// 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) {
if !reg.MatchString(url) {
return
}
return reg.FindStringSubmatch(url)[1]
}
// 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
}
func row(res int) string {
if res/10000 != 0 {
return strconv.FormatFloat(float64(res)/10000, 'f', 2, 64) + "万"
}
return strconv.Itoa(res)
}

View File

@ -12,6 +12,7 @@ import (
// mo 摸
func mo(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -48,6 +49,7 @@ func mo(cc *context, value ...string) (string, error) {
// cuo 搓
func cuo(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -88,6 +90,7 @@ func cuo(cc *context, value ...string) (string, error) {
// qiao 敲
func qiao(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -121,6 +124,7 @@ func qiao(cc *context, value ...string) (string, error) {
// chi 吃
func chi(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -155,6 +159,7 @@ func chi(cc *context, value ...string) (string, error) {
// ceng 蹭
func ceng(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -196,6 +201,7 @@ func ceng(cc *context, value ...string) (string, error) {
// ken 啃
func ken(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -243,6 +249,7 @@ func ken(cc *context, value ...string) (string, error) {
// pai 拍
func pai(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -276,6 +283,7 @@ func pai(cc *context, value ...string) (string, error) {
// xqe 冲
func xqe(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -309,6 +317,7 @@ func xqe(cc *context, value ...string) (string, error) {
// diu 丢
func diu(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -348,6 +357,7 @@ func diu(cc *context, value ...string) (string, error) {
// kiss 亲
func kiss(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -386,6 +396,7 @@ func kiss(cc *context, value ...string) (string, error) {
// garbage 垃圾 垃圾桶
func garbage(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -418,6 +429,7 @@ func garbage(cc *context, value ...string) (string, error) {
// thump 捶
func thump(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -450,6 +462,7 @@ func thump(cc *context, value ...string) (string, error) {
// jiujiu 啾啾
func jiujiu(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -481,6 +494,7 @@ func jiujiu(cc *context, value ...string) (string, error) {
// knock 2敲
func knock(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -513,6 +527,7 @@ func knock(cc *context, value ...string) (string, error) {
// 听音乐 listenMusic
func listenMusic(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -544,6 +559,7 @@ func listenMusic(cc *context, value ...string) (string, error) {
// loveYou 永远爱你
func loveYou(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -576,6 +592,7 @@ func loveYou(cc *context, value ...string) (string, error) {
// pat 2拍
func pat(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -617,6 +634,7 @@ func pat(cc *context, value ...string) (string, error) {
// jackUp 顶
func jackUp(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -659,6 +677,7 @@ func jackUp(cc *context, value ...string) (string, error) {
// pound 捣
func pound(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -691,6 +710,7 @@ func pound(cc *context, value ...string) (string, error) {
// punch 打拳
func punch(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -723,6 +743,7 @@ func punch(cc *context, value ...string) (string, error) {
// roll 滚
func roll(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -755,6 +776,7 @@ func roll(cc *context, value ...string) (string, error) {
// suck 吸 嗦
func suck(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -787,6 +809,7 @@ func suck(cc *context, value ...string) (string, error) {
// hammer 锤
func hammer(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -819,6 +842,7 @@ func hammer(cc *context, value ...string) (string, error) {
// tightly 紧贴 紧紧贴着
func tightly(cc *context, value ...string) (string, error) {
_ = value
var wg sync.WaitGroup
var err error
var m sync.Mutex
@ -851,6 +875,7 @@ func tightly(cc *context, value ...string) (string, error) {
// turn 转
func turn(cc *context, value ...string) (string, error) {
_ = value
name := cc.usrdir + "Turn.gif"
face, err := cc.getLogo(0, 0)
if err != nil {

View File

@ -17,6 +17,7 @@ import (
// pa 爬
func pa(cc *context, args ...string) (string, error) {
_ = args
name := cc.usrdir + "爬.png"
tou, err := cc.getLogo(0, 0)
if err != nil {
@ -43,6 +44,7 @@ func pa(cc *context, args ...string) (string, error) {
// si 撕
func si(cc *context, args ...string) (string, error) {
_ = args
name := cc.usrdir + "撕.png"
tou, err := cc.getLogo(0, 0)
if err != nil {
@ -69,6 +71,7 @@ func si(cc *context, args ...string) (string, error) {
// flipV 上翻,下翻
func flipV(cc *context, args ...string) (string, error) {
_ = args
name := cc.usrdir + "FlipV.png"
// 加载图片
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
@ -81,6 +84,7 @@ func flipV(cc *context, args ...string) (string, error) {
// flipH 左翻,右翻
func flipH(cc *context, args ...string) (string, error) {
_ = args
name := cc.usrdir + "FlipH.png"
// 加载图片
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
@ -93,6 +97,7 @@ func flipH(cc *context, args ...string) (string, error) {
// invert 反色
func invert(cc *context, args ...string) (string, error) {
_ = args
name := cc.usrdir + "Invert.png"
// 加载图片
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
@ -105,6 +110,7 @@ func invert(cc *context, args ...string) (string, error) {
// blur 反色
func blur(cc *context, args ...string) (string, error) {
_ = args
name := cc.usrdir + "Blur.png"
// 加载图片
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
@ -117,6 +123,7 @@ func blur(cc *context, args ...string) (string, error) {
// grayscale 灰度
func grayscale(cc *context, args ...string) (string, error) {
_ = args
name := cc.usrdir + "Grayscale.png"
// 加载图片
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
@ -129,6 +136,7 @@ func grayscale(cc *context, args ...string) (string, error) {
// invertAndGrayscale 负片
func invertAndGrayscale(cc *context, args ...string) (string, error) {
_ = args
name := cc.usrdir + "InvertAndGrayscale.png"
// 加载图片
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
@ -141,6 +149,7 @@ func invertAndGrayscale(cc *context, args ...string) (string, error) {
// convolve3x3 浮雕
func convolve3x3(cc *context, args ...string) (string, error) {
_ = args
name := cc.usrdir + "Convolve3x3.png"
// 加载图片
im, err := img.LoadFirstFrame(cc.headimgsdir[0], 0, 0)
@ -186,6 +195,7 @@ func deformation(cc *context, args ...string) (string, error) {
// alike 你像个xxx一样
func alike(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -213,6 +223,7 @@ func alike(cc *context, args ...string) (string, error) {
// marriage
func marriage(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -331,6 +342,7 @@ func alwaysLike(cc *context, args ...string) (string, error) {
// decentKiss 像样的亲亲
func decentKiss(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -358,6 +370,7 @@ func decentKiss(cc *context, args ...string) (string, error) {
// chinaFlag 国旗
func chinaFlag(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -385,6 +398,7 @@ func chinaFlag(cc *context, args ...string) (string, error) {
// dontTouch 不要靠近
func dontTouch(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -490,6 +504,7 @@ func interview(cc *context, args ...string) (string, error) {
// need 需要 你可能需要
func need(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -517,6 +532,7 @@ func need(cc *context, args ...string) (string, error) {
// paint 这像画吗
func paint(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -544,6 +560,7 @@ func paint(cc *context, args ...string) (string, error) {
// painter 小画家
func painter(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -571,6 +588,7 @@ func painter(cc *context, args ...string) (string, error) {
// perfect 完美
func perfect(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -643,6 +661,7 @@ func playGame(cc *context, args ...string) (string, error) {
// police 出警
func police(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -670,6 +689,7 @@ func police(cc *context, args ...string) (string, error) {
// police1 警察
func police1(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -697,6 +717,7 @@ func police1(cc *context, args ...string) (string, error) {
// prpr 舔 舔屏 prpr
func prpr(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -771,6 +792,7 @@ func safeSense(cc *context, args ...string) (string, error) {
// support 精神支柱
func support(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -798,6 +820,7 @@ func support(cc *context, args ...string) (string, error) {
// thinkwhat 想什么
func thinkwhat(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -825,6 +848,7 @@ func thinkwhat(cc *context, args ...string) (string, error) {
// wallpaper 墙纸
func wallpaper(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -852,6 +876,7 @@ func wallpaper(cc *context, args ...string) (string, error) {
// whyatme 为什么at我
func whyatme(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -927,6 +952,7 @@ func makeFriend(cc *context, args ...string) (string, error) {
// backToWork 打工人, 继续干活
func backToWork(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -1004,6 +1030,7 @@ func coupon(cc *context, args ...string) (string, error) {
// distracted 注意力涣散
func distracted(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error
@ -1031,6 +1058,7 @@ func distracted(cc *context, args ...string) (string, error) {
// throw 扔
func throw(cc *context, args ...string) (string, error) {
_ = args
var wg sync.WaitGroup
var m sync.Mutex
var err error

View File

@ -61,9 +61,9 @@ func init() { // 插件主体
"Star/Fork/Issue: ",
repo.Get("watchers").Int(), "/", repo.Get("forks").Int(), "/", repo.Get("open_issues").Int(), "\n",
"Language: ",
notnull(repo.Get("language").Str, "None"), "\n",
notnull(repo.Get("language").Str), "\n",
"License: ",
notnull(strings.ToUpper(repo.Get("license.key").Str), "None"), "\n",
notnull(strings.ToUpper(repo.Get("license.key").Str)), "\n",
"Last pushed: ",
repo.Get("pushed_at").Str, "\n",
"Jump: ",
@ -79,9 +79,9 @@ func init() { // 插件主体
"Star/Fork/Issue: ",
repo.Get("watchers").Int(), "/", repo.Get("forks").Int(), "/", repo.Get("open_issues").Int(), "\n",
"Language: ",
notnull(repo.Get("language").Str, "None"), "\n",
notnull(repo.Get("language").Str), "\n",
"License: ",
notnull(strings.ToUpper(repo.Get("license.key").Str), "None"), "\n",
notnull(strings.ToUpper(repo.Get("license.key").Str)), "\n",
"Last pushed: ",
repo.Get("pushed_at").Str, "\n",
"Jump: ",
@ -97,9 +97,9 @@ func init() { // 插件主体
// notnull 如果传入文本为空,则返回默认值
func notnull(text, defstr string) string {
func notnull(text string) string {
if text == "" {
return defstr
return "None"
}
return text
}