feat: bilibili video danmuku

main v0.9.8
zijiren233 2 weeks ago
parent b4740d5eb4
commit 5978c583a9

@ -2,10 +2,12 @@ package cache
import ( import (
"bytes" "bytes"
"compress/flate"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io"
"math" "math"
"net/http" "net/http"
"time" "time"
@ -353,8 +355,6 @@ func translateBilibiliSubtitleToSrt(ctx context.Context, url string) ([]byte, er
return convertToSRT(&srt), nil return convertToSRT(&srt), nil
} }
type BilibiliLiveCache struct{}
func NewBilibiliLiveCacheInitFunc(movie *model.Movie) func(ctx context.Context) ([]byte, error) { func NewBilibiliLiveCacheInitFunc(movie *model.Movie) func(ctx context.Context) ([]byte, error) {
return func(ctx context.Context) ([]byte, error) { return func(ctx context.Context) ([]byte, error) {
return BilibiliLiveCacheInitFunc(ctx, movie) return BilibiliLiveCacheInitFunc(ctx, movie)
@ -387,11 +387,41 @@ func BilibiliLiveCacheInitFunc(ctx context.Context, movie *model.Movie) ([]byte,
return genBilibiliLiveM3U8ListFile(resp.LiveStreams), nil return genBilibiliLiveM3U8ListFile(resp.LiveStreams), nil
} }
func NewBilibiliDanmuCacheInitFunc(movie *model.Movie) func(ctx context.Context) ([]byte, error) {
return func(ctx context.Context) ([]byte, error) {
return BilibiliDanmuCacheInitFunc(ctx, movie)
}
}
func BilibiliDanmuCacheInitFunc(ctx context.Context, movie *model.Movie) ([]byte, error) {
u := fmt.Sprintf("https://comment.bilibili.com/%d.xml", movie.VendorInfo.Bilibili.Cid)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code: %d", resp.StatusCode)
}
gz := flate.NewReader(resp.Body)
defer gz.Close()
data, err := io.ReadAll(gz)
if err != nil {
return nil, err
}
return data, nil
}
type BilibiliMovieCache struct { type BilibiliMovieCache struct {
NoSharedMovie *MapCache[string, *BilibiliUserCache] NoSharedMovie *MapCache[string, *BilibiliUserCache]
SharedMpd *refreshcache1.RefreshCache[*BilibiliMpdCache, *BilibiliUserCache] SharedMpd *refreshcache1.RefreshCache[*BilibiliMpdCache, *BilibiliUserCache]
Subtitle *refreshcache1.RefreshCache[BilibiliSubtitleCache, *BilibiliUserCache] Subtitle *refreshcache1.RefreshCache[BilibiliSubtitleCache, *BilibiliUserCache]
Live *refreshcache0.RefreshCache[[]byte] Live *refreshcache0.RefreshCache[[]byte]
Danmu *refreshcache0.RefreshCache[[]byte]
} }
func NewBilibiliMovieCache(movie *model.Movie) *BilibiliMovieCache { func NewBilibiliMovieCache(movie *model.Movie) *BilibiliMovieCache {
@ -400,6 +430,7 @@ func NewBilibiliMovieCache(movie *model.Movie) *BilibiliMovieCache {
SharedMpd: refreshcache1.NewRefreshCache(NewBilibiliSharedMpdCacheInitFunc(movie), time.Minute*55), SharedMpd: refreshcache1.NewRefreshCache(NewBilibiliSharedMpdCacheInitFunc(movie), time.Minute*55),
Subtitle: refreshcache1.NewRefreshCache(NewBilibiliSubtitleCacheInitFunc(movie), -1), Subtitle: refreshcache1.NewRefreshCache(NewBilibiliSubtitleCacheInitFunc(movie), -1),
Live: refreshcache0.NewRefreshCache(NewBilibiliLiveCacheInitFunc(movie), time.Minute*55), Live: refreshcache0.NewRefreshCache(NewBilibiliLiveCacheInitFunc(movie), time.Minute*55),
Danmu: refreshcache0.NewRefreshCache(NewBilibiliDanmuCacheInitFunc(movie), -1),
} }
} }

@ -60,9 +60,21 @@ func (s *BilibiliVendorService) ProxyMovie(ctx *gin.Context) {
s.handleVideoProxy(ctx, log, t) s.handleVideoProxy(ctx, log, t)
case "subtitle": case "subtitle":
s.handleSubtitleProxy(ctx, log) s.handleSubtitleProxy(ctx, log)
case "danmu":
s.handleDanmuProxy(ctx, log)
} }
} }
func (s *BilibiliVendorService) handleDanmuProxy(ctx *gin.Context, log *logrus.Entry) {
danmu, err := s.movie.BilibiliCache().Danmu.Get(ctx)
if err != nil {
log.Errorf("proxy vendor movie error: %v", err)
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewAPIErrorResp(err))
return
}
ctx.Data(http.StatusOK, "application/xml", danmu)
}
func (s *BilibiliVendorService) handleLiveProxy(ctx *gin.Context, log *logrus.Entry) { func (s *BilibiliVendorService) handleLiveProxy(ctx *gin.Context, log *logrus.Entry) {
data, err := s.movie.BilibiliCache().Live.Get(ctx) data, err := s.movie.BilibiliCache().Live.Get(ctx)
if err != nil { if err != nil {
@ -219,6 +231,8 @@ func (s *BilibiliVendorService) GenMovieInfo(ctx context.Context, user *op.User,
return movie, nil return movie, nil
} }
movie.Danmu = fmt.Sprintf("/api/room/movie/proxy/%s?token=%s&t=danmu&roomId=%s", movie.ID, userToken, movie.RoomID)
var str string var str string
if movie.MovieBase.VendorInfo.Bilibili.Shared { if movie.MovieBase.VendorInfo.Bilibili.Shared {
var u *op.UserEntry var u *op.UserEntry
@ -267,6 +281,8 @@ func (s *BilibiliVendorService) GenProxyMovieInfo(ctx context.Context, user *op.
return movie, nil return movie, nil
} }
movie.Danmu = fmt.Sprintf("/api/room/movie/proxy/%s?token=%s&t=danmu&roomId=%s", movie.ID, userToken, movie.RoomID)
movie.MovieBase.URL = fmt.Sprintf("/api/room/movie/proxy/%s?token=%s&roomId=%s", movie.ID, userToken, movie.RoomID) movie.MovieBase.URL = fmt.Sprintf("/api/room/movie/proxy/%s?token=%s&roomId=%s", movie.ID, userToken, movie.RoomID)
movie.MovieBase.Type = "mpd" movie.MovieBase.Type = "mpd"
movie.MovieBase.MoreSources = []*dbModel.MoreSource{ movie.MovieBase.MoreSources = []*dbModel.MoreSource{

@ -60,9 +60,21 @@ func (s *BilibiliVendorService) ProxyMovie(ctx *gin.Context) {
s.handleVideoProxy(ctx, log, t) s.handleVideoProxy(ctx, log, t)
case "subtitle": case "subtitle":
s.handleSubtitleProxy(ctx, log) s.handleSubtitleProxy(ctx, log)
case "danmu":
s.handleDanmuProxy(ctx, log)
} }
} }
func (s *BilibiliVendorService) handleDanmuProxy(ctx *gin.Context, log *logrus.Entry) {
danmu, err := s.movie.BilibiliCache().Danmu.Get(ctx)
if err != nil {
log.Errorf("proxy vendor movie error: %v", err)
ctx.AbortWithStatusJSON(http.StatusInternalServerError, model.NewAPIErrorResp(err))
return
}
ctx.Data(http.StatusOK, "application/xml", danmu)
}
func (s *BilibiliVendorService) handleLiveProxy(ctx *gin.Context, log *logrus.Entry) { func (s *BilibiliVendorService) handleLiveProxy(ctx *gin.Context, log *logrus.Entry) {
data, err := s.movie.BilibiliCache().Live.Get(ctx) data, err := s.movie.BilibiliCache().Live.Get(ctx)
if err != nil { if err != nil {
@ -219,6 +231,8 @@ func (s *BilibiliVendorService) GenMovieInfo(ctx context.Context, user *op.User,
return movie, nil return movie, nil
} }
movie.Danmu = fmt.Sprintf("/api/room/movie/proxy/%s?token=%s&t=danmu&roomId=%s", movie.ID, userToken, movie.RoomID)
var str string var str string
if movie.MovieBase.VendorInfo.Bilibili.Shared { if movie.MovieBase.VendorInfo.Bilibili.Shared {
var u *op.UserEntry var u *op.UserEntry
@ -267,6 +281,8 @@ func (s *BilibiliVendorService) GenProxyMovieInfo(ctx context.Context, user *op.
return movie, nil return movie, nil
} }
movie.Danmu = fmt.Sprintf("/api/room/movie/proxy/%s?token=%s&t=danmu&roomId=%s", movie.ID, userToken, movie.RoomID)
movie.MovieBase.URL = fmt.Sprintf("/api/room/movie/proxy/%s?token=%s&roomId=%s", movie.ID, userToken, movie.RoomID) movie.MovieBase.URL = fmt.Sprintf("/api/room/movie/proxy/%s?token=%s&roomId=%s", movie.ID, userToken, movie.RoomID)
movie.MovieBase.Type = "mpd" movie.MovieBase.Type = "mpd"
movie.MovieBase.MoreSources = []*dbModel.MoreSource{ movie.MovieBase.MoreSources = []*dbModel.MoreSource{

Loading…
Cancel
Save