diff --git a/web/src/pages/LibraryPage.tsx b/web/src/pages/LibraryPage.tsx index 8c71649..4d631c3 100644 --- a/web/src/pages/LibraryPage.tsx +++ b/web/src/pages/LibraryPage.tsx @@ -1,16 +1,14 @@ import { useState } from 'react' import { useLocation, useParams, useSearchParams } from 'react-router-dom' -import { motion, AnimatePresence } from 'framer-motion' +import { motion } from 'framer-motion' import type { Media } from '../types' import { useAuthStore } from '../stores/auth' -import { seriesTitle, type SeriesCard } from '../utils/groupSeries' -import { ManualScrapeDialog } from '../components/ManualScrapeDialog' -import { MetadataEditDialog } from '../components/MetadataEditDialog' -import { LibrarySeriesEpisodes } from './LibrarySeriesEpisodes' -import { LibrarySeriesDetailHeader } from './LibrarySeriesDetailHeader' +import type { SeriesCard } from '../utils/groupSeries' +import { LibraryPageDialogs } from './LibraryPageDialogs' import { LibraryPageHeader } from './LibraryPageHeader' import { LibraryMediaSections } from './LibraryMediaSections' +import { LibrarySeriesDetailSection } from './LibrarySeriesDetailSection' import { useLibraryData } from './useLibraryData' import { useLibraryScanStatus } from './useLibraryScanStatus' import { useLibrarySeriesSelection } from './useLibrarySeriesSelection' @@ -141,84 +139,40 @@ export function LibraryPage() { onSeriesClick={handleSeriesClick} /> - {/* 剧集详情:季/集选择器 */} - - {selectedSeries && ( - - setManualSeriesScrapeOpen(true)} - onMetadataEdit={() => setSeriesMetadataEditOpen(true)} - onProbe={handleSeriesProbe} - onNFO={handleSeriesNFO} - onOrganize={handleSeriesOrganize} - onSoftDelete={handleSeriesSoftDelete} - /> - - {/* 季 / 集列表 */} -
- -
-
- )} -
- - setManualSeriesScrapeOpen(false)} - onApplied={reloadCurrentLibrary} + setManualSeriesScrapeOpen(true)} + onMetadataEdit={() => setSeriesMetadataEditOpen(true)} + onProbe={handleSeriesProbe} + onNFO={handleSeriesNFO} + onOrganize={handleSeriesOrganize} + onSoftDelete={handleSeriesSoftDelete} + onSeasonChange={setSelectedSeason} /> - setSeriesMetadataEditOpen(false)} - onSaved={reloadCurrentLibrary} - /> - setManualMovie(null)} + + setManualSeriesScrapeOpen(false)} + onCloseSeriesMetadataEdit={() => setSeriesMetadataEditOpen(false)} + onCloseManualMovie={() => setManualMovie(null)} onApplied={reloadCurrentLibrary} /> ) } - -function scrapeMediaType(libraryType: string | undefined, media: Media): string { - if ((media.season_num ?? 0) > 0 || (media.episode_num ?? 0) > 0) { - return 'tv' - } - return libraryType || 'movie' -} diff --git a/web/src/pages/LibraryPageDialogs.tsx b/web/src/pages/LibraryPageDialogs.tsx new file mode 100644 index 0000000..7fef288 --- /dev/null +++ b/web/src/pages/LibraryPageDialogs.tsx @@ -0,0 +1,76 @@ +import { ManualScrapeDialog } from '../components/ManualScrapeDialog' +import { MetadataEditDialog } from '../components/MetadataEditDialog' +import type { Media } from '../types' +import { seriesTitle, type SeriesCard } from '../utils/groupSeries' + +type LibraryPageDialogsProps = { + manualSeriesScrapeOpen: boolean + seriesMetadataEditOpen: boolean + manualMovie: Media | null + selectedSeries: SeriesCard | null + selectedSeriesMediaIDs: string[] + libraryType?: string + scrapeEpisodeArtwork: boolean + onCloseManualSeriesScrape: () => void + onCloseSeriesMetadataEdit: () => void + onCloseManualMovie: () => void + onApplied: () => void +} + +export function LibraryPageDialogs({ + manualSeriesScrapeOpen, + seriesMetadataEditOpen, + manualMovie, + selectedSeries, + selectedSeriesMediaIDs, + libraryType, + scrapeEpisodeArtwork, + onCloseManualSeriesScrape, + onCloseSeriesMetadataEdit, + onCloseManualMovie, + onApplied, +}: LibraryPageDialogsProps) { + const selectedSeriesTitle = selectedSeries ? seriesTitle(selectedSeries.rep) : '' + + return ( + <> + + + + + ) +} + +function scrapeMediaType(libraryType: string | undefined, media: Media): string { + if ((media.season_num ?? 0) > 0 || (media.episode_num ?? 0) > 0) { + return 'tv' + } + return libraryType || 'movie' +} diff --git a/web/src/pages/LibrarySeriesDetailSection.tsx b/web/src/pages/LibrarySeriesDetailSection.tsx new file mode 100644 index 0000000..3dd1966 --- /dev/null +++ b/web/src/pages/LibrarySeriesDetailSection.tsx @@ -0,0 +1,123 @@ +import { AnimatePresence, motion } from 'framer-motion' + +import type { Media } from '../types' +import type { SeriesCard } from '../utils/groupSeries' +import { LibrarySeriesDetailHeader } from './LibrarySeriesDetailHeader' +import { LibrarySeriesEpisodes } from './LibrarySeriesEpisodes' + +type SeasonEpisodes = { + season: number + episodes: Media[] +} + +type LibrarySeriesDetailSectionProps = { + selectedSeries: SeriesCard | null + selectedEpisodes: SeasonEpisodes[] + selectedSeason: number | null + visibleEpisodes: Media[] + allEpisodes: Media[] + loadingEpisodes: boolean + playbackFrom: string + isAdmin: boolean + seriesToolBusy: string + onBack: () => void + onSmartScrape: () => void + onManualScrape: () => void + onMetadataEdit: () => void + onProbe: () => void + onNFO: () => void + onOrganize: () => void + onSoftDelete: () => void + onSeasonChange: (season: number) => void +} + +export function LibrarySeriesDetailSection({ + selectedSeries, + selectedEpisodes, + selectedSeason, + visibleEpisodes, + allEpisodes, + loadingEpisodes, + playbackFrom, + isAdmin, + seriesToolBusy, + onBack, + onSmartScrape, + onManualScrape, + onMetadataEdit, + onProbe, + onNFO, + onOrganize, + onSoftDelete, + onSeasonChange, +}: LibrarySeriesDetailSectionProps) { + return ( + + {selectedSeries && ( + + + + + + )} + + ) +} + +type LibrarySeriesEpisodesPanelProps = { + loading: boolean + selectedEpisodes: SeasonEpisodes[] + selectedSeason: number | null + visibleEpisodes: Media[] + playbackFrom: string + onSeasonChange: (season: number) => void +} + +function LibrarySeriesEpisodesPanel({ + loading, + selectedEpisodes, + selectedSeason, + visibleEpisodes, + playbackFrom, + onSeasonChange, +}: LibrarySeriesEpisodesPanelProps) { + return ( +
+ +
+ ) +}