mirror of
https://github.com/truewhile/MeBox.git
synced 2026-11-15 20:34:23 +08:00
优化播放逻辑
This commit is contained in:
@@ -124,10 +124,32 @@ func cloud115HLSSessionHandler(svc *service.Container) gin.HandlerFunc {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "missing media_id"})
|
||||
return
|
||||
}
|
||||
if !enforceScopedPlaybackToken(c, mediaID) {
|
||||
if c.Request.Context().Err() != nil {
|
||||
c.AbortWithStatus(499)
|
||||
return
|
||||
}
|
||||
err := svc.Cloud115.HLSProxy().ServeChild(
|
||||
actualMediaID, err := svc.Cloud115.HLSProxy().SessionMediaID(c.Param("session"), c.Param("key"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"code": "hls_session_not_found", "error": "hls session not found"})
|
||||
return
|
||||
}
|
||||
if mediaID != actualMediaID {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "playback session media mismatch"})
|
||||
return
|
||||
}
|
||||
if !enforceScopedPlaybackToken(c, actualMediaID) {
|
||||
return
|
||||
}
|
||||
if svc.Repo == nil || svc.Repo.Media == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "media not found"})
|
||||
return
|
||||
}
|
||||
m, findErr := svc.Repo.Media.FindByID(c.Request.Context(), actualMediaID)
|
||||
if findErr != nil || m == nil || !mediaVisibleForRequest(c, svc, m) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "media not found"})
|
||||
return
|
||||
}
|
||||
err = svc.Cloud115.HLSProxy().ServeChild(
|
||||
c.Request.Context(),
|
||||
c.Writer,
|
||||
c.Request,
|
||||
|
||||
@@ -418,7 +418,11 @@ func embyVideoHLSPlaylistHandler(svc *service.Container) gin.HandlerFunc {
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
err = svc.Stream.ServeHLSPlaylist(c.Writer, c.Request, c.Param("id"))
|
||||
scope, ok := localHLSPlaybackScope(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
err = svc.Stream.ServeHLSPlaylist(c.Writer, c.Request, c.Param("id"), scope)
|
||||
if errors.Is(err, service.ErrTranscodeDisabled) {
|
||||
c.JSON(http.StatusConflict, gin.H{"error": "transcode disabled"})
|
||||
return
|
||||
@@ -444,7 +448,11 @@ func embyVideoHLSSegmentHandler(svc *service.Container) gin.HandlerFunc {
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if err := svc.Stream.ServeHLSSegment(c.Writer, c.Request, c.Param("id"), c.Param("seg")); err != nil {
|
||||
scope, ok := localHLSPlaybackScope(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if err := svc.Stream.ServeHLSSegment(c.Writer, c.Request, c.Param("id"), c.Param("seg"), scope); err != nil {
|
||||
c.Status(http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/truewhile/MeBox/internal/middleware"
|
||||
"github.com/truewhile/MeBox/internal/model"
|
||||
"github.com/truewhile/MeBox/internal/service"
|
||||
)
|
||||
|
||||
func TestStopHLSChecksMediaVisibility(t *testing.T) {
|
||||
router, svc, secret := newPlaybackScopeTestRouter(t)
|
||||
svc.Transcoder = service.NewTranscoderService(svc.Cfg, zap.NewNop(), svc.Repo, nil)
|
||||
router.DELETE("/api/hls/:id", middleware.AuthRequired(secret), stopTranscodeHandler(svc))
|
||||
req := httptest.NewRequest(http.MethodDelete, "/api/hls/nonexistent?session_id=player-a", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+signedTestToken(t, secret))
|
||||
rec := httptest.NewRecorder()
|
||||
router.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusNotFound {
|
||||
t.Fatalf("stop of a nonexistent/invisible media: status=%d body=%s, want 404", rec.Code, rec.Body.String())
|
||||
}
|
||||
profile := &model.PlayProfile{UserID: "user-1", Name: "restricted", IsDefault: true, AllowedLibraryIDs: `["other-library"]`}
|
||||
if err := svc.Repo.DB.Create(profile).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req = httptest.NewRequest(http.MethodDelete, "/api/hls/media-1?session_id=player-a", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+signedTestToken(t, secret))
|
||||
rec = httptest.NewRecorder()
|
||||
router.ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusNotFound {
|
||||
t.Fatalf("invisible existing media can be stopped: %d %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,15 @@ func hlsPlaylistHandler(svc *service.Container) gin.HandlerFunc {
|
||||
if !enforceScopedPlaybackToken(c, m.ID) {
|
||||
return
|
||||
}
|
||||
err = svc.Stream.ServeHLSPlaylist(c.Writer, c.Request, c.Param("id"))
|
||||
scope, ok := localHLSPlaybackScope(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
err = svc.Stream.ServeHLSPlaylist(c.Writer, c.Request, c.Param("id"), scope)
|
||||
if errors.Is(err, service.ErrHLSGenerationSuperseded) {
|
||||
c.JSON(http.StatusConflict, gin.H{"code": "hls_generation_superseded", "error": err.Error()})
|
||||
return
|
||||
}
|
||||
if errors.Is(err, service.ErrMediaNotFound) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
|
||||
return
|
||||
@@ -62,7 +70,11 @@ func hlsSegmentHandler(svc *service.Container) gin.HandlerFunc {
|
||||
if !enforceScopedPlaybackToken(c, m.ID) {
|
||||
return
|
||||
}
|
||||
err = svc.Stream.ServeHLSSegment(c.Writer, c.Request, c.Param("id"), c.Param("seg"))
|
||||
scope, ok := localHLSPlaybackScope(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
err = svc.Stream.ServeHLSSegment(c.Writer, c.Request, c.Param("id"), c.Param("seg"), scope)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
|
||||
return
|
||||
@@ -72,11 +84,39 @@ func hlsSegmentHandler(svc *service.Container) gin.HandlerFunc {
|
||||
|
||||
func stopTranscodeHandler(svc *service.Container) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
svc.Transcoder.StopJob(c.Param("id"))
|
||||
m, err := findMediaForPlaybackEndpoint(c, svc, c.Param("id"))
|
||||
if err != nil || m == nil || !mediaVisibleForRequest(c, svc, m) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "media not found"})
|
||||
return
|
||||
}
|
||||
if !enforceScopedPlaybackToken(c, m.ID) {
|
||||
return
|
||||
}
|
||||
scope, ok := localHLSPlaybackScope(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if svc.Transcoder != nil {
|
||||
svc.Transcoder.StopPlayback(m.ID, scope)
|
||||
}
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
}
|
||||
|
||||
func localHLSPlaybackScope(c *gin.Context) (service.HLSPlaybackScope, bool) {
|
||||
userID := currentUserID(c)
|
||||
if userID == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing playback owner"})
|
||||
return service.HLSPlaybackScope{}, false
|
||||
}
|
||||
scope, err := service.HLSPlaybackScopeForRequest(c.Request, userID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return service.HLSPlaybackScope{}, false
|
||||
}
|
||||
return scope, true
|
||||
}
|
||||
|
||||
func imageProxyHandler(svc *service.Container) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
raw := c.Query("url")
|
||||
|
||||
Reference in New Issue
Block a user