bilibili/subtitles/client.go

130 lines
3.2 KiB
Go
Raw Normal View History

2024-07-01 17:22:31 +08:00
package main
import (
"fmt"
"github.com/gofiber/fiber/v3/client"
"net/url"
"regexp"
"strconv"
"strings"
)
var headers = map[string][]string{
"Accept": {"application/json"},
"Content-Type": {"application/json"},
"User-Agent": {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"},
"Host": {"api.bilibili.com"},
}
type Client struct {
cli *client.Client
}
func NewClient(sessData string) *Client {
return &Client{
cli: client.New().AddHeaders(headers).SetCookie("SESSDATA", sessData),
}
}
func (c *Client) GetSubtitles(url string) (string, error) {
vid, page, err := parseBilibiliUrl(url)
if err != nil {
return "", err
}
data, err := c.callView(vid)
if err != nil {
return "", err
}
var aid, cid = data.Data.Stat.Aid, 0
for _, p := range data.Data.Pages {
if p.Page == page {
cid = p.Cid
}
}
player, err := c.callPlayer(aid, cid)
if err != nil {
return "", err
}
subTitlesUrl := ""
for _, sub := range player.Data.Subtitle.Subtitles {
if sub.SubtitleUrl != "" {
subTitlesUrl = fmt.Sprintf("https:%s", sub.SubtitleUrl)
break
}
}
subtitles, err := c.callSubtitles(subTitlesUrl)
if err != nil {
return "", err
}
var subtitlesList = make([]string, 0, len(subtitles.Body))
for _, sub := range subtitles.Body {
subtitlesList = append(subtitlesList, sub.Content)
}
return strings.Join(subtitlesList, "\n"), nil
}
func (c *Client) callView(vid string) (data Response[ViewResponseData], err error) {
var r = c.cli.R()
if strings.HasPrefix(vid, "av") {
r.AddParam("aid", vid[2:])
} else {
r.AddParam("bvid", vid)
}
resp, err := r.Get("https://api.bilibili.com/x/web-interface/view")
if err != nil {
return data, fmt.Errorf("请求 %s 出错:%v", r.URL(), err)
}
err = resp.JSON(&data)
return data, err
}
func (c *Client) callPlayer(aid, cid int) (data Response[PlayerResponseData], err error) {
var r = c.cli.R()
r.AddParam("aid", strconv.Itoa(aid))
r.AddParam("cid", strconv.Itoa(cid))
resp, err := r.Get("https://api.bilibili.com/x/player/v2")
if err != nil {
return data, fmt.Errorf("请求 %s 出错:%v", r.URL(), err)
}
err = resp.JSON(&data)
return data, err
}
func (c *Client) callSubtitles(url string) (data SubtitlesResponse, err error) {
var r = c.cli.R()
resp, err := r.Get(url)
if err != nil {
return data, fmt.Errorf("请求 %s 出错:%v", r.URL(), err)
}
err = resp.JSON(&data)
return data, err
}
func parseBilibiliUrl(bu string) (vid string, page int, err error) {
u, err := url.Parse(bu)
if err != nil {
return "", 0, err
}
if u.Host != "www.bilibili.com" && u.Host != "m.bilibili.com" {
return "", 0, fmt.Errorf("链接似乎不是bilibili的视频链接")
}
re := regexp.MustCompile("/video/(?P<vid>[a-zA-Z0-9]+)")
parts := re.FindStringSubmatch(u.Path)
names := re.SubexpNames()
for _, name := range names {
if name == "vid" {
vid = parts[re.SubexpIndex(name)]
}
}
if vid == "" {
return "", 0, fmt.Errorf("链接似乎不是bilibili的视频链接未获取到视频id")
}
query := u.Query()
if query.Get("p") != "" {
pageStr := query.Get("p")
page, _ = strconv.Atoi(pageStr)
}
return vid, page, nil
}