mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-28 11:16:37 +08:00
fix emby cloud library merging
This commit is contained in:
@@ -231,5 +231,51 @@ func CloudLibraryMergeKey(lib model.Library) (string, bool) {
|
||||
if name == "" {
|
||||
return "", false
|
||||
}
|
||||
return strings.ToLower(strings.TrimSpace(lib.Type)) + "\x00" + name, true
|
||||
typeKey := cloudLibraryMergeTypeKey(lib.Type)
|
||||
return typeKey + "\x00" + cloudLibraryMergeNameKey(typeKey, name), true
|
||||
}
|
||||
|
||||
func cloudLibraryMergeTypeKey(libraryType string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(libraryType)) {
|
||||
case "tv", "anime", "variety":
|
||||
return "tvshows"
|
||||
default:
|
||||
return strings.ToLower(strings.TrimSpace(libraryType))
|
||||
}
|
||||
}
|
||||
|
||||
func cloudLibraryMergeNameKey(typeKey, name string) string {
|
||||
switch typeKey {
|
||||
case "movie":
|
||||
switch name {
|
||||
case "国产电影", "大陆电影", "华语电影":
|
||||
return "华语电影"
|
||||
case "外语电影", "欧美电影", "日韩电影", "日本电影", "韩国电影":
|
||||
return "外语电影"
|
||||
case "纪录", "纪录片":
|
||||
return "纪录片"
|
||||
case "演唱会", "concert":
|
||||
return "演唱会"
|
||||
case "动画电影", "动漫电影":
|
||||
return "动画电影"
|
||||
}
|
||||
case "tvshows":
|
||||
switch name {
|
||||
case "国产剧", "大陆剧", "华语剧", "国剧":
|
||||
return "国产剧"
|
||||
case "欧美剧", "美剧", "英剧":
|
||||
return "欧美剧"
|
||||
case "日韩剧", "日剧", "韩剧":
|
||||
return "日韩剧"
|
||||
case "国漫", "国产动漫", "国产动画":
|
||||
return "国漫"
|
||||
case "日番", "日漫", "番剧", "日本动漫", "日本动画":
|
||||
return "日番"
|
||||
case "欧美动漫", "欧美动画", "西方动画":
|
||||
return "欧美动漫"
|
||||
case "纪录", "纪录片":
|
||||
return "纪录片"
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
@@ -84,6 +84,61 @@ func TestFilterDisplayCloudLibrariesMergesCloudMountIntoExistingLibrary(t *testi
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterDisplayCloudLibrariesMergesEpisodicTypeAliases(t *testing.T) {
|
||||
db := newServiceTestDB(t, &model.Library{}, &model.Media{})
|
||||
repos := repository.New(db)
|
||||
local := model.Library{Name: "国漫", Path: "/media/动漫/国漫", Type: "tv", Enabled: true}
|
||||
cloud := model.Library{Name: "OpenList · 国漫", Path: BuildCloudLibraryPath("openlist", "/国漫", "/国漫"), Type: "anime", Enabled: true}
|
||||
movie := model.Library{Name: "国漫", Path: BuildCloudLibraryPath("openlist", "/电影/国漫", "/电影/国漫"), Type: "movie", Enabled: true}
|
||||
for _, lib := range []*model.Library{&local, &cloud, &movie} {
|
||||
if err := repos.Library.Create(t.Context(), lib); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
filtered := FilterDisplayCloudLibraries(t.Context(), repos, []model.Library{local, cloud, movie})
|
||||
if got := libraryNames(filtered); !slices.Equal(got, []string{"国漫", "国漫"}) {
|
||||
t.Fatalf("filtered names = %#v, want local episodic plus separate movie library", got)
|
||||
}
|
||||
if filtered[0].ID != local.ID || filtered[1].ID != movie.ID {
|
||||
t.Fatalf("filtered libraries = %#v, want anime cloud merged into local tv but movie kept", filtered)
|
||||
}
|
||||
|
||||
merged := MergedLibraryIDs([]model.Library{local, cloud, movie}, local)
|
||||
if !slices.Equal(merged, []string{local.ID, cloud.ID}) {
|
||||
t.Fatalf("merged ids = %#v, want local tv + cloud anime only", merged)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterDisplayCloudLibrariesMergesCategoryNameAliases(t *testing.T) {
|
||||
db := newServiceTestDB(t, &model.Library{}, &model.Media{})
|
||||
repos := repository.New(db)
|
||||
foreignMovie := model.Library{Name: "外语电影", Path: "/media/电影/外语电影", Type: "movie", Enabled: true}
|
||||
westernMovie := model.Library{Name: "OpenList · 欧美电影", Path: BuildCloudLibraryPath("openlist", "/欧美电影", "/欧美电影"), Type: "movie", Enabled: true}
|
||||
eastAsianMovie := model.Library{Name: "OpenList · 日韩电影", Path: BuildCloudLibraryPath("openlist", "/日韩电影", "/日韩电影"), Type: "movie", Enabled: true}
|
||||
jpAnime := model.Library{Name: "日番", Path: "/media/动漫/日番", Type: "tv", Enabled: true}
|
||||
jpAnimeCloud := model.Library{Name: "OpenList · 日漫", Path: BuildCloudLibraryPath("openlist", "/日漫", "/日漫"), Type: "anime", Enabled: true}
|
||||
for _, lib := range []*model.Library{&foreignMovie, &westernMovie, &eastAsianMovie, &jpAnime, &jpAnimeCloud} {
|
||||
if err := repos.Library.Create(t.Context(), lib); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
filtered := FilterDisplayCloudLibraries(t.Context(), repos, []model.Library{foreignMovie, westernMovie, eastAsianMovie, jpAnime, jpAnimeCloud})
|
||||
if got := libraryNames(filtered); !slices.Equal(got, []string{"外语电影", "日番"}) {
|
||||
t.Fatalf("filtered names = %#v, want user-facing alias libraries only", got)
|
||||
}
|
||||
|
||||
movieMerged := MergedLibraryIDs([]model.Library{foreignMovie, westernMovie, eastAsianMovie, jpAnime, jpAnimeCloud}, foreignMovie)
|
||||
if !slices.Equal(movieMerged, []string{foreignMovie.ID, westernMovie.ID, eastAsianMovie.ID}) {
|
||||
t.Fatalf("movie merged ids = %#v, want foreign movie aliases", movieMerged)
|
||||
}
|
||||
animeMerged := MergedLibraryIDs([]model.Library{foreignMovie, westernMovie, eastAsianMovie, jpAnime, jpAnimeCloud}, jpAnime)
|
||||
if !slices.Equal(animeMerged, []string{jpAnime.ID, jpAnimeCloud.ID}) {
|
||||
t.Fatalf("anime merged ids = %#v, want jp anime aliases", animeMerged)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterDeprecatedNativeCloudLibrariesHidesPopulatedHistory(t *testing.T) {
|
||||
db := newServiceTestDB(t, &model.Library{}, &model.Media{})
|
||||
repos := repository.New(db)
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
)
|
||||
|
||||
func TestEmbyViewsMergeEpisodicCloudLibrariesIntoUserLibrary(t *testing.T) {
|
||||
svc := newTestEmbyService(t)
|
||||
local := model.Library{Name: "国漫", Path: "/media/动漫/国漫", Type: "tv", Enabled: true}
|
||||
cloud := model.Library{Name: "OpenList · 国漫", Path: BuildCloudLibraryPath("openlist", "/国漫", "/国漫"), Type: "anime", Enabled: true}
|
||||
for _, lib := range []*model.Library{&local, &cloud} {
|
||||
if err := svc.repo.Library.Create(t.Context(), lib); err != nil {
|
||||
t.Fatalf("create library: %v", err)
|
||||
}
|
||||
}
|
||||
if err := svc.repo.DB.Create(&model.Media{
|
||||
Base: model.Base{ID: "cloud-show-1"},
|
||||
LibraryID: cloud.ID,
|
||||
Title: "云盘国漫",
|
||||
Path: "cloud://openlist/国漫/云盘国漫/Season 01/云盘国漫.S01E01.mkv",
|
||||
SeasonNum: 1,
|
||||
EpisodeNum: 1,
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("create media: %v", err)
|
||||
}
|
||||
|
||||
views, err := svc.Views(t.Context(), "user-1")
|
||||
if err != nil {
|
||||
t.Fatalf("views: %v", err)
|
||||
}
|
||||
viewItems := views["Items"].([]map[string]any)
|
||||
if len(viewItems) != 1 {
|
||||
t.Fatalf("emby views = %#v, want one merged user-facing library", viewItems)
|
||||
}
|
||||
if viewItems[0]["Id"] != local.ID || viewItems[0]["Name"] != "国漫" {
|
||||
t.Fatalf("merged view should use local library identity, got %#v", viewItems[0])
|
||||
}
|
||||
|
||||
items, err := svc.Items(t.Context(), ItemsParams{ParentID: local.ID, Recursive: true, IncludeItemTypes: []string{"Episode"}, Limit: 50})
|
||||
if err != nil {
|
||||
t.Fatalf("items: %v", err)
|
||||
}
|
||||
episodes := items["Items"].([]map[string]any)
|
||||
if len(episodes) != 1 || episodes[0]["Id"] != "cloud-show-1" {
|
||||
t.Fatalf("merged local library should include cloud episodes, got %#v", episodes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbyViewsMergeCloudCategoryAliasesIntoUserLibrary(t *testing.T) {
|
||||
svc := newTestEmbyService(t)
|
||||
local := model.Library{Name: "日番", Path: "/media/动漫/日番", Type: "tv", Enabled: true}
|
||||
cloud := model.Library{Name: "OpenList · 日漫", Path: BuildCloudLibraryPath("openlist", "/日漫", "/日漫"), Type: "anime", Enabled: true}
|
||||
for _, lib := range []*model.Library{&local, &cloud} {
|
||||
if err := svc.repo.Library.Create(t.Context(), lib); err != nil {
|
||||
t.Fatalf("create library: %v", err)
|
||||
}
|
||||
}
|
||||
if err := svc.repo.DB.Create(&model.Media{
|
||||
Base: model.Base{ID: "cloud-anime-1"},
|
||||
LibraryID: cloud.ID,
|
||||
Title: "云盘日漫",
|
||||
Path: "cloud://openlist/日漫/云盘日漫/Season 01/云盘日漫.S01E01.mkv",
|
||||
SeasonNum: 1,
|
||||
EpisodeNum: 1,
|
||||
}).Error; err != nil {
|
||||
t.Fatalf("create media: %v", err)
|
||||
}
|
||||
|
||||
views, err := svc.Views(t.Context(), "user-1")
|
||||
if err != nil {
|
||||
t.Fatalf("views: %v", err)
|
||||
}
|
||||
viewItems := views["Items"].([]map[string]any)
|
||||
if len(viewItems) != 1 || viewItems[0]["Id"] != local.ID || viewItems[0]["Name"] != "日番" {
|
||||
t.Fatalf("emby views = %#v, want cloud alias merged into local 日番", viewItems)
|
||||
}
|
||||
|
||||
items, err := svc.Items(t.Context(), ItemsParams{ParentID: local.ID, Recursive: true, IncludeItemTypes: []string{"Episode"}, Limit: 50})
|
||||
if err != nil {
|
||||
t.Fatalf("items: %v", err)
|
||||
}
|
||||
episodes := items["Items"].([]map[string]any)
|
||||
if len(episodes) != 1 || episodes[0]["Id"] != "cloud-anime-1" {
|
||||
t.Fatalf("merged local 日番 library should include 日漫 cloud episodes, got %#v", episodes)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user