// Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); const classnames = require('classnames'); const throttle = require('lodash.throttle'); const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); const { useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); const { useProfile, usePlatform, useStreamingServer, withCoreSuspender, useToast } = require('stremio/common'); const { Button, ColorInput, MainNavBars, Multiselect, Toggle } = require('stremio/components'); const useProfileSettingsInputs = require('./useProfileSettingsInputs'); const useStreamingServerSettingsInputs = require('./useStreamingServerSettingsInputs'); const useDataExport = require('./useDataExport'); const styles = require('./styles'); const { default: URLsManager } = require('./URLsManager/URLsManager'); const GENERAL_SECTION = 'general'; const PLAYER_SECTION = 'player'; const STREAMING_SECTION = 'streaming'; const SHORTCUTS_SECTION = 'shortcuts'; const Settings = () => { const { t } = useTranslation(); const { core, shell } = useServices(); const { routeFocused } = useRouteFocused(); const profile = useProfile(); const [dataExport, loadDataExport] = useDataExport(); const streamingServer = useStreamingServer(); const platform = usePlatform(); const toast = useToast(); const { interfaceLanguageSelect, hideSpoilersToggle, subtitlesLanguageSelect, subtitlesSizeSelect, subtitlesTextColorInput, subtitlesBackgroundColorInput, subtitlesOutlineColorInput, audioLanguageSelect, surroundSoundToggle, seekTimeDurationSelect, seekShortTimeDurationSelect, escExitFullscreenToggle, quitOnCloseToggle, playInExternalPlayerSelect, nextVideoPopupDurationSelect, bingeWatchingToggle, playInBackgroundToggle, hardwareDecodingToggle, } = useProfileSettingsInputs(profile); const { streamingServerRemoteUrlInput, remoteEndpointSelect, cacheSizeSelect, torrentProfileSelect, transcodingProfileSelect, } = useStreamingServerSettingsInputs(streamingServer); const [traktAuthStarted, setTraktAuthStarted] = React.useState(false); const isTraktAuthenticated = React.useMemo(() => { return profile.auth !== null && profile.auth.user !== null && profile.auth.user.trakt !== null && (Date.now() / 1000) < (profile.auth.user.trakt.created_at + profile.auth.user.trakt.expires_in); }, [profile.auth]); const logoutButtonOnClick = React.useCallback(() => { core.transport.dispatch({ action: 'Ctx', args: { action: 'Logout' } }); }, []); const toggleTraktOnClick = React.useCallback(() => { if (!isTraktAuthenticated && profile.auth !== null && profile.auth.user !== null && typeof profile.auth.user._id === 'string') { platform.openExternal(`https://www.strem.io/trakt/auth/${profile.auth.user._id}`); setTraktAuthStarted(true); } else { core.transport.dispatch({ action: 'Ctx', args: { action: 'LogoutTrakt' } }); } }, [isTraktAuthenticated, profile.auth]); const subscribeCalendarOnClick = React.useCallback(() => { if (!profile.auth) return; const protocol = platform.name === 'ios' ? 'webcal' : 'https'; const url = `${protocol}://www.strem.io/calendar/${profile.auth.user._id}.ics`; platform.openExternal(url); toast.show({ type: 'success', title: platform.name === 'ios' ? t('SETTINGS_SUBSCRIBE_CALENDAR_IOS_TOAST') : t('SETTINGS_SUBSCRIBE_CALENDAR_TOAST'), timeout: 25000 }); // Stremio 4 emits not documented event subscribeCalendar }, [profile.auth]); const exportDataOnClick = React.useCallback(() => { loadDataExport(); }, []); const onCopyRemoteUrlClick = React.useCallback(() => { if (streamingServer.remoteUrl) { navigator.clipboard.writeText(streamingServer.remoteUrl); toast.show({ type: 'success', title: t('SETTINGS_REMOTE_URL_COPIED'), timeout: 2500, }); } }, [streamingServer.remoteUrl]); const sectionsContainerRef = React.useRef(null); const generalSectionRef = React.useRef(null); const playerSectionRef = React.useRef(null); const streamingServerSectionRef = React.useRef(null); const shortcutsSectionRef = React.useRef(null); const sections = React.useMemo(() => ([ { ref: generalSectionRef, id: GENERAL_SECTION }, { ref: playerSectionRef, id: PLAYER_SECTION }, { ref: streamingServerSectionRef, id: STREAMING_SECTION }, { ref: shortcutsSectionRef, id: SHORTCUTS_SECTION }, ]), []); const [selectedSectionId, setSelectedSectionId] = React.useState(GENERAL_SECTION); const updateSelectedSectionId = React.useCallback(() => { if (sectionsContainerRef.current.scrollTop + sectionsContainerRef.current.clientHeight >= sectionsContainerRef.current.scrollHeight - 50) { setSelectedSectionId(sections[sections.length - 1].id); } else { for (let i = sections.length - 1; i >= 0; i--) { if (sections[i].ref.current.offsetTop - sectionsContainerRef.current.offsetTop <= sectionsContainerRef.current.scrollTop) { setSelectedSectionId(sections[i].id); break; } } } }, []); const sideMenuButtonOnClick = React.useCallback((event) => { const section = sections.find((section) => { return section.id === event.currentTarget.dataset.section; }); sectionsContainerRef.current.scrollTo({ top: section.ref.current.offsetTop - sectionsContainerRef.current.offsetTop, behavior: 'smooth' }); }, []); const sectionsContainerOnScroll = React.useCallback(throttle(() => { updateSelectedSectionId(); }, 50), []); React.useEffect(() => { if (isTraktAuthenticated && traktAuthStarted) { core.transport.dispatch({ action: 'Ctx', args: { action: 'InstallTraktAddon' } }); setTraktAuthStarted(false); } }, [isTraktAuthenticated, traktAuthStarted]); React.useEffect(() => { if (dataExport.exportUrl !== null && typeof dataExport.exportUrl === 'string') { platform.openExternal(dataExport.exportUrl); } }, [dataExport.exportUrl]); React.useLayoutEffect(() => { if (routeFocused) { updateSelectedSectionId(); } }, [routeFocused]); return (
App Version: {process.env.VERSION}
Build Version: {process.env.COMMIT_HASH}
{ streamingServer.settings !== null && streamingServer.settings.type === 'Ready' ?
Server Version: {streamingServer.settings.content.serverVersion}
: null } { typeof shell?.transport?.props?.shellVersion === 'string' ?
Shell Version: {shell.transport.props.shellVersion}
: null }
{profile.auth === null ? 'Anonymous user' : profile.auth.user.email}
{ profile.auth !== null ? : null }
{ profile.auth === null ?
: null }
{ profile.auth ? : null }
{ profile.auth !== null && profile.auth.user !== null && typeof profile.auth.user._id === 'string' ?
: null }
{ profile.auth !== null && profile.auth.user !== null ?
: null } { profile.auth !== null && profile.auth.user !== null && typeof profile.auth.user.email === 'string' ?
: null }
Trakt Scrobbling
{ t('SETTINGS_UI_LANGUAGE') }
{ shell.active &&
{ t('SETTINGS_QUIT_ON_CLOSE') }
}
{ t('SETTINGS_BLUR_UNWATCHED_IMAGE') }
{ t('SETTINGS_NAV_PLAYER') }
{t('SETTINGS_CLOSE_WINDOW')}
{ t('SETTINGS_SUBTITLES_LANGUAGE') }
{ shell.active ?
{ t('SETTINGS_FULLSCREEN_EXIT') }
: null }
{ t('SETTINGS_SUBTITLES_SIZE') }
{ t('SETTINGS_SUBTITLES_COLOR') }
{ t('SETTINGS_SUBTITLES_COLOR_BACKGROUND') }
{ t('SETTINGS_SUBTITLES_COLOR_OUTLINE') }
{t('SETTINGS_SECTION_AUDIO')}
{ t('SETTINGS_DEFAULT_AUDIO_TRACK') }
{ t('SETTINGS_SURROUND_SOUND') }
{t('SETTINGS_SECTION_CONTROLS')}
{ t('SETTINGS_SEEK_KEY') }
{ t('SETTINGS_SEEK_KEY_SHIFT') }
{ t('SETTINGS_PLAY_IN_BACKGROUND') }
{t('SETTINGS_SECTION_AUTO_PLAY')}
{ t('AUTO_PLAY') }
{ t('SETTINGS_NEXT_VIDEO_POPUP_DURATION') }
{t('SETTINGS_SECTION_ADVANCED')}
{ t('SETTINGS_PLAY_IN_EXTERNAL_PLAYER') }
{ shell.active &&
{ t('SETTINGS_HWDEC') }
}
{ t('SETTINGS_NAV_STREAMING') }
{ streamingServerRemoteUrlInput.value !== null ?
{t('SETTINGS_REMOTE_URL')}
{streamingServerRemoteUrlInput.value}
: null } { profile.auth !== null && profile.auth.user !== null && remoteEndpointSelect !== null ?
{ t('SETTINGS_HTTPS_ENDPOINT') }
: null } { cacheSizeSelect !== null ?
{ t('SETTINGS_SERVER_CACHE_SIZE') }
: null } { torrentProfileSelect !== null ?
{ t('SETTINGS_SERVER_TORRENT_PROFILE') }
: null } { transcodingProfileSelect !== null ?
{ t('SETTINGS_TRANSCODE_PROFILE') }
: null }
{ t('SETTINGS_NAV_SHORTCUTS') }
{ t('SETTINGS_SHORTCUT_PLAY_PAUSE') }
{ t('SETTINGS_SHORTCUT_SPACE') }
{ t('SETTINGS_SHORTCUT_SEEK_FORWARD') }
{ t('SETTINGS_SHORTCUT_OR') }
⇧ { t('SETTINGS_SHORTCUT_SHIFT') }
+
{ t('SETTINGS_SHORTCUT_SEEK_BACKWARD') }
{ t('SETTINGS_SHORTCUT_OR') }
⇧ { t('SETTINGS_SHORTCUT_SHIFT') }
+
{ t('SETTINGS_SHORTCUT_VOLUME_UP') }
{ t('SETTINGS_SHORTCUT_VOLUME_DOWN') }
{ t('SETTINGS_SHORTCUT_MENU_SUBTITLES') }
S
{ t('SETTINGS_SHORTCUT_MENU_AUDIO') }
A
{ t('SETTINGS_SHORTCUT_MENU_INFO') }
I
{ t('SETTINGS_SHORTCUT_MENU_VIDEOS') }
V
{ t('SETTINGS_SHORTCUT_FULLSCREEN') }
F
{ t('SETTINGS_SHORTCUT_NAVIGATE_MENUS') }
1
{ t('SETTINGS_SHORTCUT_TO') }
6
{ t('SETTINGS_SHORTCUT_GO_TO_SEARCH') }
0
{ t('SETTINGS_SHORTCUT_EXIT_BACK') }
{ t('SETTINGS_SHORTCUT_ESC') }
App Version
{process.env.VERSION}
Build Version
{process.env.COMMIT_HASH}
{ streamingServer.settings !== null && streamingServer.settings.type === 'Ready' ?
Server Version
{streamingServer.settings.content.serverVersion}
: null } { typeof shell?.transport?.props?.shellVersion === 'string' ?
Shell Version
{ shell.transport.props.shellVersion }
: null }
); }; const SettingsFallback = () => ( ); module.exports = withCoreSuspender(Settings, SettingsFallback);