Merge pull request #176 from Stremio/video-season

selected season as query param
This commit is contained in:
Nikola Hristov 2020-05-05 15:49:59 +03:00 committed by GitHub
commit ca4e19339d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 151 deletions

View file

@ -9,7 +9,7 @@ const useMetaDetails = require('./useMetaDetails');
const useMetaExtensions = require('./useMetaExtensions');
const styles = require('./styles');
const MetaDetails = ({ urlParams }) => {
const MetaDetails = ({ urlParams, queryParams }) => {
const metaDetails = useMetaDetails(urlParams);
const { tabs, selectedMetaExtension, clearSelectedMetaExtension } = useMetaExtensions(metaDetails.meta_resources);
const metaResourceRef = React.useMemo(() => {
@ -26,6 +26,15 @@ const MetaDetails = ({ urlParams }) => {
}, [metaDetails]);
const streamsResourceRef = metaDetails.selected !== null ? metaDetails.selected.streams_resource_ref : null;
const streamsResources = metaDetails.streams_resources;
const seasonQueryParam = React.useMemo(() => {
return queryParams.has('season') && !isNaN(queryParams.get('season')) ?
parseInt(queryParams.get('season'))
:
null;
}, [queryParams]);
const seasonOnSelect = React.useCallback((event) => {
window.location.replace(`#/metadetails/${selectedMetaResource.request.path.type_name}/${selectedMetaResource.request.path.id}?season=${event.value}`);
}, [selectedMetaResource]);
const selectedVideo = React.useMemo(() => {
return streamsResourceRef !== null && selectedMetaResource !== null ?
selectedMetaResource.content.content.videos.reduce((result, video) => {
@ -125,6 +134,8 @@ const MetaDetails = ({ urlParams }) => {
<VideosList
className={styles['videos-list']}
metaResource={selectedMetaResource}
season={seasonQueryParam}
seasonOnSelect={seasonOnSelect}
/>
:
null

View file

@ -7,20 +7,44 @@ const Image = require('stremio/common/Image');
const SearchBar = require('stremio/common/SearchBar');
const SeasonsBar = require('./SeasonsBar');
const Video = require('./Video');
const useSelectableSeasons = require('./useSelectableSeasons');
const styles = require('./styles');
const VideosList = ({ className, metaResource }) => {
const VideosList = ({ className, metaResource, season, seasonOnSelect }) => {
const videos = React.useMemo(() => {
return metaResource && metaResource.content.type === 'Ready' ?
metaResource.content.content.videos
:
[];
}, [metaResource]);
const [seasons, selectedSeason, videosForSeason, selectSeason] = useSelectableSeasons(videos);
const seasonOnSelect = React.useCallback((event) => {
selectSeason(event.value);
}, []);
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 - b);
}, [videos]);
const selectedSeason = React.useMemo(() => {
return seasons.includes(season) ?
season
:
seasons.length > 0 ?
seasons[seasons.length - 1]
:
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);
@ -88,7 +112,9 @@ const VideosList = ({ className, metaResource }) => {
VideosList.propTypes = {
className: PropTypes.string,
metaResource: PropTypes.object
metaResource: PropTypes.object,
season: PropTypes.number,
seasonOnSelect: PropTypes.func
};
module.exports = VideosList;

View file

@ -1,91 +0,0 @@
// Copyright (C) 2017-2020 Smart code 203358507
const React = require('react');
const reducer = (state, action) => {
switch (action.type) {
case 'videos-changed': {
const seasons = action.videos
.map(({ season }) => season)
.filter((season, index, seasons) => {
return season !== null &&
!isNaN(season) &&
typeof season === 'number' &&
seasons.indexOf(season) === index;
})
.sort((a, b) => a - b);
const selectedSeason = seasons.includes(state.selectedSeason) ?
state.selectedSeason
:
seasons.length > 0 ?
seasons[seasons.length - 1]
:
null;
return {
...state,
videos: action.videos,
seasons,
selectedSeason
};
}
case 'season-changed': {
const selectedSeason = state.seasons.includes(action.season) ?
action.season
:
state.season;
return {
...state,
selectedSeason
};
}
default: {
return state;
}
}
};
const initializer = (videos) => {
const initialState = {
videos: [],
seasons: [],
selectedSeason: null
};
const initAction = {
type: 'videos-changed',
videos
};
return reducer(initialState, initAction);
};
const useSelectableSeasons = (videos) => {
const [state, dispatch] = React.useReducer(
reducer,
videos,
initializer
);
const selectSeason = React.useCallback((season) => {
dispatch({
type: 'season-changed',
season
});
}, []);
const videosForSeason = React.useMemo(() => {
return state.videos
.filter((video) => {
return state.selectedSeason === null || video.season === state.selectedSeason;
})
.sort((a, b) => {
return a.episode - b.episode;
});
}, [state.videos, state.selectedSeason]);
React.useEffect(() => {
dispatch({
type: 'videos-changed',
videos
});
}, [videos]);
return [state.seasons, state.selectedSeason, videosForSeason, selectSeason];
};
module.exports = useSelectableSeasons;

View file

@ -1,52 +0,0 @@
// Copyright (C) 2017-2020 Smart code 203358507
const { renderHook, act } = require('@testing-library/react-hooks');
const useSelectableSeasons = require('../src/routes/MetaDetails/VideosList/useSelectableSeasons');
const videos = [{ 'season': 4 }, { 'season': 5 }, { 'season': 4 }, { 'season': 7 }];
describe('hooks tests', () => {
describe('useSelectableSeasons hook', () => {
it('match 7', async () => {
const { result } = renderHook(() => useSelectableSeasons(videos));
const [, selectedSeason] = result.current;
expect(selectedSeason).toBe(7);
});
it('match 5', async () => {
const { result } = renderHook(() => useSelectableSeasons(videos));
act(() => {
const [, , , selectSeason] = result.current;
selectSeason(5);
});
const [, selectedSeason] = result.current;
expect(selectedSeason).toBe(5);
});
it('not match 6', async () => {
const { result } = renderHook(() => useSelectableSeasons(videos));
act(() => {
const [, , , selectSeason] = result.current;
selectSeason(6);
});
const [, selectedSeason] = result.current;
expect(selectedSeason).toBe(undefined);
});
it('not match $', async () => {
const { result } = renderHook(() => useSelectableSeasons(videos));
act(() => {
const [, , , selectSeason] = result.current;
selectSeason('$');
});
const [, selectedSeason] = result.current;
expect(selectedSeason).toBe(undefined);
});
});
});