stremio-web/src/routes/MetaDetails/VideosList/VideosList.js

139 lines
6.2 KiB
JavaScript

// Copyright (C) 2017-2020 Smart code 203358507
const React = require('react');
const PropTypes = require('prop-types');
const classnames = require('classnames');
const Image = require('stremio/common/Image');
const SearchBar = require('stremio/common/SearchBar');
const SeasonsBar = require('./SeasonsBar');
const Video = require('./Video');
const styles = require('./styles');
const VideosList = ({ className, metaItem, season, seasonOnSelect }) => {
const videos = React.useMemo(() => {
return metaItem && metaItem.content.type === 'Ready' ?
metaItem.content.content.videos
:
[];
}, [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));
}, [videos]);
const selectedSeason = React.useMemo(() => {
if (seasons.includes(season)) {
return season;
}
const nonSpecialSeasons = seasons.filter((season) => season !== 0);
if (nonSpecialSeasons.length > 0) {
return nonSpecialSeasons[nonSpecialSeasons.length - 1];
}
if (seasons.length > 0) {
return seasons[seasons.length - 1];
}
return null;
}, [seasons, season]);
const videosForSeason = React.useMemo(() => {
return videos
.filter((video) => {
return selectedSeason === null || video.season === selectedSeason;
})
.sort((a, b) => {
return a.episode - b.episode;
});
}, [videos, selectedSeason]);
const [search, setSearch] = React.useState('');
const searchInputOnChange = React.useCallback((event) => {
setSearch(event.currentTarget.value);
}, []);
return (
<div className={classnames(className, styles['videos-list-container'])}>
{
!metaItem || metaItem.content.type === 'Loading' ?
<React.Fragment>
<SeasonsBar.Placeholder className={styles['seasons-bar']} />
<SearchBar.Placeholder className={styles['search-bar']} title={'Search videos'} />
<div className={styles['videos-scroll-container']}>
<Video.Placeholder />
<Video.Placeholder />
<Video.Placeholder />
<Video.Placeholder />
<Video.Placeholder />
</div>
</React.Fragment>
:
metaItem.content.type === 'Err' || videosForSeason.length === 0 ?
<div className={styles['message-container']}>
<Image className={styles['image']} src={require('/images/empty.png')} alt={' '} />
<div className={styles['label']}>No videos found for this meta!</div>
</div>
:
<React.Fragment>
{
seasons.length > 0 ?
<SeasonsBar
className={styles['seasons-bar']}
season={selectedSeason}
seasons={seasons}
onSelect={seasonOnSelect}
/>
:
null
}
<SearchBar
className={styles['search-bar']}
title={'Search videos'}
value={search}
onChange={searchInputOnChange}
/>
<div className={styles['videos-container']}>
{
videosForSeason
.filter((video) => {
return search.length === 0 ||
(
(typeof video.title === 'string' && video.title.toLowerCase().includes(search.toLowerCase())) ||
(!isNaN(video.released.getTime()) && video.released.toLocaleString(undefined, { year: '2-digit', month: 'short', day: 'numeric' }).toLowerCase().includes(search.toLowerCase()))
);
})
.map((video, index) => (
<Video
key={index}
id={video.id}
title={video.title}
thumbnail={video.thumbnail}
episode={video.episode}
released={video.released}
upcoming={video.upcoming}
watched={video.watched}
progress={video.progress}
deepLinks={video.deepLinks}
scheduled={video.scheduled}
/>
))
}
</div>
</React.Fragment>
}
</div>
);
};
VideosList.propTypes = {
className: PropTypes.string,
metaItem: PropTypes.object,
season: PropTypes.number,
seasonOnSelect: PropTypes.func
};
module.exports = VideosList;