mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-12 00:06:37 +08:00
初始化
初始化项目
This commit is contained in:
@@ -5,7 +5,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/service/cloud"
|
||||
)
|
||||
|
||||
func TestEmbyRootItemsExposeLibraries(t *testing.T) {
|
||||
@@ -303,165 +302,3 @@ func TestEmbyPlaybackInfoRespectsDirectPlayOnly(t *testing.T) {
|
||||
t.Fatalf("direct-only must still allow direct play: %#v", src)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbyPlaybackInfoKeepsSTRMBehindStreamEndpoint(t *testing.T) {
|
||||
svc := newTestEmbyService(t)
|
||||
if err := svc.repo.Setting.Set(t.Context(), CloudPlaybackModeSettingKey, CloudPlaybackModeSTRM); err != nil {
|
||||
t.Fatalf("set cloud playback mode: %v", err)
|
||||
}
|
||||
lib := model.Library{Name: "OpenList", Path: `cloud://openlist/Movies`, Type: "movie", Enabled: true}
|
||||
if err := svc.repo.Library.Create(t.Context(), &lib); err != nil {
|
||||
t.Fatalf("create library: %v", err)
|
||||
}
|
||||
media := model.Media{
|
||||
Base: model.Base{ID: "cloud-1"},
|
||||
LibraryID: lib.ID,
|
||||
Title: "Cloud Movie",
|
||||
Path: `cloud://openlist/Movies/f1.mkv`,
|
||||
STRMURL: `/api/cloud/play/openlist?ref=%2FMovies%2Ff1.mkv`,
|
||||
}
|
||||
if err := svc.repo.DB.Create(&media).Error; err != nil {
|
||||
t.Fatalf("create media: %v", err)
|
||||
}
|
||||
|
||||
pb, err := svc.PlaybackInfo(t.Context(), "cloud-1", "user-1")
|
||||
if err != nil {
|
||||
t.Fatalf("playback info: %v", err)
|
||||
}
|
||||
src := pb["MediaSources"].([]map[string]any)[0]
|
||||
if src["IsRemote"] != true {
|
||||
t.Fatalf("strm media should be marked remote: %#v", src)
|
||||
}
|
||||
if src["DirectStreamUrl"] != "/api/stream/cloud-1" {
|
||||
t.Fatalf("strm playback should prefer /api/stream when enabled: %#v", src)
|
||||
}
|
||||
if src["Path"] != "/Movies/f1.mkv" {
|
||||
t.Fatalf("path should expose the OpenList source path: %#v", src)
|
||||
}
|
||||
streams := src["MediaStreams"].([]map[string]any)
|
||||
if len(streams) == 0 || streams[0]["Type"] != "Video" {
|
||||
t.Fatalf("strm media should expose a fallback video stream for Android clients: %#v", src)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbyPlaybackInfoUsesVideoStreamWhenSTRMDisabled(t *testing.T) {
|
||||
svc := newTestEmbyService(t)
|
||||
if err := svc.repo.Setting.Set(t.Context(), CloudPlaybackModeSettingKey, CloudPlaybackModeRedirectProxy); err != nil {
|
||||
t.Fatalf("set cloud playback mode: %v", err)
|
||||
}
|
||||
lib := model.Library{Name: "OpenList", Path: `cloud://openlist/Movies`, Type: "movie", Enabled: true}
|
||||
if err := svc.repo.Library.Create(t.Context(), &lib); err != nil {
|
||||
t.Fatalf("create library: %v", err)
|
||||
}
|
||||
media := model.Media{
|
||||
Base: model.Base{ID: "cloud-302"},
|
||||
LibraryID: lib.ID,
|
||||
Title: "Cloud 302 Movie",
|
||||
Path: `cloud://openlist/Movies/Movie.mkv`,
|
||||
STRMURL: `/api/cloud/play/openlist?ref=%2FMovies%2FMovie.mkv`,
|
||||
Container: "mkv",
|
||||
}
|
||||
if err := svc.repo.DB.Create(&media).Error; err != nil {
|
||||
t.Fatalf("create media: %v", err)
|
||||
}
|
||||
|
||||
pb, err := svc.PlaybackInfo(t.Context(), "cloud-302", "user-1")
|
||||
if err != nil {
|
||||
t.Fatalf("playback info: %v", err)
|
||||
}
|
||||
src := pb["MediaSources"].([]map[string]any)[0]
|
||||
if src["DirectStreamUrl"] != "/Videos/cloud-302/stream.mkv" {
|
||||
t.Fatalf("302/proxy mode should use Emby video stream URL: %#v", src)
|
||||
}
|
||||
if src["Path"] != "/Movies/Movie.mkv" {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbyPlaybackInfoProbesMissingCloudTrackMetadata(t *testing.T) {
|
||||
svc := newTestEmbyService(t)
|
||||
lib := model.Library{Name: "OpenList", Path: `cloud://openlist/Movies`, Type: "movie", Enabled: true}
|
||||
if err := svc.repo.Library.Create(t.Context(), &lib); err != nil {
|
||||
t.Fatalf("create library: %v", err)
|
||||
}
|
||||
media := model.Media{
|
||||
Base: model.Base{ID: "cloud-probe-1"},
|
||||
LibraryID: lib.ID,
|
||||
Title: "云盘电影",
|
||||
Path: `cloud://openlist/Movies/Movie.mkv`,
|
||||
STRMURL: `http://nas.local/api/cloud/play/openlist?ref=%2FMovies%2FMovie.mkv`,
|
||||
}
|
||||
if err := svc.repo.DB.Create(&media).Error; err != nil {
|
||||
t.Fatalf("create media: %v", err)
|
||||
}
|
||||
resolver := &fakeCloudPlaybackResolver{
|
||||
link: &cloud.DirectLink{
|
||||
URL: "http://cdn.example.test/Movie.mkv",
|
||||
Headers: map[string]string{"Authorization": "Bearer probe-token"},
|
||||
},
|
||||
}
|
||||
prober := &fakeCloudPlaybackProber{
|
||||
probe: &ProbeResult{
|
||||
DurationSec: 3661,
|
||||
Width: 3840,
|
||||
Height: 2160,
|
||||
VideoCodec: "hevc",
|
||||
AudioCodec: "eac3",
|
||||
Container: "matroska,webm",
|
||||
},
|
||||
}
|
||||
svc.SetCloudProbe(resolver, prober)
|
||||
|
||||
if _, err := svc.PlaybackInfo(t.Context(), "cloud-probe-1", "user-1"); err != nil {
|
||||
t.Fatalf("playback info: %v", err)
|
||||
}
|
||||
|
||||
var persisted model.Media
|
||||
deadline := time.Now().Add(3 * time.Second)
|
||||
for {
|
||||
if err := svc.repo.DB.First(&persisted, "id = ?", "cloud-probe-1").Error; err != nil {
|
||||
t.Fatalf("reload media: %v", err)
|
||||
}
|
||||
if persisted.DurationSec > 0 || time.Now().After(deadline) {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
if persisted.DurationSec != 3661 || persisted.Width != 3840 || persisted.Height != 2160 || persisted.VideoCodec != "hevc" || persisted.AudioCodec != "eac3" {
|
||||
t.Fatalf("probe metadata not persisted: %#v", persisted)
|
||||
}
|
||||
if resolver.typ != "openlist" || resolver.ref != "/Movies/Movie.mkv" {
|
||||
t.Fatalf("resolver called with typ=%q ref=%q", resolver.typ, resolver.ref)
|
||||
}
|
||||
if prober.rawURL != "http://cdn.example.test/Movie.mkv" || prober.headers["Authorization"] != "Bearer probe-token" {
|
||||
t.Fatalf("probe called with url=%q headers=%#v", prober.rawURL, prober.headers)
|
||||
}
|
||||
|
||||
pb, err := svc.PlaybackInfo(t.Context(), "cloud-probe-1", "user-1")
|
||||
if err != nil {
|
||||
t.Fatalf("playback info (second): %v", err)
|
||||
}
|
||||
src := pb["MediaSources"].([]map[string]any)[0]
|
||||
if src["RunTimeTicks"] != int64(3661)*10_000_000 {
|
||||
t.Fatalf("runtime ticks not filled after async probe: %#v", src)
|
||||
}
|
||||
streams := src["MediaStreams"].([]map[string]any)
|
||||
if len(streams) != 2 || streams[0]["Codec"] != "hevc" || streams[1]["Codec"] != "eac3" {
|
||||
t.Fatalf("media streams not filled after async probe: %#v", streams)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user