mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-29 11:36:36 +08:00
fix media playback and library workflows
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/middleware"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/service"
|
||||
)
|
||||
|
||||
func enforceScopedPlaybackToken(c *gin.Context, mediaID string) bool {
|
||||
mediaID = strings.TrimSpace(mediaID)
|
||||
purpose, _ := c.Get(middleware.CtxTokenPurpose)
|
||||
if strings.TrimSpace(toString(purpose)) == "" {
|
||||
return true
|
||||
}
|
||||
if strings.TrimSpace(toString(purpose)) != service.ExternalPlaybackTokenPurpose {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "playback token scope denied"})
|
||||
return false
|
||||
}
|
||||
tokenMediaID, _ := c.Get(middleware.CtxTokenMediaID)
|
||||
if mediaID == "" || strings.TrimSpace(toString(tokenMediaID)) != mediaID {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "playback token media mismatch"})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func enforceScopedCloudPlaybackToken(c *gin.Context, svc *service.Container, typ, ref string) bool {
|
||||
purpose, _ := c.Get(middleware.CtxTokenPurpose)
|
||||
if strings.TrimSpace(toString(purpose)) == "" {
|
||||
return true
|
||||
}
|
||||
if strings.TrimSpace(toString(purpose)) != service.ExternalPlaybackTokenPurpose {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "playback token scope denied"})
|
||||
return false
|
||||
}
|
||||
tokenMediaID, _ := c.Get(middleware.CtxTokenMediaID)
|
||||
mediaID := strings.TrimSpace(toString(tokenMediaID))
|
||||
if mediaID == "" || strings.TrimSpace(c.Query("media_id")) != mediaID {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "playback token media mismatch"})
|
||||
return false
|
||||
}
|
||||
m, err := svc.Repo.Media.FindByID(c.Request.Context(), mediaID)
|
||||
if err != nil || m == nil || !mediaVisibleForRequest(c, svc, m) {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "media not found"})
|
||||
return false
|
||||
}
|
||||
if !cloudPlaybackTargetMatchesMedia(m, typ, ref) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "playback token target mismatch"})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func cloudPlaybackTargetMatchesMedia(m *model.Media, typ, ref string) bool {
|
||||
if m == nil {
|
||||
return false
|
||||
}
|
||||
if strmTyp, strmRef, ok := parseCloudPlaybackTarget(m.STRMURL); ok &&
|
||||
strings.EqualFold(strmTyp, typ) && sameCloudPlaybackRef(strmRef, ref) {
|
||||
return true
|
||||
}
|
||||
pathTyp, pathRef, ok := parseCloudMediaPath(m.Path)
|
||||
return ok && strings.EqualFold(pathTyp, typ) && sameCloudPlaybackRef(pathRef, ref)
|
||||
}
|
||||
|
||||
func parseCloudPlaybackTarget(raw string) (typ, ref string, ok bool) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return "", "", false
|
||||
}
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return "", "", false
|
||||
}
|
||||
pathValue := strings.ToLower(strings.TrimRight(u.Path, "/"))
|
||||
const prefix = "/api/cloud/play/"
|
||||
idx := strings.LastIndex(pathValue, prefix)
|
||||
if idx < 0 {
|
||||
return "", "", false
|
||||
}
|
||||
typ = strings.TrimSpace(u.Path[idx+len(prefix):])
|
||||
ref = strings.TrimSpace(u.Query().Get("ref"))
|
||||
return typ, ref, typ != "" && ref != ""
|
||||
}
|
||||
|
||||
func parseCloudMediaPath(raw string) (typ, ref string, ok bool) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if !strings.HasPrefix(strings.ToLower(raw), "cloud://") {
|
||||
return "", "", false
|
||||
}
|
||||
rest := strings.TrimPrefix(raw, "cloud://")
|
||||
parts := strings.SplitN(rest, "/", 2)
|
||||
if len(parts) != 2 {
|
||||
return "", "", false
|
||||
}
|
||||
typ = strings.TrimSpace(parts[0])
|
||||
ref = strings.TrimSpace(parts[1])
|
||||
return typ, ref, typ != "" && ref != ""
|
||||
}
|
||||
|
||||
func sameCloudPlaybackRef(a, b string) bool {
|
||||
return normalizeCloudPlaybackRef(a) == normalizeCloudPlaybackRef(b)
|
||||
}
|
||||
|
||||
func normalizeCloudPlaybackRef(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if decoded, err := url.PathUnescape(value); err == nil {
|
||||
value = decoded
|
||||
}
|
||||
value = strings.TrimSpace(value)
|
||||
return strings.TrimLeft(value, "/")
|
||||
}
|
||||
Reference in New Issue
Block a user