mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-08 22:36:37 +08:00
@@ -152,14 +152,14 @@ func TestEmbyPlaybackInfoDoesNotExposeTokenInCloudPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
source := body["MediaSources"].([]any)[0].(map[string]any)
|
source := body["MediaSources"].([]any)[0].(map[string]any)
|
||||||
pathURL, _ := source["Path"].(string)
|
pathURL, _ := source["Path"].(string)
|
||||||
if pathURL != "/api/stream/cloud-1" {
|
if pathURL != "/Movies/Movie.mkv" {
|
||||||
t.Fatalf("cloud Path should stay as non-tokenized display stream URL, got %#v", source)
|
t.Fatalf("cloud Path should expose the OpenList source path, got %#v", source)
|
||||||
}
|
}
|
||||||
if strings.Contains(pathURL, "api_key=") || strings.Contains(pathURL, "token=") {
|
if strings.Contains(pathURL, "api_key=") || strings.Contains(pathURL, "token=") {
|
||||||
t.Fatalf("cloud Path must not expose auth key/token: %#v", source)
|
t.Fatalf("cloud Path must not expose auth key/token: %#v", source)
|
||||||
}
|
}
|
||||||
if strings.Contains(pathURL, "/api/cloud/play/") {
|
if strings.Contains(pathURL, "/api/cloud/play/") || strings.Contains(pathURL, "/api/stream/") {
|
||||||
t.Fatalf("cloud Path should not expose naked cloud play URL: %#v", source)
|
t.Fatalf("cloud Path should not expose a playback URL: %#v", source)
|
||||||
}
|
}
|
||||||
directURL, _ := source["DirectStreamUrl"].(string)
|
directURL, _ := source["DirectStreamUrl"].(string)
|
||||||
if !strings.HasPrefix(directURL, "/api/stream/cloud-1") || !strings.Contains(directURL, "api_key=") {
|
if !strings.HasPrefix(directURL, "/api/stream/cloud-1") || !strings.Contains(directURL, "api_key=") {
|
||||||
@@ -236,8 +236,8 @@ func TestEmbyItemsDoNotExposeTokenInEmbeddedCloudPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
source := items[0].(map[string]any)["MediaSources"].([]any)[0].(map[string]any)
|
source := items[0].(map[string]any)["MediaSources"].([]any)[0].(map[string]any)
|
||||||
pathURL, _ := source["Path"].(string)
|
pathURL, _ := source["Path"].(string)
|
||||||
if pathURL != "/api/stream/cloud-1" {
|
if pathURL != "/Movies/Movie.mkv" {
|
||||||
t.Fatalf("embedded cloud Path should stay as non-tokenized display stream URL, got %#v", source)
|
t.Fatalf("embedded cloud Path should expose the OpenList source path, got %#v", source)
|
||||||
}
|
}
|
||||||
if strings.Contains(pathURL, "api_key=") || strings.Contains(pathURL, "token=") {
|
if strings.Contains(pathURL, "api_key=") || strings.Contains(pathURL, "token=") {
|
||||||
t.Fatalf("embedded cloud Path must not expose auth key/token: %#v", source)
|
t.Fatalf("embedded cloud Path must not expose auth key/token: %#v", source)
|
||||||
|
|||||||
@@ -204,7 +204,6 @@ func (e *EmbyService) mediaSource(ctx context.Context, m *model.Media, asEmbedde
|
|||||||
// follow the same STRM entry as generated .strm files; when disabled we
|
// follow the same STRM entry as generated .strm files; when disabled we
|
||||||
// expose /Videos/{id}/stream so playback uses the Emby 302/proxy path.
|
// expose /Videos/{id}/stream so playback uses the Emby 302/proxy path.
|
||||||
src["IsRemote"] = true
|
src["IsRemote"] = true
|
||||||
src["Path"] = playURL
|
|
||||||
}
|
}
|
||||||
return src
|
return src
|
||||||
}
|
}
|
||||||
@@ -213,7 +212,7 @@ func (e *EmbyService) baseMediaSource(m *model.Media, container string, isCloud
|
|||||||
return map[string]any{
|
return map[string]any{
|
||||||
"Id": m.ID,
|
"Id": m.ID,
|
||||||
"Name": m.Title,
|
"Name": m.Title,
|
||||||
"Path": m.Path,
|
"Path": embyMediaSourcePath(m),
|
||||||
"Container": container,
|
"Container": container,
|
||||||
"Size": m.SizeBytes,
|
"Size": m.SizeBytes,
|
||||||
"Protocol": "Http",
|
"Protocol": "Http",
|
||||||
@@ -231,6 +230,35 @@ func (e *EmbyService) baseMediaSource(m *model.Media, container string, isCloud
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// embyMediaSourcePath keeps Emby's Path field as a source identity rather
|
||||||
|
// than a playback endpoint. OpenList and other path-based cloud providers
|
||||||
|
// carry the real provider path in the internal cloud-play ref query. For
|
||||||
|
// opaque provider refs, fall back to the display path stored in cloud://.
|
||||||
|
func embyMediaSourcePath(m *model.Media) string {
|
||||||
|
if m == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if _, ref, ok := parseCloudMediaPlaybackURL(m.STRMURL); ok && strings.HasPrefix(ref, "/") {
|
||||||
|
return ref
|
||||||
|
}
|
||||||
|
raw := strings.TrimSpace(m.Path)
|
||||||
|
u, err := url.Parse(raw)
|
||||||
|
if err != nil || !strings.EqualFold(u.Scheme, "cloud") {
|
||||||
|
return m.Path
|
||||||
|
}
|
||||||
|
sourcePath := strings.TrimSpace(u.Path)
|
||||||
|
if decoded, decodeErr := url.PathUnescape(sourcePath); decodeErr == nil {
|
||||||
|
sourcePath = decoded
|
||||||
|
}
|
||||||
|
if sourcePath == "" {
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(sourcePath, "/") {
|
||||||
|
sourcePath = "/" + sourcePath
|
||||||
|
}
|
||||||
|
return sourcePath
|
||||||
|
}
|
||||||
|
|
||||||
func embyMediaContainer(m *model.Media) string {
|
func embyMediaContainer(m *model.Media) string {
|
||||||
container := strings.Trim(strings.ToLower(m.Container), ". ")
|
container := strings.Trim(strings.ToLower(m.Container), ". ")
|
||||||
if container == "" {
|
if container == "" {
|
||||||
|
|||||||
@@ -335,8 +335,8 @@ func TestEmbyPlaybackInfoKeepsSTRMBehindStreamEndpoint(t *testing.T) {
|
|||||||
if src["DirectStreamUrl"] != "/api/stream/cloud-1" {
|
if src["DirectStreamUrl"] != "/api/stream/cloud-1" {
|
||||||
t.Fatalf("strm playback should prefer /api/stream when enabled: %#v", src)
|
t.Fatalf("strm playback should prefer /api/stream when enabled: %#v", src)
|
||||||
}
|
}
|
||||||
if src["Path"] != "/api/stream/cloud-1" {
|
if src["Path"] != "/Movies/f1.mkv" {
|
||||||
t.Fatalf("path should prefer /api/stream when enabled: %#v", src)
|
t.Fatalf("path should expose the OpenList source path: %#v", src)
|
||||||
}
|
}
|
||||||
streams := src["MediaStreams"].([]map[string]any)
|
streams := src["MediaStreams"].([]map[string]any)
|
||||||
if len(streams) == 0 || streams[0]["Type"] != "Video" {
|
if len(streams) == 0 || streams[0]["Type"] != "Video" {
|
||||||
@@ -373,8 +373,23 @@ func TestEmbyPlaybackInfoUsesVideoStreamWhenSTRMDisabled(t *testing.T) {
|
|||||||
if src["DirectStreamUrl"] != "/Videos/cloud-302/stream.mkv" {
|
if src["DirectStreamUrl"] != "/Videos/cloud-302/stream.mkv" {
|
||||||
t.Fatalf("302/proxy mode should use Emby video stream URL: %#v", src)
|
t.Fatalf("302/proxy mode should use Emby video stream URL: %#v", src)
|
||||||
}
|
}
|
||||||
if src["Path"] != "/Videos/cloud-302/stream.mkv" {
|
if src["Path"] != "/Movies/Movie.mkv" {
|
||||||
t.Fatalf("302/proxy mode path should use Emby video stream URL: %#v", src)
|
t.Fatalf("302/proxy mode should preserve the OpenList source path: %#v", src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmbyMediaSourcePathFallsBackToCloudDisplayPath(t *testing.T) {
|
||||||
|
media := &model.Media{
|
||||||
|
Path: `cloud://cloud115/Shows/My%20Show/S01E01.mkv`,
|
||||||
|
STRMURL: `/api/cloud/play/cloud115?ref=opaque-file-id`,
|
||||||
|
}
|
||||||
|
if got := embyMediaSourcePath(media); got != "/Shows/My Show/S01E01.mkv" {
|
||||||
|
t.Fatalf("source path = %q", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
local := &model.Media{Path: `D:\\Media\\Movie.mkv`, STRMURL: `https://example.test/movie.mkv`}
|
||||||
|
if got := embyMediaSourcePath(local); got != local.Path {
|
||||||
|
t.Fatalf("local path = %q, want %q", got, local.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user