diff --git a/src/hooks/series/useNextEpisode.ts b/src/hooks/series/useNextEpisode.ts index 0b0ea4dea..60fda9e5e 100644 --- a/src/hooks/series/useNextEpisode.ts +++ b/src/hooks/series/useNextEpisode.ts @@ -1,26 +1,18 @@ import { useQuery } from 'react-query'; -import type { EpisodeMetadata, Series } from '#types/series'; -import { getNextItem } from '#src/utils/series'; +import type { Series } from '#types/series'; import { SERIES_CACHE_TIME } from '#src/config'; +import { getEpisodes } from '#src/services/api.service'; -export const useNextEpisode = ({ - series, - episodeMetadata, - episodeId, -}: { - series: Series | undefined; - episodeMetadata: EpisodeMetadata | undefined; - episodeId: string | null; -}) => { +export const useNextEpisode = ({ series, episodeId }: { series: Series | undefined; episodeId: string | null }) => { const { isLoading, data } = useQuery( ['next-episode', series?.series_id, episodeId], async () => { - const item = await getNextItem(series, episodeMetadata); + const item = await getEpisodes(series?.series_id, null, 1, episodeId); - return item; + return item?.episodes?.[0]; }, - { staleTime: SERIES_CACHE_TIME, cacheTime: SERIES_CACHE_TIME, enabled: !!(series?.series_id && episodeId && episodeMetadata) }, + { staleTime: SERIES_CACHE_TIME, cacheTime: SERIES_CACHE_TIME, enabled: !!(series?.series_id && episodeId) }, ); return { diff --git a/src/pages/ScreenRouting/mediaScreens/MediaSeries/MediaSeries.tsx b/src/pages/ScreenRouting/mediaScreens/MediaSeries/MediaSeries.tsx index 06950d161..2011bd932 100644 --- a/src/pages/ScreenRouting/mediaScreens/MediaSeries/MediaSeries.tsx +++ b/src/pages/ScreenRouting/mediaScreens/MediaSeries/MediaSeries.tsx @@ -91,7 +91,7 @@ const MediaSeries: ScreenComponent = ({ data: seriesMedia }) => { [seriesMedia, series, episodes], ); const episodesInSeason = getEpisodesInSeason(episodeMetadata, series); - const { data: nextItem } = useNextEpisode({ series, episodeMetadata, episodeId: episode?.mediaid || firstEpisode?.mediaid }); + const { data: nextItem } = useNextEpisode({ series, episodeId: episode?.mediaid || firstEpisode?.mediaid }); // Watch history const watchHistoryArray = useWatchHistoryStore((state) => state.watchHistory); diff --git a/src/services/api.service.ts b/src/services/api.service.ts index fc7fd2e16..6de762543 100644 --- a/src/services/api.service.ts +++ b/src/services/api.service.ts @@ -149,13 +149,20 @@ export const getSeriesByMediaIds = async (mediaIds: string[]): Promise<{ [mediaI * Get all episodes of the selected series (when no particular season is selected or when episodes are attached to series) * @param {string} seriesId */ -export const getEpisodes = async (seriesId: string | undefined, pageOffset: number, pageLimit?: number): Promise => { +export const getEpisodes = async ( + seriesId: string | undefined | null, + pageOffset: number | null, + pageLimit: number | null = PAGE_LIMIT, + afterId?: string | null, +): Promise => { if (!seriesId) { throw new Error('Series ID is required'); + } else if (pageOffset && afterId) { + throw new Error('page_offset and after_id are not allowed in the same query'); } const pathname = `/apps/series/${seriesId}/episodes`; - const url = addQueryParams(`${import.meta.env.APP_API_BASE_URL}${pathname}`, { page_offset: pageOffset, page_limit: pageLimit || PAGE_LIMIT }); + const url = addQueryParams(`${import.meta.env.APP_API_BASE_URL}${pathname}`, { page_offset: pageOffset, page_limit: pageLimit, after_id: afterId }); const response = await fetch(url); const { episodes, page, page_limit, total }: EpisodesRes = await getDataOrThrow(response); diff --git a/src/utils/series.ts b/src/utils/series.ts index 2221610b8..a3687aacd 100644 --- a/src/utils/series.ts +++ b/src/utils/series.ts @@ -1,5 +1,4 @@ import type { EpisodeMetadata, Series } from '#types/series'; -import { getEpisodes, getSeasonWithEpisodes } from '#src/services/api.service'; /** * Get an array of options for a season filter @@ -10,74 +9,6 @@ export const getFiltersFromSeries = (series: Series | undefined): { label: strin : []; }; -/** - * Retrieve a first episode of the next season - */ -const getNextSeasonEpisode = async (seasonNumber: number, series: Series | undefined) => { - const seasons = series?.seasons; - - // The seasons is the last one in case there is only one season available or it is the same as the last season in the seasons array - const isLastSeason = seasons?.length === 1 || seasons?.[seasons?.length - 1]?.season_number === seasonNumber; - - if (isLastSeason) { - return; - } else { - // Need to know the order of seasons to choose the next season number - const hasAscendingOrder = (Number(seasons?.[1]?.season_number) || 0) > (Number(seasons?.[0]?.season_number) || 0); - const nextSeasonNumber = hasAscendingOrder ? seasonNumber + 1 : seasonNumber - 1; - - return (await getSeasonWithEpisodes(series?.series_id, nextSeasonNumber, 0, 1))?.episodes?.[0]; - } -}; - -/** - * Get a next episode of the selected season / episodes list - */ -const getNextEpisode = async (seasonNumber: number, seriesId: string, pageWithEpisode: number) => { - if (seasonNumber) { - return (await getSeasonWithEpisodes(seriesId, seasonNumber, pageWithEpisode, 1))?.episodes?.[0]; - } else { - return (await getEpisodes(seriesId, pageWithEpisode, 1))?.episodes?.[0]; - } -}; - -export const getNextItem = async (series: Series | undefined, episodeMetadata: EpisodeMetadata | undefined) => { - if (!episodeMetadata || !series) { - return; - } - - const seasonNumber = Number(episodeMetadata.seasonNumber); - const episodeNumber = Number(episodeMetadata.episodeNumber); - - // Get initial data to collect information about total number of elements - const { episodes, pagination } = - seasonNumber !== 0 ? await getSeasonWithEpisodes(series?.series_id, seasonNumber, 0) : await getEpisodes(series?.series_id, 0); - - if (episodes.length === 1 && seasonNumber) { - return getNextSeasonEpisode(seasonNumber, series); - } - - // Both episodes and seasons can be sorted by asc / desc - const hasAscendingOrder = (Number(episodes[1].episodeNumber) || 0) > (Number(episodes[0].episodeNumber) || 0); - const nextEpisodeNumber = hasAscendingOrder ? episodeNumber + 1 : episodeNumber - 1; - // First page has 0 number, that is why we use Math.floor here und subtract 1 - const pageWithEpisode = Math.floor(hasAscendingOrder ? nextEpisodeNumber - 1 : pagination.total - nextEpisodeNumber - 1); - // Consider the case when we have a next episode in the retrieved list - const nextElementIndex = episodes.findIndex((el) => Number(el.episodeNumber) === nextEpisodeNumber); - - if (nextElementIndex !== -1) { - return episodes[nextElementIndex]; - } - - // Fetch the next episodes of the season when there is more to fetch - if (pageWithEpisode < pagination.total) { - return getNextEpisode(seasonNumber, series?.series_id, pageWithEpisode); - // Switch selected season in case the current one has nor more episodes inside - } else if (seasonNumber) { - return getNextSeasonEpisode(seasonNumber, series); - } -}; - /** Get a total amount of episodes in a season */ export const getEpisodesInSeason = (episodeMetadata: EpisodeMetadata | undefined, series: Series | undefined) => { return (series?.seasons || []).find((el) => el.season_number === Number(episodeMetadata?.seasonNumber))?.episode_count;