diff --git a/src/backend/metadata/tmdb.ts b/src/backend/metadata/tmdb.ts index 28c716d9..a265b051 100644 --- a/src/backend/metadata/tmdb.ts +++ b/src/backend/metadata/tmdb.ts @@ -91,14 +91,28 @@ export function formatTMDBMeta( export function formatTMDBMetaToMediaItem(media: TMDBMediaResult): MediaItem { const type = TMDBMediaToMediaItemType(media.object_type); - return { + // Define the basic structure of MediaItem + const mediaItem: MediaItem = { title: media.title, id: media.id.toString(), year: media.original_release_date?.getFullYear() ?? 0, release_date: media.original_release_date, poster: media.poster, type, + seasons: undefined, }; + + // If it's a TV show, include the seasons information + if (type === "show") { + const seasons = media.seasons?.map((season) => ({ + title: season.title, + id: season.id.toString(), + number: season.season_number, + })); + mediaItem.seasons = seasons as MWSeasonMeta[]; + } + + return mediaItem; } export function TMDBIdToUrlId( diff --git a/src/components/media/ModalEpisodeSelector.tsx b/src/components/media/ModalEpisodeSelector.tsx index e19b6556..a5e5c727 100644 --- a/src/components/media/ModalEpisodeSelector.tsx +++ b/src/components/media/ModalEpisodeSelector.tsx @@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { get } from "@/backend/metadata/tmdb"; +import { Flare } from "@/components/utils/Flare"; import { conf } from "@/setup/config"; interface ModalEpisodeSelectorProps { @@ -57,8 +58,8 @@ export function EpisodeSelector({ }, [handleSeasonSelect, tmdbId]); return ( -
-
+
+
{seasonsData.map((season) => (
))}
-
-
+
+
{selectedSeason ? ( selectedSeason.episodes.map( (episode: { @@ -87,23 +88,31 @@ export function EpisodeSelector({ show_id: number; id: number; }) => ( -
navigate( `/media/tmdb-tv-${tmdbId}-${mediaTitle}/${episode.show_id}/${episode.id}`, ) } - className="bg-mediaCard-hoverBackground rounded p-2 hover:scale-95 transition-transform transition-border-color duration-[0.28s] ease-in-out transform-origin-center" + className="group cursor-pointer rounded-xl relative p-[0.65em] bg-background-main transition-colors duration-[0.28s] flex-shrink-0 w-48 sm:w-auto mr-2 sm:mr-0" > - -

- {episode.name} -

-
+
+ +

+ {episode.name} +

+
+ ), ) ) : ( diff --git a/src/components/media/PopupModal.tsx b/src/components/media/PopupModal.tsx index 3274c31d..a9d9bc1b 100644 --- a/src/components/media/PopupModal.tsx +++ b/src/components/media/PopupModal.tsx @@ -20,6 +20,29 @@ interface PopupModalProps { media: MediaItem; } +interface MediaData { + backdrop_path?: string; + title?: string; + name?: string; + runtime?: number; + release_date?: string; + first_air_date?: string; + vote_average?: number; + genres?: Array<{ name: string }>; + overview?: string; +} + +interface MediaInfo { + results?: Array<{ + iso_3166_1: string; + rating?: string; + release_dates?: Array<{ + certification: string; + release_date: string; + }>; + }>; +} + type StyleState = { opacity: number; visibility: "visible" | "hidden" | undefined; @@ -46,11 +69,10 @@ export function PopupModal({ opacity: 0, visibility: "hidden", }); - const [data, setData] = useState(null); - const [mediaInfo, setMediaInfo] = useState(null); + const [data, setData] = useState(null); + const [mediaInfo, setMediaInfo] = useState(null); const [error, setError] = useState(null); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [menuOpen, setMenuOpen] = useState(false); // Added definition for menuOpen + // const [menuOpen, setMenuOpen] = useState(false); const navigate = useNavigate(); useEffect(() => { @@ -62,7 +84,6 @@ export function PopupModal({ onClose(); } } - document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); @@ -83,7 +104,7 @@ export function PopupModal({ try { const mediaTypePath = media.type === "show" ? "tv" : media.type; - const result = await get(`/${mediaTypePath}/${media.id}`, { + const result = await get(`/${mediaTypePath}/${media.id}`, { api_key: conf().TMDB_READ_API_KEY, language: "en-US", }); @@ -107,7 +128,7 @@ export function PopupModal({ const mediaTypeForAPI = media.type === "show" ? "tv" : media.type; const endpointSuffix = media.type === "show" ? "content_ratings" : "release_dates"; - const result = await get( + const result = await get( `/${mediaTypeForAPI}/${media.id}/${endpointSuffix}`, { api_key: conf().TMDB_READ_API_KEY, @@ -126,10 +147,7 @@ export function PopupModal({ }, [media.id, media.type, isVisible]); if (!isVisible && style.visibility === "hidden") return null; - - if (error) { - return
Error: {error}
; - } + if (error) return
Error: {error}
; const isTVShow = media.type === "show"; const usReleaseInfo = mediaInfo?.results?.find( @@ -158,11 +176,7 @@ export function PopupModal({
@@ -172,9 +186,7 @@ export function PopupModal({ alt={media.poster ? "" : "failed to fetch :("} className="rounded-xl object-cover w-full h-full" loading="lazy" - style={{ - maxHeight: "60vh", - }} + style={{ maxHeight: "60vh" }} /> ) : ( @@ -239,19 +251,17 @@ export function PopupModal({
- {Array.from({ length: 5 }, (_, index) => { - return ( - - {index < Math.round(Number(data?.vote_average) / 2) ? ( - - ) : ( - - )} - - ); - })} + {Array.from({ length: 5 }, (_, index) => ( + + {index < Math.round(Number(data?.vote_average) / 2) ? ( + + ) : ( + + )} + + ))}
- {data?.genres?.length > 0 + {data?.genres && data.genres.length > 0 ? data.genres.map((genre: { name: string }) => (
@@ -259,8 +269,9 @@ export function PopupModal({
)) - : Array.from({ length: 3 }).map((_) => ( -
+ : Array.from({ length: 3 }).map((_, idx) => ( + // eslint-disable-next-line react/no-array-index-key +
))} diff --git a/src/components/player/atoms/Episodes.tsx b/src/components/player/atoms/Episodes.tsx index fa36a6e9..e5422c17 100644 --- a/src/components/player/atoms/Episodes.tsx +++ b/src/components/player/atoms/Episodes.tsx @@ -118,8 +118,6 @@ function EpisodesView({ const newData = setPlayerMeta(loadingState.value.fullData, episodeId); if (newData) onChange?.(newData); } - // prevent router clear here, otherwise its done double - // player already switches route after meta change router.close(true); }, [setPlayerMeta, loadingState, router, onChange], diff --git a/src/setup/App.tsx b/src/setup/App.tsx index 97983c7b..322d6658 100644 --- a/src/setup/App.tsx +++ b/src/setup/App.tsx @@ -134,6 +134,7 @@ function App() { } /> + } /> } /> } /> diff --git a/src/utils/mediaTypes.ts b/src/utils/mediaTypes.ts index c81b1ac0..3a7e2d44 100644 --- a/src/utils/mediaTypes.ts +++ b/src/utils/mediaTypes.ts @@ -1,4 +1,5 @@ export interface MediaItem { + seasons: import("c:/Users/huzei/OneDrive/Desktop/Sudo-Flix/src/backend/metadata/types/mw").MWSeasonMeta[]; id: string; title: string; year?: number;