From 5978c583a966fd89f96235f620e2c0c59607fdb9 Mon Sep 17 00:00:00 2001 From: zijiren233 Date: Thu, 13 Feb 2025 21:50:57 +0800 Subject: [PATCH] feat: bilibili video danmuku --- internal/cache/bilibili.go | 35 +++++++++++++++++-- .../vendors/vendorBilibili/bilibili.go | 16 +++++++++ .../vendors/vendorbilibili/bilibili.go | 16 +++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/internal/cache/bilibili.go b/internal/cache/bilibili.go index b23ca47..7f5e7b3 100644 --- a/internal/cache/bilibili.go +++ b/internal/cache/bilibili.go @@ -2,10 +2,12 @@ package cache import ( "bytes" + "compress/flate" "context" "encoding/json" "errors" "fmt" + "io" "math" "net/http" "time" @@ -353,8 +355,6 @@ func translateBilibiliSubtitleToSrt(ctx context.Context, url string) ([]byte, er return convertToSRT(&srt), nil } -type BilibiliLiveCache struct{} - func NewBilibiliLiveCacheInitFunc(movie *model.Movie) func(ctx context.Context) ([]byte, error) { return func(ctx context.Context) ([]byte, error) { return BilibiliLiveCacheInitFunc(ctx, movie) @@ -387,11 +387,41 @@ func BilibiliLiveCacheInitFunc(ctx context.Context, movie *model.Movie) ([]byte, 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 { NoSharedMovie *MapCache[string, *BilibiliUserCache] SharedMpd *refreshcache1.RefreshCache[*BilibiliMpdCache, *BilibiliUserCache] Subtitle *refreshcache1.RefreshCache[BilibiliSubtitleCache, *BilibiliUserCache] Live *refreshcache0.RefreshCache[[]byte] + Danmu *refreshcache0.RefreshCache[[]byte] } func NewBilibiliMovieCache(movie *model.Movie) *BilibiliMovieCache { @@ -400,6 +430,7 @@ func NewBilibiliMovieCache(movie *model.Movie) *BilibiliMovieCache { SharedMpd: refreshcache1.NewRefreshCache(NewBilibiliSharedMpdCacheInitFunc(movie), time.Minute*55), Subtitle: refreshcache1.NewRefreshCache(NewBilibiliSubtitleCacheInitFunc(movie), -1), Live: refreshcache0.NewRefreshCache(NewBilibiliLiveCacheInitFunc(movie), time.Minute*55), + Danmu: refreshcache0.NewRefreshCache(NewBilibiliDanmuCacheInitFunc(movie), -1), } } diff --git a/server/handlers/vendors/vendorBilibili/bilibili.go b/server/handlers/vendors/vendorBilibili/bilibili.go index abc0c78..524c050 100644 --- a/server/handlers/vendors/vendorBilibili/bilibili.go +++ b/server/handlers/vendors/vendorBilibili/bilibili.go @@ -60,9 +60,21 @@ func (s *BilibiliVendorService) ProxyMovie(ctx *gin.Context) { s.handleVideoProxy(ctx, log, t) case "subtitle": 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) { data, err := s.movie.BilibiliCache().Live.Get(ctx) if err != nil { @@ -219,6 +231,8 @@ func (s *BilibiliVendorService) GenMovieInfo(ctx context.Context, user *op.User, 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 if movie.MovieBase.VendorInfo.Bilibili.Shared { var u *op.UserEntry @@ -267,6 +281,8 @@ func (s *BilibiliVendorService) GenProxyMovieInfo(ctx context.Context, user *op. 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.Type = "mpd" movie.MovieBase.MoreSources = []*dbModel.MoreSource{ diff --git a/server/handlers/vendors/vendorbilibili/bilibili.go b/server/handlers/vendors/vendorbilibili/bilibili.go index abc0c78..524c050 100644 --- a/server/handlers/vendors/vendorbilibili/bilibili.go +++ b/server/handlers/vendors/vendorbilibili/bilibili.go @@ -60,9 +60,21 @@ func (s *BilibiliVendorService) ProxyMovie(ctx *gin.Context) { s.handleVideoProxy(ctx, log, t) case "subtitle": 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) { data, err := s.movie.BilibiliCache().Live.Get(ctx) if err != nil { @@ -219,6 +231,8 @@ func (s *BilibiliVendorService) GenMovieInfo(ctx context.Context, user *op.User, 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 if movie.MovieBase.VendorInfo.Bilibili.Shared { var u *op.UserEntry @@ -267,6 +281,8 @@ func (s *BilibiliVendorService) GenProxyMovieInfo(ctx context.Context, user *op. 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.Type = "mpd" movie.MovieBase.MoreSources = []*dbModel.MoreSource{