mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 21:27:05 +00:00
MetaDetails adapted to changes in core
This commit is contained in:
parent
d32fe5123a
commit
07398b56cc
8 changed files with 207 additions and 202 deletions
|
|
@ -2,43 +2,30 @@
|
|||
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const { VerticalNavBar, HorizontalNavBar, MetaPreview, ModalDialog, Image, useInLibrary } = require('stremio/common');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { VerticalNavBar, HorizontalNavBar, MetaPreview, ModalDialog, Image } = require('stremio/common');
|
||||
const StreamsList = require('./StreamsList');
|
||||
const VideosList = require('./VideosList');
|
||||
const useMetaDetails = require('./useMetaDetails');
|
||||
const useMetaExtensions = require('./useMetaExtensions');
|
||||
const useSeason = require('./useSeason');
|
||||
const useMetaExtensionTabs = require('./useMetaExtensionTabs');
|
||||
const styles = require('./styles');
|
||||
|
||||
const MetaDetails = ({ urlParams, queryParams }) => {
|
||||
const { core } = useServices();
|
||||
const metaDetails = useMetaDetails(urlParams);
|
||||
const { tabs, selectedMetaExtension, clearSelectedMetaExtension } = useMetaExtensions(metaDetails.meta_resources);
|
||||
const metaResourceRef = React.useMemo(() => {
|
||||
return metaDetails.selected !== null ? metaDetails.selected.meta_resources_ref : null;
|
||||
}, [metaDetails.selected]);
|
||||
const selectedMetaResource = React.useMemo(() => {
|
||||
return metaDetails.meta_resources.reduceRight((result, metaResource) => {
|
||||
if (metaResource.content.type === 'Ready') {
|
||||
return metaResource;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, null);
|
||||
}, [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'))
|
||||
const [season, setSeason] = useSeason(urlParams, queryParams);
|
||||
const [tabs, metaExtension, clearMetaExtension] = useMetaExtensionTabs(metaDetails.metaExtensions);
|
||||
const [metaPath, streamsPath] = React.useMemo(() => {
|
||||
return metaDetails.selected !== null ?
|
||||
[metaDetails.selected.metaPath, metaDetails.selected.streamsPath]
|
||||
:
|
||||
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) => {
|
||||
if (video.id === streamsResourceRef.id) {
|
||||
[null, null];
|
||||
}, [metaDetails.selected]);
|
||||
const video = React.useMemo(() => {
|
||||
return streamsPath !== null && metaDetails.metaCatalog !== null && metaDetails.metaCatalog.content.type === 'Ready' ?
|
||||
metaDetails.metaCatalog.content.content.videos.reduce((result, video) => {
|
||||
if (video.id === streamsPath.id) {
|
||||
return video;
|
||||
}
|
||||
|
||||
|
|
@ -46,14 +33,42 @@ const MetaDetails = ({ urlParams, queryParams }) => {
|
|||
}, null)
|
||||
:
|
||||
null;
|
||||
}, [selectedMetaResource, streamsResourceRef]);
|
||||
const [inLibrary, toggleInLibrary] = useInLibrary(selectedMetaResource !== null ? selectedMetaResource.content.content : null);
|
||||
}, [metaDetails.metaCatalog, streamsPath]);
|
||||
const addToLibrary = React.useCallback(() => {
|
||||
if (metaDetails.metaCatalog === null || metaDetails.metaCatalog.content.type !== 'Ready') {
|
||||
return;
|
||||
}
|
||||
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'AddToLibrary',
|
||||
args: metaDetails.metaCatalog.content.content
|
||||
}
|
||||
});
|
||||
}, [metaDetails]);
|
||||
const removeFromLibrary = React.useCallback(() => {
|
||||
if (metaDetails.metaCatalog === null || metaDetails.metaCatalog.content.type !== 'Ready') {
|
||||
return;
|
||||
}
|
||||
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'RemoveFromLibrary',
|
||||
args: metaDetails.metaCatalog.content.content.id
|
||||
}
|
||||
});
|
||||
}, [metaDetails]);
|
||||
const seasonOnSelect = React.useCallback((event) => {
|
||||
setSeason(event.value);
|
||||
}, [setSeason]);
|
||||
return (
|
||||
<div className={styles['metadetails-container']}>
|
||||
<HorizontalNavBar
|
||||
className={styles['nav-bar']}
|
||||
backButton={true}
|
||||
title={selectedMetaResource !== null ? selectedMetaResource.content.content.name : null}
|
||||
title={metaDetails.metaCatalog !== null && metaDetails.metaCatalog.content.type === 'Ready' ? metaDetails.metaCatalog.content.content.name : null}
|
||||
/>
|
||||
<div className={styles['metadetails-content']}>
|
||||
{
|
||||
|
|
@ -61,39 +76,41 @@ const MetaDetails = ({ urlParams, queryParams }) => {
|
|||
<VerticalNavBar
|
||||
className={styles['vertical-nav-bar']}
|
||||
tabs={tabs}
|
||||
selected={selectedMetaExtension !== null ? selectedMetaExtension.url : null}
|
||||
selected={metaExtension !== null ? metaExtension.url : null}
|
||||
/>
|
||||
:
|
||||
null
|
||||
}
|
||||
{
|
||||
metaResourceRef === null ?
|
||||
metaPath === null ?
|
||||
<div className={styles['meta-message-container']}>
|
||||
<Image className={styles['image']} src={'/images/empty.png'} alt={' '} />
|
||||
<div className={styles['message-label']}>No meta was selected!</div>
|
||||
</div>
|
||||
:
|
||||
metaDetails.meta_resources.length === 0 ?
|
||||
metaDetails.metaCatalog === null ?
|
||||
<div className={styles['meta-message-container']}>
|
||||
<Image className={styles['image']} src={'/images/empty.png'} alt={' '} />
|
||||
<div className={styles['message-label']}>No addons ware requested for this meta!</div>
|
||||
</div>
|
||||
:
|
||||
metaDetails.meta_resources.every((metaResource) => metaResource.content.type === 'Err') ?
|
||||
metaDetails.metaCatalog.content.type === 'Err' ?
|
||||
<div className={styles['meta-message-container']}>
|
||||
<Image className={styles['image']} src={'/images/empty.png'} alt={' '} />
|
||||
<div className={styles['message-label']}>No metadata was found!</div>
|
||||
</div>
|
||||
:
|
||||
selectedMetaResource !== null ?
|
||||
metaDetails.metaCatalog.content.type === 'Loading' ?
|
||||
<MetaPreview.Placeholder className={styles['meta-preview']} />
|
||||
:
|
||||
<React.Fragment>
|
||||
{
|
||||
typeof selectedMetaResource.content.content.background === 'string' &&
|
||||
selectedMetaResource.content.content.background.length > 0 ?
|
||||
typeof metaDetails.metaCatalog.content.content.background === 'string' &&
|
||||
metaDetails.metaCatalog.content.content.background.length > 0 ?
|
||||
<div className={styles['background-image-layer']}>
|
||||
<Image
|
||||
className={styles['background-image']}
|
||||
src={selectedMetaResource.content.content.background}
|
||||
src={metaDetails.metaCatalog.content.content.background}
|
||||
alt={' '}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -102,39 +119,37 @@ const MetaDetails = ({ urlParams, queryParams }) => {
|
|||
}
|
||||
<MetaPreview
|
||||
className={styles['meta-preview']}
|
||||
name={selectedMetaResource.content.content.name + (selectedVideo !== null && typeof selectedVideo.title === 'string' ? ` - ${selectedVideo.title}` : '')}
|
||||
logo={selectedMetaResource.content.content.logo}
|
||||
runtime={selectedMetaResource.content.content.runtime}
|
||||
releaseInfo={selectedMetaResource.content.content.releaseInfo}
|
||||
released={selectedMetaResource.content.content.released}
|
||||
name={metaDetails.metaCatalog.content.content.name + (video !== null && typeof video.title === 'string' && video.title.length > 0 ? ` - ${video.title}` : '')}
|
||||
logo={metaDetails.metaCatalog.content.content.logo}
|
||||
runtime={metaDetails.metaCatalog.content.content.runtime}
|
||||
releaseInfo={metaDetails.metaCatalog.content.content.releaseInfo}
|
||||
released={metaDetails.metaCatalog.content.content.released}
|
||||
description={
|
||||
selectedVideo !== null && typeof selectedVideo.overview === 'string' && selectedVideo.overview.length > 0 ?
|
||||
selectedVideo.overview
|
||||
video !== null && typeof video.overview === 'string' && video.overview.length > 0 ?
|
||||
video.overview
|
||||
:
|
||||
selectedMetaResource.content.content.description
|
||||
metaDetails.metaCatalog.content.content.description
|
||||
}
|
||||
links={selectedMetaResource.content.content.links}
|
||||
trailerStreams={selectedMetaResource.content.content.trailerStreams}
|
||||
inLibrary={inLibrary}
|
||||
toggleInLibrary={toggleInLibrary}
|
||||
links={metaDetails.metaCatalog.content.content.links}
|
||||
trailerStreams={metaDetails.metaCatalog.content.content.trailerStreams}
|
||||
inLibrary={metaDetails.metaCatalog.content.content.inLibrary}
|
||||
toggleInLibrary={metaDetails.metaCatalog.content.content.inLibrary ? removeFromLibrary : addToLibrary}
|
||||
/>
|
||||
</React.Fragment>
|
||||
:
|
||||
<MetaPreview.Placeholder className={styles['meta-preview']} />
|
||||
}
|
||||
<div className={styles['spacing']} />
|
||||
{
|
||||
streamsResourceRef !== null ?
|
||||
streamsPath !== null ?
|
||||
<StreamsList
|
||||
className={styles['streams-list']}
|
||||
streamsResources={streamsResources}
|
||||
streamsCatalogs={metaDetails.streamsCatalogs}
|
||||
/>
|
||||
:
|
||||
metaResourceRef !== null ?
|
||||
metaPath !== null ?
|
||||
<VideosList
|
||||
className={styles['videos-list']}
|
||||
metaResource={selectedMetaResource}
|
||||
season={seasonQueryParam}
|
||||
metaCatalog={metaDetails.metaCatalog}
|
||||
season={season}
|
||||
seasonOnSelect={seasonOnSelect}
|
||||
/>
|
||||
:
|
||||
|
|
@ -142,15 +157,15 @@ const MetaDetails = ({ urlParams, queryParams }) => {
|
|||
}
|
||||
</div>
|
||||
{
|
||||
selectedMetaExtension !== null ?
|
||||
metaExtension !== null ?
|
||||
<ModalDialog
|
||||
className={styles['meta-extension-modal-container']}
|
||||
title={selectedMetaExtension.name}
|
||||
onCloseRequest={clearSelectedMetaExtension}>
|
||||
title={metaExtension.name}
|
||||
onCloseRequest={clearMetaExtension}>
|
||||
<iframe
|
||||
className={styles['meta-extension-modal-iframe']}
|
||||
sandbox={'allow-forms allow-scripts allow-same-origin'}
|
||||
src={selectedMetaExtension.url}
|
||||
src={metaExtension.url}
|
||||
/>
|
||||
</ModalDialog>
|
||||
:
|
||||
|
|
|
|||
|
|
@ -8,38 +8,48 @@ const { Button, Image } = require('stremio/common');
|
|||
const Stream = require('./Stream');
|
||||
const styles = require('./styles');
|
||||
|
||||
const StreamsList = ({ className, streamsResources }) => {
|
||||
const StreamsList = ({ className, streamsCatalogs }) => {
|
||||
const streams = React.useMemo(() => {
|
||||
return streamsResources
|
||||
.filter((streamsResource) => streamsResource.content.type === 'Ready')
|
||||
.map((streamsResource) => streamsResource.content.content)
|
||||
return streamsCatalogs
|
||||
.filter((catalog) => catalog.content.type === 'Ready')
|
||||
.map((catalog) => ({
|
||||
...catalog.content.content,
|
||||
addonName: catalog.addonName
|
||||
}))
|
||||
.flat(1);
|
||||
}, [streamsResources]);
|
||||
}, [streamsCatalogs]);
|
||||
return (
|
||||
<div className={classnames(className, styles['streams-list-container'])}>
|
||||
{
|
||||
streamsResources.length === 0 ?
|
||||
streamsCatalogs.length === 0 ?
|
||||
<div className={styles['message-container']}>
|
||||
<Image className={styles['image']} src={'/images/empty.png'} alt={' '} />
|
||||
<div className={styles['label']}>No addons were requested for streams!</div>
|
||||
</div>
|
||||
:
|
||||
streamsResources.every((streamsResource) => streamsResource.content.type === 'Err') ?
|
||||
streamsCatalogs.every((streamsResource) => streamsResource.content.type === 'Err') ?
|
||||
<div className={styles['message-container']}>
|
||||
<Image className={styles['image']} src={'/images/empty.png'} alt={' '} />
|
||||
<div className={styles['label']}>No streams were found!</div>
|
||||
</div>
|
||||
:
|
||||
streams.length > 0 ?
|
||||
streams.length === 0 ?
|
||||
<div className={styles['streams-container']}>
|
||||
{streams.map((stream, index) => (
|
||||
<Stream {...stream} key={index} />
|
||||
))}
|
||||
<Stream.Placeholder />
|
||||
<Stream.Placeholder />
|
||||
</div>
|
||||
:
|
||||
<div className={styles['streams-container']}>
|
||||
<Stream.Placeholder />
|
||||
<Stream.Placeholder />
|
||||
{streams.map((stream, index) => (
|
||||
<Stream
|
||||
key={index}
|
||||
addonName={stream.addonName}
|
||||
title={stream.title}
|
||||
thumbnail={stream.thumbnail}
|
||||
progress={stream.progress}
|
||||
deepLinks={stream.deepLinks}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
<Button className={styles['install-button-container']} title={'Install Addons'} href={'#/addons'}>
|
||||
|
|
@ -52,7 +62,7 @@ const StreamsList = ({ className, streamsResources }) => {
|
|||
|
||||
StreamsList.propTypes = {
|
||||
className: PropTypes.string,
|
||||
streamsResources: PropTypes.arrayOf(PropTypes.object)
|
||||
streamsCatalogs: PropTypes.arrayOf(PropTypes.object).isRequired
|
||||
};
|
||||
|
||||
module.exports = StreamsList;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const { Button, Image } = require('stremio/common');
|
|||
const VideoPlaceholder = require('./VideoPlaceholder');
|
||||
const styles = require('./styles');
|
||||
|
||||
const Video = ({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, deepLinks, ...props }) => {
|
||||
const Video = ({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, scheduled, deepLinks, ...props }) => {
|
||||
const href = React.useMemo(() => {
|
||||
return deepLinks ?
|
||||
typeof deepLinks.player === 'string' ?
|
||||
|
|
@ -53,7 +53,12 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w
|
|||
{released.toLocaleString(undefined, { year: '2-digit', month: 'short', day: 'numeric' })}
|
||||
</div>
|
||||
:
|
||||
null
|
||||
scheduled ?
|
||||
<div className={styles['released-container']} title={'To be announced'}>
|
||||
TBA
|
||||
</div>
|
||||
:
|
||||
null
|
||||
}
|
||||
<div className={styles['upcoming-watched-container']}>
|
||||
{
|
||||
|
|
@ -99,6 +104,7 @@ Video.propTypes = {
|
|||
upcoming: PropTypes.bool,
|
||||
watched: PropTypes.bool,
|
||||
progress: PropTypes.number,
|
||||
scheduled: PropTypes.bool,
|
||||
deepLinks: PropTypes.shape({
|
||||
meta_details_streams: PropTypes.string,
|
||||
player: PropTypes.string
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ const SeasonsBar = require('./SeasonsBar');
|
|||
const Video = require('./Video');
|
||||
const styles = require('./styles');
|
||||
|
||||
const VideosList = ({ className, metaResource, season, seasonOnSelect }) => {
|
||||
const VideosList = ({ className, metaCatalog, season, seasonOnSelect }) => {
|
||||
const videos = React.useMemo(() => {
|
||||
return metaResource && metaResource.content.type === 'Ready' ?
|
||||
metaResource.content.content.videos
|
||||
return metaCatalog && metaCatalog.content.type === 'Ready' ?
|
||||
metaCatalog.content.content.videos
|
||||
:
|
||||
[];
|
||||
}, [metaResource]);
|
||||
}, [metaCatalog]);
|
||||
const seasons = React.useMemo(() => {
|
||||
return videos
|
||||
.map(({ season }) => season)
|
||||
|
|
@ -52,7 +52,7 @@ const VideosList = ({ className, metaResource, season, seasonOnSelect }) => {
|
|||
return (
|
||||
<div className={classnames(className, styles['videos-list-container'])}>
|
||||
{
|
||||
!metaResource || metaResource.content.type === 'Loading' ?
|
||||
!metaCatalog || metaCatalog.content.type === 'Loading' ?
|
||||
<React.Fragment>
|
||||
<SeasonsBar.Placeholder className={styles['seasons-bar']} />
|
||||
<SearchBar.Placeholder className={styles['search-bar']} title={'Search videos'} />
|
||||
|
|
@ -65,7 +65,7 @@ const VideosList = ({ className, metaResource, season, seasonOnSelect }) => {
|
|||
</div>
|
||||
</React.Fragment>
|
||||
:
|
||||
metaResource.content.type === 'Err' || videosForSeason.length === 0 ?
|
||||
metaCatalog.content.type === 'Err' || videosForSeason.length === 0 ?
|
||||
<div className={styles['message-container']}>
|
||||
<Image className={styles['image']} src={'/images/empty.png'} alt={' '} />
|
||||
<div className={styles['label']}>No videos found for this meta!</div>
|
||||
|
|
@ -96,11 +96,23 @@ const VideosList = ({ className, metaResource, season, seasonOnSelect }) => {
|
|||
return search.length === 0 ||
|
||||
(
|
||||
(typeof video.title === 'string' && video.title.toLowerCase().includes(search.toLowerCase())) ||
|
||||
(video.released.toLocaleString(undefined, { year: '2-digit', month: 'short', day: 'numeric' }).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 {...video} key={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>
|
||||
|
|
@ -112,7 +124,7 @@ const VideosList = ({ className, metaResource, season, seasonOnSelect }) => {
|
|||
|
||||
VideosList.propTypes = {
|
||||
className: PropTypes.string,
|
||||
metaResource: PropTypes.object,
|
||||
metaCatalog: PropTypes.object,
|
||||
season: PropTypes.number,
|
||||
seasonOnSelect: PropTypes.func
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,111 +1,64 @@
|
|||
// Copyright (C) 2017-2020 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { CONSTANTS, deepLinking, useModelState } = require('stremio/common');
|
||||
const { useModelState } = require('stremio/common');
|
||||
|
||||
const initMetaDetailsState = () => ({
|
||||
const init = () => ({
|
||||
selected: null,
|
||||
meta_resources: [],
|
||||
streams_resources: []
|
||||
metaCatalog: null,
|
||||
streamsCatalogs: [],
|
||||
metaExtensions: []
|
||||
});
|
||||
|
||||
const mapMetaDetailsStateWithCtx = (meta_details, ctx) => {
|
||||
const selected = meta_details.selected;
|
||||
const meta_resources = meta_details.meta_resources.map((meta_resource) => {
|
||||
return meta_resource.content.type === 'Ready' ?
|
||||
{
|
||||
request: meta_resource.request,
|
||||
const map = (metaDetails) => ({
|
||||
...metaDetails,
|
||||
metaCatalog: metaDetails.metaCatalog !== null && metaDetails.metaCatalog.content.type === 'Ready' ?
|
||||
{
|
||||
...metaDetails.metaCatalog,
|
||||
content: {
|
||||
...metaDetails.metaCatalog.content,
|
||||
content: {
|
||||
type: 'Ready',
|
||||
content: {
|
||||
...meta_resource.content.content,
|
||||
...metaDetails.metaCatalog.content.content,
|
||||
released: new Date(
|
||||
typeof metaDetails.metaCatalog.content.content.released === 'string' ?
|
||||
metaDetails.metaCatalog.content.content.released
|
||||
:
|
||||
NaN
|
||||
),
|
||||
videos: metaDetails.metaCatalog.content.content.videos.map((video) => ({
|
||||
...video,
|
||||
released: new Date(
|
||||
typeof meta_resource.content.content.released === 'string' ?
|
||||
meta_resource.content.content.released
|
||||
typeof video.released === 'string' ?
|
||||
video.released
|
||||
:
|
||||
NaN
|
||||
),
|
||||
videos: meta_resource.content.content.videos.map((video) => ({
|
||||
...video,
|
||||
released: new Date(
|
||||
typeof video.released === 'string' ?
|
||||
video.released
|
||||
:
|
||||
NaN
|
||||
),
|
||||
upcoming: Date.parse(video.released) > Date.now(),
|
||||
// TODO add watched and progress
|
||||
deepLinks: deepLinking.withVideo({
|
||||
video,
|
||||
metaTransportUrl: meta_resource.request.base,
|
||||
metaItem: meta_resource.content.content
|
||||
})
|
||||
})),
|
||||
metaExtensions: meta_resource.content.content.links.filter((link) => link.category === CONSTANTS.META_LINK_CATEGORY)
|
||||
}
|
||||
},
|
||||
addon: ctx.profile.addons.reduce((result, addon) => {
|
||||
if (addon.transportUrl === meta_resource.request.base) {
|
||||
return addon;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, null)
|
||||
}
|
||||
:
|
||||
meta_resource;
|
||||
});
|
||||
const streams_resources = meta_details.streams_resources.map((stream_resource) => {
|
||||
return stream_resource.content.type === 'Ready' ?
|
||||
{
|
||||
request: stream_resource.request,
|
||||
content: {
|
||||
type: 'Ready',
|
||||
content: stream_resource.content.content.map((stream) => ({
|
||||
...stream,
|
||||
// TODO map progress
|
||||
deepLinks: deepLinking.withStream({
|
||||
stream,
|
||||
streamTransportUrl: stream_resource.request.base,
|
||||
// TODO metaTransportUrl should be based on state
|
||||
metaTransportUrl: meta_details.meta_resources.reduceRight((result, meta_resource) => {
|
||||
if (meta_resource.content.type === 'Ready') {
|
||||
return meta_resource.request.base;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, ''),
|
||||
type: selected.meta_resource_ref.type_name,
|
||||
id: selected.meta_resource_ref.id,
|
||||
videoId: selected.streams_resource_ref.id,
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
:
|
||||
stream_resource;
|
||||
});
|
||||
return { selected, meta_resources, streams_resources };
|
||||
};
|
||||
}
|
||||
:
|
||||
metaDetails.metaCatalog
|
||||
});
|
||||
|
||||
const useMetaDetails = (urlParams) => {
|
||||
const loadMetaDetailsAction = React.useMemo(() => {
|
||||
const action = React.useMemo(() => {
|
||||
if (typeof urlParams.type === 'string' && typeof urlParams.id === 'string') {
|
||||
return {
|
||||
action: 'Load',
|
||||
args: {
|
||||
model: 'MetaDetails',
|
||||
args: {
|
||||
meta_resource_ref: {
|
||||
metaPath: {
|
||||
resource: 'meta',
|
||||
type_name: urlParams.type,
|
||||
type: urlParams.type,
|
||||
id: urlParams.id,
|
||||
extra: []
|
||||
},
|
||||
streams_resource_ref: typeof urlParams.videoId === 'string' ?
|
||||
streamsPath: typeof urlParams.videoId === 'string' ?
|
||||
{
|
||||
resource: 'stream',
|
||||
type_name: urlParams.type,
|
||||
type: urlParams.type,
|
||||
id: urlParams.videoId,
|
||||
extra: []
|
||||
}
|
||||
|
|
@ -120,12 +73,7 @@ const useMetaDetails = (urlParams) => {
|
|||
};
|
||||
}
|
||||
}, [urlParams]);
|
||||
return useModelState({
|
||||
model: 'meta_details',
|
||||
action: loadMetaDetailsAction,
|
||||
mapWithCtx: mapMetaDetailsStateWithCtx,
|
||||
init: initMetaDetailsState
|
||||
});
|
||||
return useModelState({ model: 'meta_details', action, map, init });
|
||||
};
|
||||
|
||||
module.exports = useMetaDetails;
|
||||
|
|
|
|||
23
src/routes/MetaDetails/useMetaExtensionTabs.js
Normal file
23
src/routes/MetaDetails/useMetaExtensionTabs.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (C) 2017-2020 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
|
||||
const useMetaExtensionTabs = (metaExtensions) => {
|
||||
const tabs = React.useMemo(() => {
|
||||
return metaExtensions
|
||||
.map((extension) => ({
|
||||
id: extension.url,
|
||||
label: extension.addon.manifest.name,
|
||||
logo: extension.addon.manifest.logo,
|
||||
icon: 'ic_addons',
|
||||
onClick: () => setSelected(extension)
|
||||
}));
|
||||
}, [metaExtensions]);
|
||||
const [selected, setSelected] = React.useState(null);
|
||||
const clear = React.useCallback(() => {
|
||||
setSelected(null);
|
||||
}, []);
|
||||
return [tabs, selected, clear];
|
||||
};
|
||||
|
||||
module.exports = useMetaExtensionTabs;
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (C) 2017-2020 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
|
||||
const useMetaExtensions = (metaResources) => {
|
||||
const tabs = React.useMemo(() => {
|
||||
return metaResources.filter((metaResource) => metaResource.content.type === 'Ready' && metaResource.content.content.metaExtensions.length > 0 && metaResource.addon !== null)
|
||||
.map((metaResource) => {
|
||||
return metaResource.content.content.metaExtensions.map((metaExtension) => (
|
||||
{
|
||||
id: metaExtension.url,
|
||||
label: metaResource.addon.manifest.name,
|
||||
logo: metaResource.addon.manifest.logo,
|
||||
icon: 'ic_addons',
|
||||
onClick: () => { setSelectedMetaExtension(metaExtension); }
|
||||
}
|
||||
));
|
||||
})
|
||||
.flat(2)
|
||||
.filter((tab, index, tabs) => tabs.findIndex((_tab) => _tab.id === tab.id) === index);
|
||||
}, [metaResources]);
|
||||
const [selectedMetaExtension, setSelectedMetaExtension] = React.useState(null);
|
||||
const clearSelectedMetaExtension = React.useCallback(() => {
|
||||
setSelectedMetaExtension(null);
|
||||
}, []);
|
||||
return { tabs, selectedMetaExtension, clearSelectedMetaExtension };
|
||||
};
|
||||
|
||||
module.exports = useMetaExtensions;
|
||||
20
src/routes/MetaDetails/useSeason.js
Normal file
20
src/routes/MetaDetails/useSeason.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (C) 2017-2020 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
|
||||
const useSeason = (urlParams, queryParams) => {
|
||||
const season = React.useMemo(() => {
|
||||
return queryParams.has('season') && !isNaN(queryParams.get('season')) ?
|
||||
parseInt(queryParams.get('season'))
|
||||
:
|
||||
null;
|
||||
}, [queryParams]);
|
||||
const setSeason = React.useCallback((season) => {
|
||||
const nextQueryParams = new URLSearchParams(queryParams);
|
||||
nextQueryParams.set('season', season);
|
||||
window.location.replace(`#${urlParams.path}?${nextQueryParams}`);
|
||||
}, [urlParams, queryParams]);
|
||||
return [season, setSeason];
|
||||
};
|
||||
|
||||
module.exports = useSeason;
|
||||
Loading…
Reference in a new issue