mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-07 05:46:38 +08:00
优化
This commit is contained in:
@@ -195,7 +195,8 @@ func listLibrarySeriesEpisodesHandler(svc *service.Container) gin.HandlerFunc {
|
|||||||
writeInternalOrCanceled(c, err)
|
writeInternalOrCanceled(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, gin.H{"items": items, "total": len(items)})
|
grouped := service.GroupEpisodeVersionsForDisplay(items)
|
||||||
|
c.JSON(http.StatusOK, gin.H{"items": grouped, "total": len(grouped)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,6 +236,7 @@ func listMediaEpisodesHandler(svc *service.Container) gin.HandlerFunc {
|
|||||||
writeInternalOrCanceled(c, err)
|
writeInternalOrCanceled(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, gin.H{"items": items, "total": len(items)})
|
grouped := service.GroupEpisodeVersionsForDisplay(items)
|
||||||
|
c.JSON(http.StatusOK, gin.H{"items": grouped, "total": len(grouped)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,25 @@ func GroupMediaVersions(items []model.Media) []MediaItem {
|
|||||||
return groupMediaVersions(items)
|
return groupMediaVersions(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupEpisodeVersionsForDisplay folds encoding/container variants into one
|
||||||
|
// episode while preserving season/episode ordering for episode-list APIs.
|
||||||
|
func GroupEpisodeVersionsForDisplay(items []model.Media) []MediaItem {
|
||||||
|
grouped := groupMediaVersions(items)
|
||||||
|
if grouped == nil {
|
||||||
|
return []MediaItem{}
|
||||||
|
}
|
||||||
|
sort.SliceStable(grouped, func(i, j int) bool {
|
||||||
|
if grouped[i].SeasonNum != grouped[j].SeasonNum {
|
||||||
|
return grouped[i].SeasonNum < grouped[j].SeasonNum
|
||||||
|
}
|
||||||
|
if grouped[i].EpisodeNum != grouped[j].EpisodeNum {
|
||||||
|
return grouped[i].EpisodeNum < grouped[j].EpisodeNum
|
||||||
|
}
|
||||||
|
return grouped[i].CreatedAt.Before(grouped[j].CreatedAt)
|
||||||
|
})
|
||||||
|
return grouped
|
||||||
|
}
|
||||||
|
|
||||||
func mediaVersionGroupKey(m model.Media) string {
|
func mediaVersionGroupKey(m model.Media) string {
|
||||||
// 远程 Emby 挂载条目保持独立,不与其它远程条目或本地条目折叠合并。
|
// 远程 Emby 挂载条目保持独立,不与其它远程条目或本地条目折叠合并。
|
||||||
if IsEmbyRemoteID(m.ID) {
|
if IsEmbyRemoteID(m.ID) {
|
||||||
|
|||||||
@@ -49,6 +49,28 @@ func TestGroupMediaVersionsMergesEpisodeByExternalIDAcrossLibraries(t *testing.T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGroupEpisodeVersionsForDisplayMergesAndKeepsEpisodeOrder(t *testing.T) {
|
||||||
|
rows := []model.Media{
|
||||||
|
{Base: model.Base{ID: "ep2"}, LibraryID: "tv", Title: "Show", SeasonNum: 1, EpisodeNum: 2, TMDbID: 99, Path: "/show/s01e02.mkv"},
|
||||||
|
{Base: model.Base{ID: "ep1-small"}, LibraryID: "tv", Title: "Show", SeasonNum: 1, EpisodeNum: 1, TMDbID: 99, Path: "/show/s01e01.mp4", SizeBytes: 100},
|
||||||
|
{Base: model.Base{ID: "ep1-large"}, LibraryID: "tv", Title: "Show", SeasonNum: 1, EpisodeNum: 1, TMDbID: 99, Path: "/show/s01e01.mkv", SizeBytes: 200},
|
||||||
|
}
|
||||||
|
|
||||||
|
grouped := GroupEpisodeVersionsForDisplay(rows)
|
||||||
|
if len(grouped) != 2 {
|
||||||
|
t.Fatalf("grouped len = %d, want 2: %#v", len(grouped), grouped)
|
||||||
|
}
|
||||||
|
if grouped[0].EpisodeNum != 1 || len(grouped[0].Versions) != 2 {
|
||||||
|
t.Fatalf("episode 1 was not merged first: %#v", grouped)
|
||||||
|
}
|
||||||
|
if grouped[0].ID != "ep1-large" {
|
||||||
|
t.Fatalf("primary version = %q, want ep1-large", grouped[0].ID)
|
||||||
|
}
|
||||||
|
if grouped[1].EpisodeNum != 2 {
|
||||||
|
t.Fatalf("second item episode = %d, want 2", grouped[1].EpisodeNum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGroupMediaVersionsMergesMovieEncodingVariants(t *testing.T) {
|
func TestGroupMediaVersionsMergesMovieEncodingVariants(t *testing.T) {
|
||||||
hd := model.Media{
|
hd := model.Media{
|
||||||
LibraryID: "movies",
|
LibraryID: "movies",
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export function LibrarySeriesEpisodes({
|
|||||||
<div className="grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
|
<div className="grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
|
||||||
{visibleEpisodes.map((ep) => {
|
{visibleEpisodes.map((ep) => {
|
||||||
const displayTitle = episodeDisplayTitle(ep, visibleEpisodes)
|
const displayTitle = episodeDisplayTitle(ep, visibleEpisodes)
|
||||||
|
const versionCount = ep.versions?.length ?? 1
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={ep.id}
|
key={ep.id}
|
||||||
@@ -102,6 +103,7 @@ export function LibrarySeriesEpisodes({
|
|||||||
{ep.duration_sec > 0
|
{ep.duration_sec > 0
|
||||||
? `${Math.floor(ep.duration_sec / 60)} 分钟`
|
? `${Math.floor(ep.duration_sec / 60)} 分钟`
|
||||||
: formatSize(ep.size_bytes)}
|
: formatSize(ep.size_bytes)}
|
||||||
|
{versionCount > 1 ? ` · ${versionCount} 版本` : ''}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
Reference in New Issue
Block a user