Files
MeBox/web/src/pages/LibrarySeriesDetailSection.tsx
T
truewhile a79bbb80a8 Remove unused recycle bin and add optional local file delete (#26)
Soft-delete restore/purge/list and the recycle_purge job are gone.
Admin delete now removes library index rows, with an optional
delete_files query that also deletes local media + sidecar NFO.
UI copy is renamed from 移入回收站 to 删除, with a confirm checkbox.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: truewhile <truewhile@users.noreply.github.com>
2026-09-03 14:12:52 +08:00

136 lines
3.4 KiB
TypeScript

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
canFavorite: boolean
favourite: boolean
favouriteBusy: boolean
onToggleFavourite: () => void
seriesToolBusy: string
onBack: () => void
onSmartScrape: () => void
onManualScrape: () => void
onMetadataEdit: () => void
onProbe: () => void
onNFO: () => void
onOrganize: () => void
onDelete: () => void
onSeasonChange: (season: number) => void
}
export function LibrarySeriesDetailSection({
selectedSeries,
selectedEpisodes,
selectedSeason,
visibleEpisodes,
allEpisodes,
loadingEpisodes,
playbackFrom,
isAdmin,
canFavorite,
favourite,
favouriteBusy,
onToggleFavourite,
seriesToolBusy,
onBack,
onSmartScrape,
onManualScrape,
onMetadataEdit,
onProbe,
onNFO,
onOrganize,
onDelete,
onSeasonChange,
}: LibrarySeriesDetailSectionProps) {
return (
<AnimatePresence mode="wait">
{selectedSeries && (
<motion.div
initial={{ opacity: 0, y: 16 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
className="space-y-6"
>
<LibrarySeriesDetailHeader
series={selectedSeries}
visibleEpisodes={visibleEpisodes}
allEpisodes={allEpisodes}
playbackFrom={playbackFrom}
isAdmin={isAdmin}
canFavorite={canFavorite}
favourite={favourite}
favouriteBusy={favouriteBusy}
onToggleFavourite={onToggleFavourite}
seriesToolBusy={seriesToolBusy}
onBack={onBack}
onSmartScrape={onSmartScrape}
onManualScrape={onManualScrape}
onMetadataEdit={onMetadataEdit}
onProbe={onProbe}
onNFO={onNFO}
onOrganize={onOrganize}
onDelete={onDelete}
/>
<LibrarySeriesEpisodesPanel
loading={loadingEpisodes}
selectedEpisodes={selectedEpisodes}
selectedSeason={selectedSeason}
visibleEpisodes={visibleEpisodes}
playbackFrom={playbackFrom}
onSeasonChange={onSeasonChange}
/>
</motion.div>
)}
</AnimatePresence>
)
}
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 (
<div className="space-y-6">
<LibrarySeriesEpisodes
loading={loading}
selectedEpisodes={selectedEpisodes}
selectedSeason={selectedSeason}
visibleEpisodes={visibleEpisodes}
playbackFrom={playbackFrom}
onSeasonChange={onSeasonChange}
/>
</div>
)
}