mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-04-20 10:42:12 +00:00
refactor: improve logic related to open player streams
This commit is contained in:
parent
81de9803da
commit
4ce7ad21d5
6 changed files with 60 additions and 129 deletions
|
|
@ -39,6 +39,15 @@ const ICON_FOR_TYPE = new Map([
|
|||
['podcast', 'ic_podcast'],
|
||||
['other', 'ic_movies'],
|
||||
]);
|
||||
const EXTERNAL_PLAYERS = [
|
||||
{ id: null, name: 'EXTERNAL_PLAYER_DISABLED' },
|
||||
{ id: 'choose', name: 'EXTERNAL_PLAYER_ALLOW_CHOOSING', platforms: ['android'] },
|
||||
{ id: 'vlc', name: 'VLC', platforms: ['android', 'ios', 'windows', 'macos', 'linux'] },
|
||||
{ id: 'outplayer', name: 'Outplayer', platforms: ['ios'] },
|
||||
{ id: 'infuse', name: 'Infuse', platforms: ['ios'] },
|
||||
{ id: 'justplayer', name: 'Just Player', platforms: ['android'] },
|
||||
{ id: 'mxplayer', name: 'MX Player', platforms: ['android'] },
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
CHROMECAST_RECEIVER_APP_ID,
|
||||
|
|
@ -55,5 +64,6 @@ module.exports = {
|
|||
SHARE_LINK_CATEGORY,
|
||||
WRITERS_LINK_CATEGORY,
|
||||
TYPE_PRIORITIES,
|
||||
ICON_FOR_TYPE
|
||||
ICON_FOR_TYPE,
|
||||
EXTERNAL_PLAYERS,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright (C) 2017-2022 Smart code 203358507
|
||||
|
||||
const platform = require('./platform');
|
||||
|
||||
let options = [{ label: 'EXTERNAL_PLAYER_DISABLED', value: 'internal' }];
|
||||
|
||||
if (platform.name === 'ios') {
|
||||
options = options.concat([
|
||||
{ label: 'VLC', value: 'vlc' },
|
||||
{ label: 'Outplayer', value: 'outplayer' },
|
||||
{ label: 'Infuse', value: 'infuse' }
|
||||
]);
|
||||
} else if (platform.name === 'android') {
|
||||
options = options.concat([
|
||||
{ label: 'EXTERNAL_PLAYER_ALLOW_CHOOSING', value: 'choose' },
|
||||
{ label: 'VLC', value: 'vlc' },
|
||||
{ label: 'Just Player', value: 'justplayer' },
|
||||
{ label: 'MX Player', value: 'mxplayer' }
|
||||
]);
|
||||
} else if (['windows', 'macos', 'linux'].includes(platform.name)) {
|
||||
options = options.concat([
|
||||
{ label: 'VLC', value: 'vlc' }
|
||||
]);
|
||||
} else {
|
||||
options = options.concat([
|
||||
{ label: 'M3U Playlist', value: 'm3u' }
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = options;
|
||||
|
|
@ -41,7 +41,6 @@ const useProfile = require('./useProfile');
|
|||
const useStreamingServer = require('./useStreamingServer');
|
||||
const useTorrent = require('./useTorrent');
|
||||
const platform = require('./platform');
|
||||
const externalPlayerOptions = require('./externalPlayerOptions');
|
||||
|
||||
module.exports = {
|
||||
AddonDetailsModal,
|
||||
|
|
@ -88,5 +87,4 @@ module.exports = {
|
|||
useStreamingServer,
|
||||
useTorrent,
|
||||
platform,
|
||||
externalPlayerOptions,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,64 +4,45 @@ const React = require('react');
|
|||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const Icon = require('@stremio/stremio-icons/dom');
|
||||
const { Button, Image, PlayIconCircleCentered, useProfile, platform, useStreamingServer, useToast } = require('stremio/common');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { Button, Image, PlayIconCircleCentered, platform, useProfile, useToast } = require('stremio/common');
|
||||
const StreamPlaceholder = require('./StreamPlaceholder');
|
||||
const styles = require('./styles');
|
||||
|
||||
const Stream = ({ className, addonName, name, description, thumbnail, progress, deepLinks, ...props }) => {
|
||||
const profile = useProfile();
|
||||
const streamingServer = useStreamingServer();
|
||||
const Stream = ({ className, addonName, name, description, thumbnail, progress, deepLinks }) => {
|
||||
const { core } = useServices();
|
||||
const profile = useProfile();
|
||||
const toast = useToast();
|
||||
const href = React.useMemo(() => {
|
||||
const haveStreamingServer = streamingServer.settings !== null && streamingServer.settings.type === 'Ready';
|
||||
return deepLinks ?
|
||||
profile.settings.playerType && profile.settings.playerType !== 'internal' ?
|
||||
platform.isMobile() || !haveStreamingServer ?
|
||||
(deepLinks.externalPlayer.openPlayer || {})[platform.name] || deepLinks.externalPlayer.href
|
||||
: null
|
||||
:
|
||||
typeof deepLinks.player === 'string' ?
|
||||
deepLinks.player
|
||||
:
|
||||
null
|
||||
:
|
||||
null;
|
||||
}, [deepLinks, profile, streamingServer]);
|
||||
const onClick = React.useCallback((e) => {
|
||||
if (href === null) {
|
||||
// link does not lead to the player, it is expected to
|
||||
// open with local video player through the streaming server
|
||||
core.transport.dispatch({
|
||||
action: 'StreamingServer',
|
||||
args: {
|
||||
action: 'PlayOnDevice',
|
||||
const onClick = React.useCallback(() => {
|
||||
if (deepLinks.externalPlayer.openPlayer) {
|
||||
if (platform.isMobile() && deepLinks.externalPlayer.openPlayer[platform.name]) {
|
||||
window.location = deepLinks.externalPlayer.openPlayer[platform.name];
|
||||
toast.show({
|
||||
type: 'success',
|
||||
title: `Stream opened in ${profile.settings.playerType}`,
|
||||
timeout: 4000
|
||||
});
|
||||
} else if (typeof deepLinks.externalPlayer.streaming === 'string') {
|
||||
core.transport.dispatch({
|
||||
action: 'StreamingServer',
|
||||
args: {
|
||||
device: 'vlc',
|
||||
source: deepLinks.externalPlayer.streaming
|
||||
action: 'PlayOnDevice',
|
||||
args: {
|
||||
device: profile.settings.playerType,
|
||||
source: deepLinks.externalPlayer.streaming,
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (profile.settings.playerType === 'external') {
|
||||
toast.show({
|
||||
type: 'success',
|
||||
title: 'Stream opened in external player',
|
||||
timeout: 4000
|
||||
});
|
||||
});
|
||||
}
|
||||
} else if (typeof deepLinks.player === 'string') {
|
||||
window.location = deepLinks.player;
|
||||
}
|
||||
props.onClick(e);
|
||||
}, [href, deepLinks, props.onClick, profile, toast]);
|
||||
const forceDownload = React.useMemo(() => {
|
||||
// we only do this in one case to force the download
|
||||
// of a M3U playlist generated in the browser
|
||||
return href === deepLinks.externalPlayer.href ? deepLinks.externalPlayer.fileName : false;
|
||||
}, [href]);
|
||||
}, [deepLinks, profile.settings]);
|
||||
const renderThumbnailFallback = React.useCallback(() => (
|
||||
<Icon className={styles['placeholder-icon']} icon={'ic_broken_link'} />
|
||||
), []);
|
||||
return (
|
||||
<Button href={href} download={forceDownload} {...props} onClick={onClick} className={classnames(className, styles['stream-container'])} title={addonName}>
|
||||
<Button className={classnames(className, styles['stream-container'])} title={addonName} onClick={onClick}>
|
||||
{
|
||||
typeof thumbnail === 'string' && thumbnail.length > 0 ?
|
||||
<div className={styles['thumbnail-container']} title={name || addonName}>
|
||||
|
|
@ -107,52 +88,18 @@ Stream.propTypes = {
|
|||
fileName: PropTypes.string,
|
||||
streaming: PropTypes.string,
|
||||
openPlayer: PropTypes.shape({
|
||||
choose: {
|
||||
ios: PropTypes.string,
|
||||
android: PropTypes.string,
|
||||
windows: PropTypes.string,
|
||||
macos: PropTypes.string,
|
||||
linux: PropTypes.string
|
||||
},
|
||||
vlc: {
|
||||
ios: PropTypes.string,
|
||||
android: PropTypes.string,
|
||||
windows: PropTypes.string,
|
||||
macos: PropTypes.string,
|
||||
linux: PropTypes.string
|
||||
},
|
||||
outplayer: {
|
||||
ios: PropTypes.string,
|
||||
android: PropTypes.string,
|
||||
windows: PropTypes.string,
|
||||
macos: PropTypes.string,
|
||||
linux: PropTypes.string
|
||||
},
|
||||
infuse: {
|
||||
ios: PropTypes.string,
|
||||
android: PropTypes.string,
|
||||
windows: PropTypes.string,
|
||||
macos: PropTypes.string,
|
||||
linux: PropTypes.string
|
||||
},
|
||||
justplayer: {
|
||||
ios: PropTypes.string,
|
||||
android: PropTypes.string,
|
||||
windows: PropTypes.string,
|
||||
macos: PropTypes.string,
|
||||
linux: PropTypes.string
|
||||
},
|
||||
mxplayer: {
|
||||
ios: PropTypes.string,
|
||||
android: PropTypes.string,
|
||||
windows: PropTypes.string,
|
||||
macos: PropTypes.string,
|
||||
linux: PropTypes.string
|
||||
},
|
||||
ios: PropTypes.string,
|
||||
android: PropTypes.string,
|
||||
windows: PropTypes.string,
|
||||
macos: PropTypes.string,
|
||||
linux: PropTypes.string,
|
||||
tizen: PropTypes.string,
|
||||
webos: PropTypes.string,
|
||||
chromeos: PropTypes.string,
|
||||
roku: PropTypes.string,
|
||||
})
|
||||
})
|
||||
}),
|
||||
onClick: PropTypes.func
|
||||
};
|
||||
|
||||
module.exports = Stream;
|
||||
|
|
|
|||
|
|
@ -111,7 +111,6 @@ const StreamsList = ({ className, ...props }) => {
|
|||
thumbnail={stream.thumbnail}
|
||||
progress={stream.progress}
|
||||
deepLinks={stream.deepLinks}
|
||||
onClick={stream.onClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
const React = require('react');
|
||||
const { useTranslation } = require('react-i18next');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { CONSTANTS, interfaceLanguages, languageNames, externalPlayerOptions } = require('stremio/common');
|
||||
const { CONSTANTS, interfaceLanguages, languageNames, platform } = require('stremio/common');
|
||||
const { EXTERNAL_PLAYERS } = require('stremio/common/CONSTANTS');
|
||||
|
||||
const useProfileSettingsInputs = (profile) => {
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -158,11 +159,17 @@ const useProfileSettingsInputs = (profile) => {
|
|||
}
|
||||
}), [profile.settings]);
|
||||
const playInExternalPlayerSelect = React.useMemo(() => ({
|
||||
options: externalPlayerOptions.map((opt) => {
|
||||
opt.label = t(opt.label);
|
||||
return opt;
|
||||
}),
|
||||
selected: [`${profile.settings.playerType || 'internal'}`],
|
||||
options: EXTERNAL_PLAYERS
|
||||
.filter(({ platforms }) => !platforms || platforms.includes(platform.name))
|
||||
.map(({ id, name }) => ({
|
||||
value: id === null ? 'none' : id,
|
||||
label: t(name, { defaultValue: name }),
|
||||
})),
|
||||
selected: [profile.settings.playerType],
|
||||
renderLabelText: () => {
|
||||
const externalPlayer = EXTERNAL_PLAYERS.find(({ id }) => id === profile.settings.playerType);
|
||||
return externalPlayer ? t(externalPlayer.name, { defaultValue: externalPlayer.name }) : profile.settings.playerType;
|
||||
},
|
||||
onSelect: (event) => {
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
|
|
@ -170,7 +177,7 @@ const useProfileSettingsInputs = (profile) => {
|
|||
action: 'UpdateSettings',
|
||||
args: {
|
||||
...profile.settings,
|
||||
playerType: event.value
|
||||
playerType: event.value === 'none' ? null : event.value,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue