mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-20 19:02:15 +00:00
Merge pull request #170 from Stremio/addons-nav-bar
Addons nav bar update
This commit is contained in:
commit
42a16d3b6a
6 changed files with 97 additions and 63 deletions
|
|
@ -6,6 +6,7 @@ const CATALOG_PREVIEW_SIZE = 10;
|
|||
const CATALOG_PAGE_SIZE = 100;
|
||||
const NONE_EXTRA_VALUE = 'None';
|
||||
const SKIP_EXTRA_NAME = 'skip';
|
||||
const META_LINK_CATEGORY = 'meta';
|
||||
const IMDB_LINK_CATEGORY = 'imdb';
|
||||
const SHARE_LINK_CATEGORY = 'share';
|
||||
const TYPE_PRIORITIES = {
|
||||
|
|
@ -29,6 +30,7 @@ module.exports = {
|
|||
CATALOG_PAGE_SIZE,
|
||||
NONE_EXTRA_VALUE,
|
||||
SKIP_EXTRA_NAME,
|
||||
META_LINK_CATEGORY,
|
||||
IMDB_LINK_CATEGORY,
|
||||
SHARE_LINK_CATEGORY,
|
||||
TYPE_PRIORITIES
|
||||
|
|
|
|||
|
|
@ -23,17 +23,6 @@ const withMetaItem = ({ metaItem }) => {
|
|||
};
|
||||
};
|
||||
|
||||
const withMetaResource = ({ metaResource, type, id, videoId }) => {
|
||||
const queryParams = new URLSearchParams([['metaTransportUrl', metaResource.request.base]]);
|
||||
return {
|
||||
meta_details_videos: `#/metadetails/${encodeURIComponent(type)}/${encodeURIComponent(id)}?${queryParams.toString()}`,
|
||||
meta_details_streams: typeof videoId === 'string' ?
|
||||
`#/metadetails/${encodeURIComponent(type)}/${encodeURIComponent(id)}/${encodeURIComponent(videoId)}?${queryParams.toString()}`
|
||||
:
|
||||
null
|
||||
};
|
||||
};
|
||||
|
||||
const withLibItem = ({ libItem, streams = {} }) => {
|
||||
const [stream, streamTransportUrl, metaTransportUrl] = typeof libItem.state.video_id === 'string' && typeof streams[`${encodeURIComponent(libItem._id)}/${encodeURIComponent(libItem.state.video_id)}`] === 'object' ?
|
||||
streams[`${encodeURIComponent(libItem._id)}/${encodeURIComponent(libItem.state.video_id)}`]
|
||||
|
|
@ -60,13 +49,12 @@ const withLibItem = ({ libItem, streams = {} }) => {
|
|||
};
|
||||
|
||||
const withVideo = ({ video, metaTransportUrl, metaItem, streams = {} }) => {
|
||||
const queryParams = new URLSearchParams([['metaTransportUrl', metaTransportUrl]]);
|
||||
const [stream, streamTransportUrl] = typeof streams[`${encodeURIComponent(metaItem.id)}/${encodeURIComponent(video.id)}`] === 'object' ?
|
||||
streams[`${encodeURIComponent(metaItem.id)}/${encodeURIComponent(video.id)}`]
|
||||
:
|
||||
[];
|
||||
return {
|
||||
meta_details_streams: `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}/${encodeURIComponent(video.id)}?${queryParams.toString()}`,
|
||||
meta_details_streams: `#/metadetails/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}/${encodeURIComponent(video.id)}`,
|
||||
// TODO check if stream is external
|
||||
player: typeof stream === 'object' && typeof streamTransportUrl === 'string' ?
|
||||
`#/player/${encodeURIComponent(serializeStream(stream))}/${encodeURIComponent(streamTransportUrl)}/${encodeURIComponent(metaTransportUrl)}/${encodeURIComponent(metaItem.type)}/${encodeURIComponent(metaItem.id)}/${encodeURIComponent(video.id)}`
|
||||
|
|
@ -96,7 +84,6 @@ const withCatalog = ({ request }) => {
|
|||
module.exports = {
|
||||
withCatalog,
|
||||
withMetaItem,
|
||||
withMetaResource,
|
||||
withLibItem,
|
||||
withVideo,
|
||||
withStream,
|
||||
|
|
|
|||
|
|
@ -2,35 +2,32 @@
|
|||
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const { VerticalNavBar, HorizontalNavBar, MetaPreview, Image, useInLibrary } = require('stremio/common');
|
||||
const { VerticalNavBar, HorizontalNavBar, MetaPreview, ModalDialog, Image, useInLibrary } = require('stremio/common');
|
||||
const StreamsList = require('./StreamsList');
|
||||
const VideosList = require('./VideosList');
|
||||
const useMetaDetails = require('./useMetaDetails');
|
||||
const useMetaExtensions = require('./useMetaExtensions');
|
||||
const styles = require('./styles');
|
||||
|
||||
const MetaDetails = ({ urlParams, queryParams }) => {
|
||||
const MetaDetails = ({ urlParams }) => {
|
||||
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 selectedAddon = queryParams.get('metaTransportUrl');
|
||||
const selectedMetaResource = React.useMemo(() => {
|
||||
return metaDetails.meta_resources.reduceRight((result, metaResource) => {
|
||||
if (typeof selectedAddon === 'string') {
|
||||
if (metaResource.request.base === selectedAddon) {
|
||||
return metaResource;
|
||||
}
|
||||
} else if (metaResource.content.type === 'Ready') {
|
||||
if (metaResource.content.type === 'Ready') {
|
||||
return metaResource;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, null);
|
||||
}, [metaDetails, selectedAddon]);
|
||||
}, [metaDetails]);
|
||||
const streamsResourceRef = metaDetails.selected !== null ? metaDetails.selected.streams_resource_ref : null;
|
||||
const streamsResources = metaDetails.streams_resources;
|
||||
const selectedVideo = React.useMemo(() => {
|
||||
return streamsResourceRef !== null && selectedMetaResource !== null && selectedMetaResource.content.type === 'Ready' ?
|
||||
return streamsResourceRef !== null && selectedMetaResource !== null ?
|
||||
selectedMetaResource.content.content.videos.reduce((result, video) => {
|
||||
if (video.id === streamsResourceRef.id) {
|
||||
return video;
|
||||
|
|
@ -41,30 +38,21 @@ const MetaDetails = ({ urlParams, queryParams }) => {
|
|||
:
|
||||
null;
|
||||
}, [selectedMetaResource, streamsResourceRef]);
|
||||
const tabs = React.useMemo(() => {
|
||||
return metaDetails.meta_resources.map((metaResource) => ({
|
||||
id: metaResource.addon.transportUrl,
|
||||
label: metaResource.addon.manifest.name,
|
||||
logo: metaResource.addon.manifest.logo,
|
||||
icon: 'ic_addons',
|
||||
href: metaResource.deepLinks.meta_details_streams !== null ? metaResource.deepLinks.meta_details_streams : metaResource.deepLinks.meta_details_videos
|
||||
}));
|
||||
}, [metaDetails]);
|
||||
const [inLibrary, toggleInLibrary] = useInLibrary(selectedMetaResource !== null && selectedMetaResource.content.type === 'Ready' ? selectedMetaResource.content.content : null);
|
||||
const [inLibrary, toggleInLibrary] = useInLibrary(selectedMetaResource !== null ? selectedMetaResource.content.content : null);
|
||||
return (
|
||||
<div className={styles['metadetails-container']}>
|
||||
<HorizontalNavBar
|
||||
className={styles['nav-bar']}
|
||||
backButton={true}
|
||||
title={selectedMetaResource !== null && selectedMetaResource.content.type === 'Ready' ? selectedMetaResource.content.content.name : null}
|
||||
title={selectedMetaResource !== null ? selectedMetaResource.content.content.name : null}
|
||||
/>
|
||||
<div className={styles['metadetails-content']}>
|
||||
{
|
||||
metaDetails.meta_resources.length > 0 ?
|
||||
tabs.length > 0 ?
|
||||
<VerticalNavBar
|
||||
className={styles['vertical-nav-bar']}
|
||||
tabs={tabs}
|
||||
selected={selectedMetaResource !== null ? selectedMetaResource.request.base : null}
|
||||
selected={selectedMetaExtension !== null ? selectedMetaExtension.url : null}
|
||||
/>
|
||||
:
|
||||
null
|
||||
|
|
@ -88,7 +76,7 @@ const MetaDetails = ({ urlParams, queryParams }) => {
|
|||
<div className={styles['message-label']}>No metadata was found!</div>
|
||||
</div>
|
||||
:
|
||||
selectedMetaResource !== null && selectedMetaResource.content.type === 'Ready' ?
|
||||
selectedMetaResource !== null ?
|
||||
<React.Fragment>
|
||||
{
|
||||
typeof selectedMetaResource.content.content.background === 'string' &&
|
||||
|
|
@ -142,6 +130,21 @@ const MetaDetails = ({ urlParams, queryParams }) => {
|
|||
null
|
||||
}
|
||||
</div>
|
||||
{
|
||||
selectedMetaExtension !== null ?
|
||||
<ModalDialog
|
||||
className={styles['meta-extension-modal-container']}
|
||||
title={selectedMetaExtension.name}
|
||||
onCloseRequest={clearSelectedMetaExtension}>
|
||||
<iframe
|
||||
className={styles['meta-extension-modal-iframe']}
|
||||
sandbox={'allow-forms allow-scripts allow-same-origin'}
|
||||
src={selectedMetaExtension.url}
|
||||
/>
|
||||
</ModalDialog>
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@
|
|||
meta-info-container: meta-info-container;
|
||||
}
|
||||
|
||||
:import('~stremio/common/ModalDialog/styles.less') {
|
||||
modal-dialog-container: modal-dialog-container;
|
||||
title-modal-container: title-container;
|
||||
}
|
||||
|
||||
.metadetails-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -104,4 +109,20 @@
|
|||
background-color: @color-background-dark5-70;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.meta-extension-modal-container {
|
||||
.modal-dialog-container {
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
|
||||
.title-modal-container {
|
||||
max-height: 1.2em;
|
||||
}
|
||||
|
||||
.meta-extension-modal-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (C) 2017-2020 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { deepLinking, useModelState } = require('stremio/common');
|
||||
const { CONSTANTS, deepLinking, useModelState } = require('stremio/common');
|
||||
|
||||
const initMetaDetailsState = () => ({
|
||||
selected: null,
|
||||
|
|
@ -12,10 +12,10 @@ const initMetaDetailsState = () => ({
|
|||
const mapMetaDetailsStateWithCtx = (meta_details, ctx) => {
|
||||
const selected = meta_details.selected;
|
||||
const meta_resources = meta_details.meta_resources.map((meta_resource) => {
|
||||
return {
|
||||
request: meta_resource.request,
|
||||
content: meta_resource.content.type === 'Ready' ?
|
||||
{
|
||||
return meta_resource.content.type === 'Ready' ?
|
||||
{
|
||||
request: meta_resource.request,
|
||||
content: {
|
||||
type: 'Ready',
|
||||
content: {
|
||||
...meta_resource.content.content,
|
||||
|
|
@ -40,28 +40,20 @@ const mapMetaDetailsStateWithCtx = (meta_details, ctx) => {
|
|||
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;
|
||||
}
|
||||
}
|
||||
:
|
||||
meta_resource.content,
|
||||
deepLinks: meta_details.selected !== null ?
|
||||
deepLinking.withMetaResource({
|
||||
metaResource: meta_resource,
|
||||
type: meta_details.selected.meta_resource_ref.type_name,
|
||||
id: meta_details.selected.meta_resource_ref.id,
|
||||
videoId: meta_details.selected.streams_resource_ref !== null ? meta_details.selected.streams_resource_ref.id : null
|
||||
})
|
||||
:
|
||||
null,
|
||||
addon: ctx.profile.addons.reduce((result, addon) => {
|
||||
if (addon.transportUrl === meta_resource.request.base) {
|
||||
return addon;
|
||||
}
|
||||
|
||||
return result;
|
||||
}, null)
|
||||
};
|
||||
return result;
|
||||
}, null)
|
||||
}
|
||||
:
|
||||
meta_resource;
|
||||
});
|
||||
const streams_resources = meta_details.streams_resources.map((stream_resource) => {
|
||||
return stream_resource.content.type === 'Ready' ?
|
||||
|
|
|
|||
29
src/routes/MetaDetails/useMetaExtensions.js
Normal file
29
src/routes/MetaDetails/useMetaExtensions.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// 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;
|
||||
Loading…
Reference in a new issue