import EmbyLogo from '@app/assets/services/emby.svg'; import JellyfinLogo from '@app/assets/services/jellyfin.svg'; import PlexLogo from '@app/assets/services/plex.svg'; import AppDataWarning from '@app/components/AppDataWarning'; import Button from '@app/components/Common/Button'; import ImageFader from '@app/components/Common/ImageFader'; import PageTitle from '@app/components/Common/PageTitle'; import LanguagePicker from '@app/components/Layout/LanguagePicker'; import SettingsJellyfin from '@app/components/Settings/SettingsJellyfin'; import SettingsPlex from '@app/components/Settings/SettingsPlex'; import SettingsServices from '@app/components/Settings/SettingsServices'; import SetupSteps from '@app/components/Setup/SetupSteps'; import useLocale from '@app/hooks/useLocale'; import useSettings from '@app/hooks/useSettings'; import defineMessages from '@app/utils/defineMessages'; import { MediaServerType } from '@server/constants/server'; import type { Library } from '@server/lib/settings'; import axios from 'axios'; import Image from 'next/image'; import { useRouter } from 'next/router'; import { useCallback, useEffect, useState } from 'react'; import { useIntl } from 'react-intl'; import { useToasts } from 'react-toast-notifications'; import useSWR, { mutate } from 'swr'; import SetupLogin from './SetupLogin'; const messages = defineMessages('components.Setup', { welcome: 'Welcome to Seerr', subtitle: 'Get started by choosing your media server', configjellyfin: 'Configure Jellyfin', configplex: 'Configure Plex', configemby: 'Configure Emby', setup: 'Setup', finish: 'Finish Setup', finishing: 'Finishing…', continue: 'Continue', servertype: 'Choose Server Type', signin: 'Sign In', configuremediaserver: 'Configure Media Server', configureservices: 'Configure Services', librarieserror: 'Validation failed. Please toggle the libraries again to continue.', }); const Setup = () => { const intl = useIntl(); const [isUpdating, setIsUpdating] = useState(false); const [currentStep, setCurrentStep] = useState(1); const [mediaServerSettingsComplete, setMediaServerSettingsComplete] = useState(false); const [mediaServerType, setMediaServerType] = useState( MediaServerType.NOT_CONFIGURED ); const router = useRouter(); const { locale } = useLocale(); const settings = useSettings(); const toasts = useToasts(); const finishSetup = async () => { setIsUpdating(true); const response = await axios.post<{ initialized: boolean }>( '/api/v1/settings/initialize' ); setIsUpdating(false); if (response.data.initialized) { await axios.post('/api/v1/settings/main', { locale }); mutate('/api/v1/settings/public'); router.push('/'); } }; const validateLibraries = useCallback(async () => { try { const endpointMap: Record = { [MediaServerType.JELLYFIN]: '/api/v1/settings/jellyfin', [MediaServerType.EMBY]: '/api/v1/settings/jellyfin', [MediaServerType.PLEX]: '/api/v1/settings/plex', [MediaServerType.NOT_CONFIGURED]: '', }; const endpoint = endpointMap[mediaServerType]; if (!endpoint) return; const response = await axios.get(endpoint); const hasEnabledLibraries = response.data?.libraries?.some( (library: Library) => library.enabled ); setMediaServerSettingsComplete(hasEnabledLibraries); } catch { toasts.addToast(intl.formatMessage(messages.librarieserror), { autoDismiss: true, appearance: 'error', }); setMediaServerSettingsComplete(false); } }, [intl, mediaServerType, toasts]); const { data: backdrops } = useSWR('/api/v1/backdrops', { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, }); useEffect(() => { if (settings.currentSettings.initialized) { router.push('/'); } if ( settings.currentSettings.mediaServerType !== MediaServerType.NOT_CONFIGURED ) { setMediaServerType(settings.currentSettings.mediaServerType); if (currentStep < 3) { setCurrentStep(3); } } }, [ settings.currentSettings.mediaServerType, settings.currentSettings.initialized, router, toasts, intl, currentStep, mediaServerType, validateLibraries, ]); useEffect(() => { if (currentStep === 3) { validateLibraries(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentStep]); const handleComplete = () => { validateLibraries(); }; if (settings.currentSettings.initialized) return <>; return (
`https://image.tmdb.org/t/p/original${backdrop}` ) ?? [] } />
Logo
{currentStep === 1 && (
{intl.formatMessage(messages.welcome)}
{intl.formatMessage(messages.subtitle)}
)} {currentStep === 2 && ( { setMediaServerType(MediaServerType.NOT_CONFIGURED); setCurrentStep(1); }} onComplete={() => setCurrentStep(3)} /> )} {currentStep === 3 && (
{mediaServerType === MediaServerType.PLEX ? ( ) : ( )}
)} {currentStep === 4 && (
)}
); }; export default Setup;