135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
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
|
||
}
|
||
}
|
||
if subTitlesUrl == "" {
|
||
return "", fmt.Errorf("没有找到字幕")
|
||
}
|
||
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)
|
||
} else {
|
||
page = 1
|
||
}
|
||
return vid, page, nil
|
||
}
|