添加新功能,完善项目

This commit is contained in:
truewhile
2026-09-22 16:22:29 +08:00
parent 47899284a5
commit b5ce4646cf
85 changed files with 7103 additions and 982 deletions
+132
View File
@@ -1,6 +1,8 @@
package service
import (
"context"
"strings"
"testing"
"time"
@@ -65,3 +67,133 @@ func TestEmbyLatestItemsOrderByReleaseDate(t *testing.T) {
t.Fatalf("latest item should expose PremiereDate for Emby clients: %#v", items[0])
}
}
// SimilarItems with a real series_id (not a media table row ID) must return
// results instead of an empty list. Before bug-2 fix, Media.FindByID returned
// nil for any ID that wasn't a primary-key match in the media table (including
// series_id values and virtual msgo-series-* IDs), so SimilarItems always
// returned empty for series detail pages.
func TestEmbyServiceSimilarItemsSeriesID(t *testing.T) {
svc := newTestEmbyService(t)
svc.SetDiscovery(NewMediaDiscoveryService(zap.NewNop(), svc.repo))
lib := model.Library{Name: "TV", Path: "/media/tv", Type: "tv", Enabled: true}
if err := svc.repo.Library.Create(context.Background(), &lib); err != nil {
t.Fatal(err)
}
// Two series with the same genre so they score > 0 for similarity.
ep1 := model.Media{
LibraryID: lib.ID,
SeriesID: "real-series-1",
Title: "剧一",
Genres: "Action",
SeasonNum: 1,
EpisodeNum: 1,
Path: "/media/tv/s1e1.mkv",
}
ep2 := model.Media{
LibraryID: lib.ID,
SeriesID: "real-series-2",
Title: "剧二",
Genres: "Action",
SeasonNum: 1,
EpisodeNum: 1,
Path: "/media/tv/s2e1.mkv",
}
for _, m := range []*model.Media{&ep1, &ep2} {
if err := svc.repo.DB.Create(m).Error; err != nil {
t.Fatal(err)
}
}
// "real-series-1" is the series_id stored in the media row but is NOT a
// primary key in the media table, so Media.FindByID("real-series-1") returns
// nil. SimilarItems must fall back to findSeriesGroup and still return
// results.
result, err := svc.SimilarItems(context.Background(), "real-series-1", "", 12)
if err != nil {
t.Fatalf("SimilarItems with series_id: %v", err)
}
similar, _ := result["Items"].([]map[string]any)
if similar == nil {
t.Fatal("SimilarItems returned nil items for a series_id that resolves via findSeriesGroup")
}
// Should contain 剧二 (the only other episodic content with the same genre).
found := false
for _, item := range similar {
if name, _ := item["Name"].(string); strings.Contains(name, "剧二") || strings.Contains(name, "第 1 集") {
found = true
break
}
}
if !found && len(similar) == 0 {
t.Fatalf("SimilarItems returned no results; want at least 剧二 for series real-series-1")
}
}
// SimilarItems with a virtual series ID (msgo-series-*) must also work.
// Virtual IDs are generated for episodes that have no series_id set.
func TestEmbyServiceSimilarItemsVirtualSeriesID(t *testing.T) {
svc := newTestEmbyService(t)
svc.SetDiscovery(NewMediaDiscoveryService(zap.NewNop(), svc.repo))
lib := model.Library{Name: "TV2", Path: "/media/tv2", Type: "tv", Enabled: true}
if err := svc.repo.Library.Create(context.Background(), &lib); err != nil {
t.Fatal(err)
}
// Episodes WITHOUT SeriesID → series group gets a virtual msgo-series-* ID.
ep1 := model.Media{
LibraryID: lib.ID,
Title: "虚拟剧一",
Genres: "Drama",
SeasonNum: 1,
EpisodeNum: 1,
Path: "/media/tv2/virtual1/S01E01.mkv",
}
ep2 := model.Media{
LibraryID: lib.ID,
Title: "虚拟剧二",
Genres: "Drama",
SeasonNum: 1,
EpisodeNum: 1,
Path: "/media/tv2/virtual2/S01E01.mkv",
}
for _, m := range []*model.Media{&ep1, &ep2} {
if err := svc.repo.DB.Create(m).Error; err != nil {
t.Fatal(err)
}
}
// Fetch series items to get the virtual ID for ep1's series.
seriesItems, err := svc.Items(context.Background(), ItemsParams{
IncludeItemTypes: []string{"Series"},
Recursive: true,
})
if err != nil {
t.Fatal(err)
}
items, _ := seriesItems["Items"].([]map[string]any)
var virtualID string
for _, item := range items {
id, _ := item["Id"].(string)
name, _ := item["Name"].(string)
if strings.Contains(name, "虚拟剧一") && strings.HasPrefix(id, embyVirtualSeriesPrefix) {
virtualID = id
break
}
}
if virtualID == "" {
t.Skip("virtual series ID not generated for episodes without series_id in this build")
}
result, err := svc.SimilarItems(context.Background(), virtualID, "", 12)
if err != nil {
t.Fatalf("SimilarItems with virtual series ID: %v", err)
}
similar, _ := result["Items"].([]map[string]any)
if similar == nil {
t.Fatalf("SimilarItems returned nil items for virtual series ID %q", virtualID)
}
}