import React, { useState } from 'react'; import LoadingSpinner from '../Common/LoadingSpinner'; import type { PlexSettings } from '../../../server/lib/settings'; import useSWR from 'swr'; import { Formik, Field } from 'formik'; import Button from '../Common/Button'; import axios from 'axios'; import LibraryItem from './LibraryItem'; import Badge from '../Common/Badge'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import * as Yup from 'yup'; const messages = defineMessages({ plexsettings: 'Plex Settings', plexsettingsDescription: 'Configure the settings for your Plex server. Overseerr uses your Plex server to scan your library at an interval and see what content is available.', servername: 'Server Name (Automatically set after you save)', servernamePlaceholder: 'Plex Server Name', hostname: 'Hostname/IP', port: 'Port', ssl: 'SSL', save: 'Save Changes', saving: 'Saving...', plexlibraries: 'Plex Libraries', plexlibrariesDescription: 'These are the libraries Overseerr will scan for titles. If you see no libraries listed, you will need to run at least one sync by clicking the button below. You must first configure and save your plex connection settings before you will be able to retrieve your libraries.', syncing: 'Syncing', sync: 'Sync Plex Libraries', manualscan: 'Manual Library Scan', manualscanDescription: "Normally, this will only be run once every 24 hours. Overseerr will check your Plex server's recently added more aggressively. If this is your first time configuring Plex, a one time full manual library scan is recommended!", notrunning: 'Not Running', currentlibrary: 'Current Library: {name}', librariesRemaining: 'Libraries Remaining: {count}', startscan: 'Start Scan', cancelscan: 'Cancel Scan', validationHostnameRequired: 'You must provide a hostname/IP', validationPortRequired: 'You must provide a port', }); interface Library { id: string; name: string; enabled: boolean; } interface SyncStatus { running: boolean; progress: number; total: number; currentLibrary: Library; libraries: Library[]; } interface SettingsPlexProps { onComplete?: () => void; } const SettingsPlex: React.FC = ({ onComplete }) => { const intl = useIntl(); const { data, error, revalidate } = useSWR( '/api/v1/settings/plex' ); const { data: dataSync, revalidate: revalidateSync } = useSWR( '/api/v1/settings/plex/sync', { refreshInterval: 1000, } ); const [isSyncing, setIsSyncing] = useState(false); const [submitError, setSubmitError] = useState(null); const PlexSettingsSchema = Yup.object().shape({ hostname: Yup.string().required( intl.formatMessage(messages.validationHostnameRequired) ), port: Yup.number().required( intl.formatMessage(messages.validationPortRequired) ), }); const activeLibraries = data?.libraries .filter((library) => library.enabled) .map((library) => library.id) ?? []; const syncLibraries = async () => { setIsSyncing(true); await axios.get('/api/v1/settings/plex/library', { params: { sync: true, enable: activeLibraries.length > 0 ? activeLibraries.join(',') : undefined, }, }); setIsSyncing(false); revalidate(); }; const startScan = async () => { await axios.get('/api/v1/settings/plex/sync', { params: { start: true, }, }); revalidateSync(); }; const cancelScan = async () => { await axios.get('/api/v1/settings/plex/sync', { params: { cancel: true, }, }); revalidateSync(); }; const toggleLibrary = async (libraryId: string) => { setIsSyncing(true); if (activeLibraries.includes(libraryId)) { await axios.get('/api/v1/settings/plex/library', { params: { enable: activeLibraries.length > 0 ? activeLibraries.filter((id) => id !== libraryId).join(',') : undefined, }, }); } else { await axios.get('/api/v1/settings/plex/library', { params: { enable: [...activeLibraries, libraryId].join(','), }, }); } setIsSyncing(false); revalidate(); }; if (!data && !error) { return ; } return ( <>

{ setSubmitError(null); try { await axios.post('/api/v1/settings/plex', { ip: values.hostname, port: Number(values.port), useSsl: values.useSsl, } as PlexSettings); revalidate(); if (onComplete) { onComplete(); } } catch (e) { setSubmitError(e.response.data.message); } }} > {({ errors, touched, values, handleSubmit, setFieldValue, isSubmitting, }) => { return (
{submitError && (
{submitError}
)}
{values.useSsl ? 'https://' : 'http://'}
{errors.hostname && touched.hostname && (
{errors.hostname}
)}
{errors.port && touched.port && (
{errors.port}
)}
{ setFieldValue('useSsl', !values.useSsl); }} className="w-6 h-6 text-indigo-600 transition duration-150 ease-in-out rounded-md form-checkbox" />
); }}

    {data?.libraries.map((library) => ( toggleLibrary(library.id)} /> ))}

{dataSync?.running && (
)}
{dataSync?.running ? `${dataSync.progress} of ${dataSync.total}` : 'Not running'}
{dataSync?.running && ( <>
library.id === dataSync.currentLibrary.id ) + 1 ).length, }} />
)}
{!dataSync?.running && ( )} {dataSync?.running && ( )}
); }; export default SettingsPlex;