Skip to content

Commit

Permalink
✨ 添加AI视频总结 (#41)
Browse files Browse the repository at this point in the history
* ✨ 添加AI视频总结

* 🐛 修改lint

* ✨ 搬运wbi

* 🐛 修改为大写
  • Loading branch information
guohuiyuan authored Oct 12, 2023
1 parent 7e6a3d9 commit 6cf9415
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 3 deletions.
1 change: 1 addition & 0 deletions bilibili/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.json
41 changes: 39 additions & 2 deletions bilibili/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,19 @@ func LoadDynamicDetail(str string) (card DynamicCard, err error) {
}

// GetDynamicDetail 用动态id查动态信息
func GetDynamicDetail(dynamicIDStr string) (card DynamicCard, err error) {
func GetDynamicDetail(cookiecfg *CookieConfig, dynamicIDStr string) (card DynamicCard, err error) {
var data []byte
data, err = web.GetData(fmt.Sprintf(DynamicDetailURL, dynamicIDStr))
data, err = web.RequestDataWithHeaders(web.NewDefaultClient(), fmt.Sprintf(DynamicDetailURL, dynamicIDStr), "GET", func(req *http.Request) error {
if cookiecfg != nil {
cookie := ""
cookie, err = cookiecfg.Load()
if err != nil {
return err
}
req.Header.Add("cookie", cookie)
}
return nil
}, nil)
if err != nil {
return
}
Expand Down Expand Up @@ -183,3 +193,30 @@ func GetVideoInfo(id string) (card Card, err error) {
err = json.Unmarshal(binary.StringToBytes(gjson.ParseBytes(data).Get("data").Raw), &card)
return
}

// GetVideoSummary 用av或bv查看AI视频总结
func GetVideoSummary(id string) (videoSummary VideoSummary, err error) {
var (
data []byte
card Card
)
_, 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)
if err != nil {
return
}
data, err = web.GetData(SignURL(fmt.Sprintf(VideoSummaryURL, card.BvID, card.CID)))
if err != nil {
return
}
err = json.Unmarshal(data, &videoSummary)
return
}
21 changes: 20 additions & 1 deletion bilibili/api_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package bilibili

import "testing"
import (
"testing"
)

func TestGetAllGuard(t *testing.T) {
guardUser, err := GetAllGuard("628537")
Expand All @@ -9,3 +11,20 @@ func TestGetAllGuard(t *testing.T) {
}
t.Logf("%+v\n", guardUser)
}

func TestGetVideoSummary(t *testing.T) {
videoSummary, err := GetVideoSummary("BV1ju4y1s7kn")
if err != nil {
t.Fatal(err)
}
t.Logf("%+v\n", videoSummary)
}

func TestGetDynamicDetail(t *testing.T) {
cfg := NewCookieConfig("config.json")
detail, err := GetDynamicDetail(cfg, "851252197280710664")
if err != nil {
t.Fatal(err)
}
t.Logf("%+v\n", detail)
}
31 changes: 31 additions & 0 deletions bilibili/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ const (
DanmakuURL = "https://danmakus.com/user/%v"
// AllGuardURL 查询所有舰长,提督,总督
AllGuardURL = "https://api.vtbs.moe/v1/guard/all"
// VideoSummaryURL AI视频总结
VideoSummaryURL = "https://api.bilibili.com/x/web-interface/view/conclusion/get?bvid=%v&cid=%v"
// NavURL 导航URL
NavURL = "https://api.bilibili.com/x/web-interface/nav"
)

// DynamicCard 总动态结构体,包括desc,card
Expand Down Expand Up @@ -79,6 +83,7 @@ type Card struct {
AID any `json:"aid"`
BvID any `json:"bvid"`
Dynamic any `json:"dynamic"`
CID int `json:"cid"`
Pic string `json:"pic"`
Title string `json:"title"`
ID int `json:"id"`
Expand Down Expand Up @@ -350,6 +355,32 @@ type Danmakusuki struct {
} `json:"data"`
}

// VideoSummary AI视频总结结构体
type VideoSummary struct {
Code int `json:"code"`
Message string `json:"message"`
TTL int `json:"ttl"`
Data struct {
Code int `json:"code"`
ModelResult struct {
ResultType int `json:"result_type"`
Summary string `json:"summary"`
Outline []struct {
Title string `json:"title"`
PartOutline []struct {
Timestamp int `json:"timestamp"`
Content string `json:"content"`
} `json:"part_outline"`
Timestamp int `json:"timestamp"`
} `json:"outline"`
} `json:"model_result"`
Stid string `json:"stid"`
Status int `json:"status"`
LikeNum int `json:"like_num"`
DislikeNum int `json:"dislike_num"`
} `json:"data"`
}

// CookieConfig 配置结构体
type CookieConfig struct {
BilibiliCookie string `json:"bilibili_cookie"`
Expand Down
117 changes: 117 additions & 0 deletions bilibili/wbi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package bilibili

import (
"crypto/md5"
"encoding/hex"
"net/url"
"path/filepath"
"sort"
"strconv"
"strings"
"time"

"github.com/FloatTech/floatbox/binary"
"github.com/FloatTech/floatbox/web"
"github.com/RomiChan/syncx"
"github.com/tidwall/gjson"
)

var (
mixinKeyEncTab = []int{
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
36, 20, 34, 44, 52,
}
cache syncx.Map[string, string]
lastUpdateTime time.Time
replacements = [...]string{"!", "'", "(", ")", "*"}
)

// SignURL wbi签名包装 https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md
func SignURL(urlStr string) string {
urlObj, _ := url.Parse(urlStr)
imgKey, subKey := getWbiKeysCached()
query := urlObj.Query()
params := map[string]string{}
for k, v := range query {
if len(v) > 0 {
params[k] = v[0]
}
}
newParams := wbiSign(params, imgKey, subKey)
for k, v := range newParams {
query.Set(k, v)
}
urlObj.RawQuery = query.Encode()
newURL := urlObj.String()
return newURL
}

func getMixinKey(orig string) string {
var str strings.Builder
t := 0
for _, v := range mixinKeyEncTab {
if v < len(orig) {
str.WriteByte(orig[v])
t++
}
if t > 31 {
break
}
}
return str.String()
}

func wbiSign(params map[string]string, imgKey string, subKey string) map[string]string {
mixinKey := getMixinKey(imgKey + subKey)
currTime := strconv.FormatInt(time.Now().Unix(), 10)
params["wts"] = currTime
// Sort keys
keys := make([]string, 0, len(params))
for k, v := range params {
keys = append(keys, k)
for _, old := range replacements {
v = strings.ReplaceAll(v, old, "")
}
params[k] = v
}
sort.Strings(keys)
h := md5.New()
for k, v := range keys {
h.Write([]byte(v))
h.Write([]byte{'='})
h.Write([]byte(params[v]))
if k < len(keys)-1 {
h.Write([]byte{'&'})
}
}
h.Write([]byte(mixinKey))
params["w_rid"] = hex.EncodeToString(h.Sum(make([]byte, 0, md5.Size)))
return params
}

func getWbiKeysCached() (string, string) {
if time.Since(lastUpdateTime).Minutes() > 10 {
imgKey, subKey := getWbiKeys()
cache.Store("imgKey", imgKey)
cache.Store("subKey", subKey)
lastUpdateTime = time.Now()
return imgKey, subKey
}
imgKeyI, _ := cache.Load("imgKey")
subKeyI, _ := cache.Load("subKey")
return imgKeyI, subKeyI
}

func getWbiKeys() (string, string) {
data, _ := web.GetData(NavURL)
json := binary.BytesToString(data)
imgURL := gjson.Get(json, "data.wbi_img.img_url").String()
subURL := gjson.Get(json, "data.wbi_img.sub_url").String()
imgKey := imgURL[strings.LastIndex(imgURL, "/")+1:]
imgKey = strings.TrimSuffix(imgKey, filepath.Ext(imgKey))
subKey := subURL[strings.LastIndex(subURL, "/")+1:]
subKey = strings.TrimSuffix(subKey, filepath.Ext(subKey))
return imgKey, subKey
}

0 comments on commit 6cf9415

Please sign in to comment.