diff --git a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js index 29637a24c..1133e2162 100644 --- a/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js +++ b/src/routes/MetaDetails/VideosList/SeasonsBar/SeasonsBar.js @@ -9,19 +9,26 @@ const { Button, MultiselectMenu } = require('stremio/components'); const SeasonsBarPlaceholder = require('./SeasonsBarPlaceholder'); const styles = require('./styles'); -const SeasonsBar = ({ className, seasons, season, onSelect }) => { +const SeasonsBar = ({ className, seasons, season, episode, onSelect }) => { const options = React.useMemo(() => { - return seasons.map((season) => ({ - value: String(season), - label: season > 0 ? `${t('SEASON')} ${season}` : t('SPECIAL') + return seasons.map(({ id, episodes }) => ({ + value: String(id), + label: id > 0 ? `${t('SEASON')} ${id}` : t('SPECIAL'), + options: episodes.map((episode) => ({ + value: String(episode), + label: `${t('EPISODE')} ${episode}` + })), })); }, [seasons]); const selectedSeason = React.useMemo(() => { - return { label: String(season), value: String(season) }; + return { label: String(season.id), value: String(season.id), options: season.episodes.map((episode) => ({ + value: String(episode), + label: `${t('EPISODE')} ${episode}` + }))}; }, [season]); const prevNextButtonOnClick = React.useCallback((event) => { if (typeof onSelect === 'function') { - const seasonIndex = seasons.indexOf(season); + const seasonIndex = seasons.findIndex(({ id }) => id === season.id); const valueIndex = event.currentTarget.dataset.action === 'next' ? seasonIndex + 1 < seasons.length ? seasonIndex + 1 : seasons.length - 1 : @@ -35,11 +42,12 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => { }); } }, [season, seasons, onSelect]); - const seasonOnSelect = React.useCallback((value) => { + const seasonOnSelect = React.useCallback((level, value) => { if (typeof onSelect === 'function') { onSelect({ type: 'select', value: value, + level, reactEvent: event.reactEvent, nativeEvent: event.nativeEvent }); @@ -47,7 +55,7 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => { }, [onSelect]); const [prevDisabled, nextDisabled] = React.useMemo(() => { - const currentIndex = seasons.indexOf(season); + const currentIndex = seasons.findIndex(({ id }) => id === season.id); return [ currentIndex === 0, currentIndex === seasons.length - 1 @@ -63,7 +71,8 @@ const SeasonsBar = ({ className, seasons, season, onSelect }) => { 0 ? `${t('SEASON')} ${season}` : t('SPECIAL')} + title={season.id > 0 ? `${t('SEASON')} ${season.id}` : t('SPECIAL')} + subtitle={episode && `${t('EPISODE')} ${episode}`} selectedOption={selectedSeason} onSelect={seasonOnSelect} /> @@ -79,8 +88,15 @@ SeasonsBar.Placeholder = SeasonsBarPlaceholder; SeasonsBar.propTypes = { className: PropTypes.string, - seasons: PropTypes.arrayOf(PropTypes.number).isRequired, - season: PropTypes.number.isRequired, + seasons: PropTypes.arrayOf(PropTypes.shape({ + id: PropTypes.number, + episodes: PropTypes.arrayOf(PropTypes.number), + })).isRequired, + season: PropTypes.shape({ + id: PropTypes.number, + episodes: PropTypes.arrayOf(PropTypes.number), + }).isRequired, + episode: PropTypes.string, onSelect: PropTypes.func }; diff --git a/src/routes/MetaDetails/VideosList/VideosList.js b/src/routes/MetaDetails/VideosList/VideosList.js index 999a1a1ae..a6f2d3a32 100644 --- a/src/routes/MetaDetails/VideosList/VideosList.js +++ b/src/routes/MetaDetails/VideosList/VideosList.js @@ -11,6 +11,7 @@ const styles = require('./styles'); const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, toggleNotifications }) => { const { core } = useServices(); + const [selectedEpisode, setSelectedEpisode] = React.useState(null); const showNotificationsToggle = React.useMemo(() => { return metaItem?.content?.content?.inLibrary && metaItem?.content?.content?.videos?.length; }, [metaItem]); @@ -21,22 +22,19 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, []; }, [metaItem]); const seasons = React.useMemo(() => { - return videos - .map(({ season }) => season) - .filter((season, index, seasons) => { - return season !== null && - !isNaN(season) && - typeof season === 'number' && - seasons.indexOf(season) === index; - }) - .sort((a, b) => (a || Number.MAX_SAFE_INTEGER) - (b || Number.MAX_SAFE_INTEGER)); + return [...new Set(videos.map(({ season }) => season))].map((season) => ({ + id: season, + episodes: videos.filter(({ season: s }) => s === season).map(({ episode }) => episode) + })) + .sort((a, b) => (a.id || Number.MAX_SAFE_INTEGER) - (b.id || Number.MAX_SAFE_INTEGER)); }, [videos]); const selectedSeason = React.useMemo(() => { - if (seasons.includes(season)) { - return season; + const foundSeason = seasons.find(({ id }) => id === season); + if (foundSeason) { + return foundSeason; } - const nonSpecialSeasons = seasons.filter((season) => season !== 0); + const nonSpecialSeasons = seasons.filter(({ id }) => id !== 0); if (nonSpecialSeasons.length > 0) { return nonSpecialSeasons[nonSpecialSeasons.length - 1]; } @@ -50,7 +48,7 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, const videosForSeason = React.useMemo(() => { return videos .filter((video) => { - return selectedSeason === null || video.season === selectedSeason; + return selectedSeason === null || video.season === selectedSeason.id; }) .sort((a, b) => { return a.episode - b.episode; @@ -71,6 +69,26 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, }); }; + const handleSelect = (event) => { + if (!event.level) { + seasonOnSelect(event); + } else { + setSelectedEpisode(event.value); + const episode = videos.find(({ season: s, episode: e }) => s === season && e.toString() === event.value); + if (episode.deepLinks) { + if (typeof episode.deepLinks.player === 'string') { + window.location = episode.deepLinks.player; + } else if (typeof episode.deepLinks.metaDetailsStreams === 'string') { + window.location.replace(episode.deepLinks.metaDetailsStreams); + } + } + } + }; + + React.useEffect(() => { + setSelectedEpisode(null); + }, [season]); + return (
{ @@ -107,8 +125,9 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, : null