Skip to content

Commit

Permalink
feat(series): review fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonLantukh committed May 30, 2023
1 parent 2e794d9 commit b46603a
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 342 deletions.
55 changes: 19 additions & 36 deletions src/components/VideoList/VideoList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type Props = {
loadMore?: () => void;
};

// eslint-disable-next-line @typescript-eslint/no-empty-function
const defaultLoadMore = () => {};

function VideoList({
playlist,
header,
Expand All @@ -42,46 +45,26 @@ function VideoList({
isLoggedIn,
hasSubscription,
hasLoadMore,
loadMore,
loadMore = defaultLoadMore,
}: Props) {
return (
<div className={classNames(styles.container, !!className && className)} data-testid={testId('video-list')}>
{!!header && header}
{loadMore ? (
<InfiniteScroll pageStart={0} loadMore={loadMore} hasMore={hasLoadMore} loader={<InfiniteScrollLoader key="loader" />}>
<>
{playlist?.playlist?.map((playlistItem: PlaylistItem) => (
<VideoListItem
key={playlistItem.mediaid}
progress={watchHistory ? watchHistory[playlistItem.mediaid] : undefined}
onClick={() => onListItemClick && onListItemClick(playlistItem, playlistItem.feedid)}
onHover={() => onListItemHover && onListItemHover(playlistItem)}
loading={isLoading}
isActive={activeMediaId === playlistItem.mediaid}
activeLabel={activeLabel}
isLocked={isLocked(accessModel, isLoggedIn, hasSubscription, playlistItem)}
item={playlistItem}
/>
))}
</>
</InfiniteScroll>
) : (
<>
{playlist?.playlist?.map((playlistItem: PlaylistItem) => (
<VideoListItem
key={playlistItem.mediaid}
progress={watchHistory ? watchHistory[playlistItem.mediaid] : undefined}
onClick={() => onListItemClick && onListItemClick(playlistItem, playlistItem.feedid)}
onHover={() => onListItemHover && onListItemHover(playlistItem)}
loading={isLoading}
isActive={activeMediaId === playlistItem.mediaid}
activeLabel={activeLabel}
isLocked={isLocked(accessModel, isLoggedIn, hasSubscription, playlistItem)}
item={playlistItem}
/>
))}
</>
)}
<InfiniteScroll pageStart={0} loadMore={loadMore || defaultLoadMore} hasMore={hasLoadMore} loader={<InfiniteScrollLoader key="loader" />}>
{playlist?.playlist?.map((playlistItem: PlaylistItem) => (
<VideoListItem
key={playlistItem.mediaid}
progress={watchHistory ? watchHistory[playlistItem.mediaid] : undefined}
onClick={() => onListItemClick && onListItemClick(playlistItem, playlistItem.feedid)}
onHover={() => onListItemHover && onListItemHover(playlistItem)}
loading={isLoading}
isActive={activeMediaId === playlistItem.mediaid}
activeLabel={activeLabel}
isLocked={isLocked(accessModel, isLoggedIn, hasSubscription, playlistItem)}
item={playlistItem}
/>
))}
</InfiniteScroll>
</div>
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/containers/AppRoutes/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import About from '#src/pages/About/About';
import Home from '#src/pages/Home/Home';
import Search from '#src/pages/Search/Search';
import User from '#src/pages/User/User';
import DeprecatedSeries from '#src/pages/DeprecatedSeries/DeprecatedSeries';
import LegacySeries from '#src/pages/LegacySeries/LegacySeries';
import MediaScreenRouter from '#src/pages/ScreenRouting/MediaScreenRouter';
import PlaylistScreenRouter from '#src/pages/ScreenRouting/PlaylistScreenRouter';
import Layout from '#src/containers/Layout/Layout';
Expand All @@ -22,7 +22,7 @@ export default function AppRoutes() {
<Route index element={<Home />} />
<Route path="/p/:id" element={<PlaylistScreenRouter />} />
<Route path="/m/:id/*" element={<MediaScreenRouter />} />
<Route path="/s/:id/*" element={<DeprecatedSeries />} />
<Route path="/s/:id/*" element={<LegacySeries />} />
<Route path="/q/*" element={<Search />} />
<Route path="/u/*" element={<User />} />
<Route path="/o/about" element={<About />} />
Expand Down
18 changes: 4 additions & 14 deletions src/hooks/series/useNextEpisode.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,18 @@
import { useEffect, useState } from 'react';

import type { Playlist, PlaylistItem } from '#types/playlist';
import type { PlaylistItem } from '#types/playlist';
import type { EpisodeMetadata, Series } from '#types/series';
import { getNextItem } from '#src/utils/series';

export const useNextEpisode = ({
episode,
seriesPlaylist,
series,
episodeMetadata,
}: {
episode: PlaylistItem | undefined;
seriesPlaylist: Playlist;
series: Series | undefined;
episodeMetadata: EpisodeMetadata | undefined;
}) => {
export const useNextEpisode = ({ series, episodeMetadata }: { series: Series | undefined; episodeMetadata: EpisodeMetadata | undefined }) => {
const [nextItem, setNextItem] = useState<PlaylistItem | undefined>(undefined);
useEffect(() => {
async function fetchData() {
const item = await getNextItem(episode, seriesPlaylist, series, episodeMetadata);
const item = await getNextItem(series, episodeMetadata);
setNextItem(item);
}
fetchData();
}, [episode, seriesPlaylist, series, episodeMetadata]);
}, [series, episodeMetadata]);

return nextItem;
};
4 changes: 2 additions & 2 deletions src/hooks/series/useSeriesId.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import { useQuery } from 'react-query';

import type { PlaylistItem } from '#types/playlist';
import { getSeriesByMediaIds } from '#src/services/api.service';
import { getSeriesIdFromEpisode } from '#src/utils/media';
import { getLegacySeriesPlaylistIdFromEpisodeTags } from '#src/utils/media';

const useGetSeriesId = (item: PlaylistItem) => {
const staticSeriesId = getSeriesIdFromEpisode(item);
const staticSeriesId = getLegacySeriesPlaylistIdFromEpisodeTags(item);

const { isLoading, data } = useQuery(['seriesId', item.mediaid], async () => {
// get all series for the given media id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
import shallow from 'zustand/shallow';

import { filterSeries, getEpisodesInSeason, getFiltersFromSeries, getNextItem } from './utils';
import { filterSeries, getEpisodesInSeason, getFiltersFromSeries, getNextItem, generateLegacyEpisodeJSONLD } from './utils';

import { generateLegacyEpisodeJSONLD } from '#src/utils/structuredData';
import VideoLayout from '#components/VideoLayout/VideoLayout';
import InlinePlayer from '#src/containers/InlinePlayer/InlinePlayer';
import { isLocked } from '#src/utils/entitlements';
Expand All @@ -30,7 +29,7 @@ import useQueryParam from '#src/hooks/useQueryParam';
import Loading from '#src/pages/Loading/Loading';
import usePlaylist from '#src/hooks/usePlaylist';

const DeprecatedSeries = () => {
const LegacySeries = () => {
const breakpoint = useBreakpoint();
const { t } = useTranslation('video');
const [playTrailer, setPlayTrailer] = useState<boolean>(false);
Expand Down Expand Up @@ -229,4 +228,4 @@ const DeprecatedSeries = () => {
);
};

export default DeprecatedSeries;
export default LegacySeries;
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { deprecatedSeriesURL } from '#src/utils/formatting';
import { secondsToISO8601 } from '#src/utils/datetime';
import type { Playlist, PlaylistItem } from '#types/playlist';
import type { EpisodeMetadata } from '#types/series';

/**
* Get an array of options for a season filter
Expand Down Expand Up @@ -42,3 +45,45 @@ export const getEpisodesInSeason = (episode: PlaylistItem | undefined, seriesPla

return seriesPlaylist.playlist.filter((i) => i.seasonNumber === episode?.seasonNumber)?.length;
};

export const generateLegacySeriesMetadata = (seriesPlaylist: Playlist, seriesId: string | undefined) => {
// Use playlist for old flow and media id for a new flow
const seriesCanonical = `${window.location.origin}/s/${seriesId}`;

return {
'@type': 'TVSeries',
'@id': seriesCanonical,
name: seriesPlaylist.title,
numberOfEpisodes: String(seriesPlaylist.playlist.length),
numberOfSeasons: String(
seriesPlaylist.playlist.reduce(function (list, playlistItem) {
return !playlistItem.seasonNumber || list.includes(playlistItem.seasonNumber) ? list : list.concat(playlistItem.seasonNumber);
}, [] as string[]).length,
),
};
};

export const generateLegacyEpisodeJSONLD = (
seriesPlaylist: Playlist,
episode: PlaylistItem | undefined,
episodeMetadata: EpisodeMetadata | undefined,
seriesId: string,
) => {
const episodeCanonical = `${window.location.origin}${deprecatedSeriesURL({ episodeId: episode?.mediaid, seriesId })}`;
const seriesMetadata = generateLegacySeriesMetadata(seriesPlaylist, seriesId);

if (!episode) {
return JSON.stringify(seriesMetadata);
}

return JSON.stringify({
'@context': 'http://schema.org/',
'@type': 'TVEpisode',
'@id': episodeCanonical,
episodeNumber: episodeMetadata?.episodeNumber,
seasonNumber: episodeMetadata?.seasonNumber,
name: episode.title,
uploadDate: secondsToISO8601(episode.pubdate),
partOfSeries: seriesMetadata,
});
};
4 changes: 2 additions & 2 deletions src/pages/ScreenRouting/MediaScreenRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import useMedia from '#src/hooks/useMedia';
import Loading from '#src/pages/Loading/Loading';
import ErrorPage from '#components/ErrorPage/ErrorPage';
import type { PlaylistItem } from '#types/playlist';
import { isEpisode, isDeprecatedSeriesFlow } from '#src/utils/media';
import { isEpisode, isLegacySeriesFlow } from '#src/utils/media';
import MediaMovie from '#src/pages/ScreenRouting/mediaScreens/MediaMovie/MediaMovie';
import MediaSeries from '#src/pages/ScreenRouting/mediaScreens/MediaSeries/MediaSeries';
import MediaLiveChannel from '#src/pages/ScreenRouting/mediaScreens/MediaLiveChannel/MediaLiveChannel';
Expand All @@ -27,7 +27,7 @@ mediaScreenMap.registerDefault(MediaMovie);

// Register legacy series and episode screens when `contentType` is missing
mediaScreenMap.register(MediaEpisode, (item) => !!item && isEpisode(item));
mediaScreenMap.register(MediaSeries, (item) => !!item && isDeprecatedSeriesFlow(item));
mediaScreenMap.register(MediaSeries, (item) => !!item && isLegacySeriesFlow(item));

const MediaScreenRouter = () => {
const params = useParams();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import { useTranslation } from 'react-i18next';
import shallow from 'zustand/shallow';
import { useSearchParams } from 'react-router-dom';

import { filterSeries, getEpisodesInSeason, getFiltersFromSeries } from './utils';

import { generateEpisodeJSONLD } from '#src/utils/structuredData';
import VideoLayout from '#components/VideoLayout/VideoLayout';
import InlinePlayer from '#src/containers/InlinePlayer/InlinePlayer';
import { isLocked } from '#src/utils/entitlements';
import useEntitlement from '#src/hooks/useEntitlement';
import { getEpisodesInSeason, getFiltersFromSeries } from '#src/utils/series';
import { deprecatedSeriesURL, formatSeriesMetaString, formatVideoMetaString, mediaURL } from '#src/utils/formatting';
import useMedia from '#src/hooks/useMedia';
import { useSeriesData } from '#src/hooks/series/useSeriesData';
Expand Down Expand Up @@ -77,9 +76,9 @@ const MediaSeriesContent: ScreenComponent<PlaylistItem> = ({ data: seriesMedia }
} = useEpisodes(seriesId, seasonFilter, { enabled: seasonFilter !== undefined && !!series });

const firstEpisode = useMemo(() => episodes?.[0]?.episodes?.[0], [episodes]);
const filteredPlaylist = useMemo(() => filterSeries(seriesPlaylist, episodes), [seriesPlaylist, episodes]);
const playlist = useMemo(() => ({ ...seriesPlaylist, playlist: episodes?.flatMap((e) => e.episodes) || [] }), [seriesPlaylist, episodes]);
const episodesInSeason = getEpisodesInSeason(episodeMetadata, series);
const nextItem = useNextEpisode({ episode, seriesPlaylist, series, episodeMetadata });
const nextItem = useNextEpisode({ series, episodeMetadata });

// Watch history
const watchHistoryArray = useWatchHistoryStore((state) => state.watchHistory);
Expand Down Expand Up @@ -226,7 +225,7 @@ const MediaSeriesContent: ScreenComponent<PlaylistItem> = ({ data: seriesMedia }
accessModel={accessModel}
isLoggedIn={isLoggedIn}
hasSubscription={hasSubscription}
playlist={filteredPlaylist}
playlist={playlist}
relatedTitle={inlineLayout ? seriesPlaylist.title : t('episodes')}
onItemClick={onCardClick}
setFilter={setSeasonFilter}
Expand Down
Loading

0 comments on commit b46603a

Please sign in to comment.