From 7425c3d57befc023a52a97ec64c6bd7825d0dbc4 Mon Sep 17 00:00:00 2001 From: truewhile <62226914+truewhile@users.noreply.github.com> Date: Fri, 28 Aug 2026 22:38:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/handler/media.go | 8 ++++- internal/service/media_library.go | 9 ++++- web/src/api/library.ts | 3 +- web/src/pages/HomePage.tsx | 60 ++++++++----------------------- 4 files changed, 32 insertions(+), 48 deletions(-) diff --git a/internal/handler/media.go b/internal/handler/media.go index 676c7ef..12bdec7 100644 --- a/internal/handler/media.go +++ b/internal/handler/media.go @@ -47,7 +47,13 @@ func listLibrariesHandler(svc *service.Container) gin.HandlerFunc { } withPreview := c.Query("with_preview") == "1" || c.Query("with_preview") == "true" if withPreview { - previews, err := svc.Media.ListLibrariesWithPreview(c.Request.Context(), libs, mediaVisibilityForRequest(c, svc), 10) + limit, _ := strconv.Atoi(c.DefaultQuery("preview_limit", c.DefaultQuery("limit", "10"))) + if limit <= 0 { + limit = 10 + } else if limit > 100 { + limit = 100 + } + previews, err := svc.Media.ListLibrariesWithPreview(c.Request.Context(), libs, mediaVisibilityForRequest(c, svc), limit) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return diff --git a/internal/service/media_library.go b/internal/service/media_library.go index 21e1ed3..fd7a23e 100644 --- a/internal/service/media_library.go +++ b/internal/service/media_library.go @@ -57,11 +57,18 @@ func (s *MediaService) ListLibrariesWithPreview(ctx context.Context, libraries [ } } + fetchCount := cardLimit * 4 + if fetchCount < 60 { + fetchCount = 60 + } else if fetchCount > 200 { + fetchCount = 200 + } + for i := range out { if out[i].Total == 0 { continue } - items, _, err := s.repo.Media.ListByLibrariesFiltered(ctx, []string{out[i].ID}, 0, 60, filter) + items, _, err := s.repo.Media.ListByLibrariesFiltered(ctx, []string{out[i].ID}, 0, fetchCount, filter) if err != nil { continue } diff --git a/web/src/api/library.ts b/web/src/api/library.ts index dc97634..18a6056 100644 --- a/web/src/api/library.ts +++ b/web/src/api/library.ts @@ -87,12 +87,13 @@ export interface LibraryWithPreview extends Library { } export const libraryAPI = { - list: (options?: { includeHidden?: boolean; withPreview?: boolean }) => + list: (options?: { includeHidden?: boolean; withPreview?: boolean; previewLimit?: number }) => api .get('/libraries', { params: { ...(options?.includeHidden ? { include_hidden: 1 } : {}), ...(options?.withPreview ? { with_preview: 1 } : {}), + ...(options?.previewLimit ? { preview_limit: options.previewLimit } : {}), }, }) .then((r) => r.data), diff --git a/web/src/pages/HomePage.tsx b/web/src/pages/HomePage.tsx index 011b89b..b517c0d 100644 --- a/web/src/pages/HomePage.tsx +++ b/web/src/pages/HomePage.tsx @@ -1,9 +1,9 @@ import { useEffect, useMemo, useState } from 'react' -import { libraryAPI } from '../api/library' +import { libraryAPI, type LibraryWithPreview } from '../api/library' import { playbackAPI, type HistoryItem } from '../api/playback' import type { Library, Media } from '../types' -import { groupSeries, type SeriesCard } from '../utils/groupSeries' +import type { SeriesCard } from '../utils/groupSeries' import { ContinueWatchingSection, HomeCarouselSection, @@ -29,56 +29,26 @@ export function HomePage() { setLoading(true) try { const [libs, hist] = await Promise.all([ - libraryAPI.list().then((rows) => asArray(rows)).catch(() => [] as Library[]), - playbackAPI.recentHistory().then((rows) => asArray(rows)).catch(() => [] as HistoryItem[]), + libraryAPI + .list({ withPreview: true, previewLimit: 20 }) + .then((rows) => asArray(rows)) + .catch(() => [] as LibraryWithPreview[]), + playbackAPI + .recentHistory() + .then((rows) => asArray(rows)) + .catch(() => [] as HistoryItem[]), ]) if (cancelled) return setLibraries(libs) setHistory(hist.filter((h) => h && !h.completed && !!h.media)) - // Fetch media items for all libraries in parallel - const isSeriesType = (type?: string) => type === 'tv' || type === 'anime' || type === 'variety' - const results = await Promise.allSettled( - libs.map(async (lib) => { - // 剧集类媒体库(tv/anime/variety):后端 /series 已按剧聚合, - // 首页若用 episode 级 /media 的前 30 行再 groupSeries,同一部剧的 - // 多集会折叠成 1 张卡,导致整行只显示 1 个条目。 - // 改用 /series 分页拉取全部聚合后的剧集卡片。 - if (isSeriesType(lib.type)) { - const cards: SeriesCard[] = [] - let total = 0 - const pageSize = 200 - for (let page = 1; page <= 10; page++) { - const data = await libraryAPI.listSeries(lib.id, page, pageSize) - const pageItems = asArray(data?.items) - cards.push(...pageItems) - total = data?.total ?? cards.length - if (cards.length >= total || pageItems.length < pageSize) break - } - return { id: lib.id, cards, items: [], total } - } - const page = await libraryAPI.listMedia(lib.id, 1, 30) - const items = asArray(page?.items) - const cards = groupSeries(items) - return { - id: lib.id, - cards, - items, - total: page?.total ?? items.length, - } - }), - ) - - if (cancelled) return const mapData: Record = {} - for (const res of results) { - if (res.status === 'fulfilled' && res.value) { - mapData[res.value.id] = { - cards: res.value.cards, - items: res.value.items, - total: res.value.total, - } + for (const lib of libs) { + mapData[lib.id] = { + cards: lib.cards ?? [], + items: [], + total: lib.total ?? 0, } } setLibraryData(mapData)