diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index af7105214..ca67ef1aa 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -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, }; diff --git a/src/common/externalPlayerOptions.js b/src/common/externalPlayerOptions.js deleted file mode 100644 index 1ff11aa6f..000000000 --- a/src/common/externalPlayerOptions.js +++ /dev/null @@ -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; diff --git a/src/common/index.js b/src/common/index.js index 3c9d7860b..ee4952918 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -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, }; diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index b6ab98b4e..ff6038d29 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -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(() => ( ), []); return ( - + { typeof thumbnail === 'string' && thumbnail.length > 0 ? @@ -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; diff --git a/src/routes/MetaDetails/StreamsList/StreamsList.js b/src/routes/MetaDetails/StreamsList/StreamsList.js index 853e337b3..81f3172ea 100644 --- a/src/routes/MetaDetails/StreamsList/StreamsList.js +++ b/src/routes/MetaDetails/StreamsList/StreamsList.js @@ -111,7 +111,6 @@ const StreamsList = ({ className, ...props }) => { thumbnail={stream.thumbnail} progress={stream.progress} deepLinks={stream.deepLinks} - onClick={stream.onClick} /> ))} diff --git a/src/routes/Settings/useProfileSettingsInputs.js b/src/routes/Settings/useProfileSettingsInputs.js index 8ba4e5b8e..8b0dc27dc 100644 --- a/src/routes/Settings/useProfileSettingsInputs.js +++ b/src/routes/Settings/useProfileSettingsInputs.js @@ -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, } } });