fix: add support for ssl when connecting to plex

fixes #275
This commit is contained in:
sct
2020-12-15 03:22:54 +00:00
parent f998873fc5
commit 3ba09d07eb
5 changed files with 165 additions and 110 deletions

View File

@@ -62,6 +62,7 @@ class PlexAPI {
this.plexClient = new NodePlexAPI({ this.plexClient = new NodePlexAPI({
hostname: settings.plex.ip, hostname: settings.plex.ip,
port: settings.plex.port, port: settings.plex.port,
https: settings.plex.useSsl,
token: plexToken, token: plexToken,
authenticator: { authenticator: {
authenticate: ( authenticate: (

View File

@@ -14,6 +14,7 @@ export interface PlexSettings {
machineId?: string; machineId?: string;
ip: string; ip: string;
port: number; port: number;
useSsl?: boolean;
libraries: Library[]; libraries: Library[];
} }
@@ -109,6 +110,7 @@ class Settings {
name: '', name: '',
ip: '127.0.0.1', ip: '127.0.0.1',
port: 32400, port: 32400,
useSsl: false,
libraries: [], libraries: [],
}, },
radarr: [], radarr: [],

View File

@@ -4,6 +4,7 @@ declare module 'plex-api' {
hostname: string; hostname: string;
port: number; port: number;
token?: string; token?: string;
https?: boolean;
authenticator: { authenticator: {
authenticate: ( authenticate: (
_plexApi: PlexAPI, _plexApi: PlexAPI,

View File

@@ -2,21 +2,23 @@ import React, { useState } from 'react';
import LoadingSpinner from '../Common/LoadingSpinner'; import LoadingSpinner from '../Common/LoadingSpinner';
import type { PlexSettings } from '../../../server/lib/settings'; import type { PlexSettings } from '../../../server/lib/settings';
import useSWR from 'swr'; import useSWR from 'swr';
import { useFormik } from 'formik'; import { Formik, Field } from 'formik';
import Button from '../Common/Button'; import Button from '../Common/Button';
import axios from 'axios'; import axios from 'axios';
import LibraryItem from './LibraryItem'; import LibraryItem from './LibraryItem';
import Badge from '../Common/Badge'; import Badge from '../Common/Badge';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import * as Yup from 'yup';
const messages = defineMessages({ const messages = defineMessages({
plexsettings: 'Plex Settings', plexsettings: 'Plex Settings',
plexsettingsDescription: 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.', '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)', servername: 'Server Name (Automatically set after you save)',
servernamePlaceholder: 'Plex Server Name', servernamePlaceholder: 'Plex Server Name',
hostname: 'Hostname/IP', hostname: 'Hostname/IP',
port: 'Port', port: 'Port',
ssl: 'SSL',
save: 'Save Changes', save: 'Save Changes',
saving: 'Saving...', saving: 'Saving...',
plexlibraries: 'Plex Libraries', plexlibraries: 'Plex Libraries',
@@ -32,6 +34,8 @@ const messages = defineMessages({
librariesRemaining: 'Libraries Remaining: {count}', librariesRemaining: 'Libraries Remaining: {count}',
startscan: 'Start Scan', startscan: 'Start Scan',
cancelscan: 'Cancel Scan', cancelscan: 'Cancel Scan',
validationHostnameRequired: 'You must provide a hostname/IP',
validationPortRequired: 'You must provide a port',
}); });
interface Library { interface Library {
@@ -64,33 +68,15 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
} }
); );
const [isSyncing, setIsSyncing] = useState(false); const [isSyncing, setIsSyncing] = useState(false);
const [isUpdating, setIsUpdating] = useState(false);
const [submitError, setSubmitError] = useState<string | null>(null); const [submitError, setSubmitError] = useState<string | null>(null);
const formik = useFormik({
initialValues: {
hostname: data?.ip,
port: data?.port,
},
enableReinitialize: true,
onSubmit: async (values) => {
setSubmitError(null);
setIsUpdating(true);
try {
await axios.post('/api/v1/settings/plex', {
ip: values.hostname,
port: Number(values.port),
} as PlexSettings);
revalidate(); const PlexSettingsSchema = Yup.object().shape({
if (onComplete) { hostname: Yup.string().required(
onComplete(); intl.formatMessage(messages.validationHostnameRequired)
} ),
} catch (e) { port: Yup.number().required(
setSubmitError(e.response.data.message); intl.formatMessage(messages.validationPortRequired)
} finally { ),
setIsUpdating(false);
}
},
}); });
const activeLibraries = const activeLibraries =
@@ -164,7 +150,42 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
<FormattedMessage {...messages.plexsettingsDescription} /> <FormattedMessage {...messages.plexsettingsDescription} />
</p> </p>
</div> </div>
<form onSubmit={formik.handleSubmit}> <Formik
initialValues={{
hostname: data?.ip,
port: data?.port,
useSsl: data?.useSsl,
}}
enableReinitialize
validationSchema={PlexSettingsSchema}
onSubmit={async (values) => {
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 (
<form onSubmit={handleSubmit}>
<div className="mt-6 sm:mt-5"> <div className="mt-6 sm:mt-5">
{submitError && ( {submitError && (
<div className="bg-red-700 text-white p-4 rounded-md mb-6"> <div className="bg-red-700 text-white p-4 rounded-md mb-6">
@@ -203,16 +224,17 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
</label> </label>
<div className="mt-1 sm:mt-0 sm:col-span-2"> <div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg flex rounded-md shadow-sm"> <div className="max-w-lg flex rounded-md shadow-sm">
<input <Field
type="text" type="text"
id="hostname" id="hostname"
name="hostname" name="hostname"
placeholder="127.0.0.1" placeholder="127.0.0.1"
value={formik.values.hostname}
onChange={formik.handleChange}
className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500" className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
/> />
</div> </div>
{errors.hostname && touched.hostname && (
<div className="text-red-500 mt-2">{errors.hostname}</div>
)}
</div> </div>
</div> </div>
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5"> <div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
@@ -224,24 +246,48 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
</label> </label>
<div className="mt-1 sm:mt-0 sm:col-span-2"> <div className="mt-1 sm:mt-0 sm:col-span-2">
<div className="max-w-lg rounded-md shadow-sm sm:max-w-xs"> <div className="max-w-lg rounded-md shadow-sm sm:max-w-xs">
<input <Field
type="text" type="text"
id="port" id="port"
name="port" name="port"
placeholder="32400" placeholder="32400"
value={formik.values.port}
onChange={formik.handleChange}
className="form-input block w-24 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500" className="form-input block w-24 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
/> />
</div> </div>
{errors.port && touched.port && (
<div className="text-red-500 mt-2">{errors.port}</div>
)}
</div> </div>
</div> </div>
</div> </div>
<div className="mt-6 sm:mt-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:border-t sm:border-gray-200 sm:pt-5">
<label
htmlFor="ssl"
className="block text-sm font-medium leading-5 text-gray-400 sm:mt-px sm:pt-2"
>
{intl.formatMessage(messages.ssl)}
</label>
<div className="mt-1 sm:mt-0 sm:col-span-2">
<Field
type="checkbox"
id="useSsl"
name="useSsl"
onChange={() => {
setFieldValue('useSsl', !values.useSsl);
}}
className="form-checkbox h-6 w-6 rounded-md text-indigo-600 transition duration-150 ease-in-out"
/>
</div>
</div>
<div className="mt-8 border-t border-gray-700 pt-5"> <div className="mt-8 border-t border-gray-700 pt-5">
<div className="flex justify-end"> <div className="flex justify-end">
<span className="ml-3 inline-flex rounded-md shadow-sm"> <span className="ml-3 inline-flex rounded-md shadow-sm">
<Button buttonType="primary" type="submit" disabled={isUpdating}> <Button
{isUpdating buttonType="primary"
type="submit"
disabled={isSubmitting}
>
{isSubmitting
? intl.formatMessage(messages.saving) ? intl.formatMessage(messages.saving)
: intl.formatMessage(messages.save)} : intl.formatMessage(messages.save)}
</Button> </Button>
@@ -249,6 +295,9 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
</div> </div>
</div> </div>
</form> </form>
);
}}
</Formik>
<div className="mt-10"> <div className="mt-10">
<h3 className="text-lg leading-6 font-medium text-gray-200"> <h3 className="text-lg leading-6 font-medium text-gray-200">
<FormattedMessage {...messages.plexlibraries} /> <FormattedMessage {...messages.plexlibraries} />

View File

@@ -210,7 +210,7 @@
"components.Settings.runnow": "Run Now", "components.Settings.runnow": "Run Now",
"components.Settings.save": "Save Changes", "components.Settings.save": "Save Changes",
"components.Settings.saving": "Saving...", "components.Settings.saving": "Saving...",
"components.Settings.servername": "Server Name (Automatically Set)", "components.Settings.servername": "Server Name (Automatically set after you save)",
"components.Settings.servernamePlaceholder": "Plex Server Name", "components.Settings.servernamePlaceholder": "Plex Server Name",
"components.Settings.sonarrSettingsDescription": "Set up your Sonarr connection below. You can have multiple, but only two active as defaults at any time (one for standard HD and one for 4K). Administrators can override which server is used for new requests.", "components.Settings.sonarrSettingsDescription": "Set up your Sonarr connection below. You can have multiple, but only two active as defaults at any time (one for standard HD and one for 4K). Administrators can override which server is used for new requests.",
"components.Settings.sonarrsettings": "Sonarr Settings", "components.Settings.sonarrsettings": "Sonarr Settings",
@@ -218,6 +218,8 @@
"components.Settings.startscan": "Start Scan", "components.Settings.startscan": "Start Scan",
"components.Settings.sync": "Sync Plex Libraries", "components.Settings.sync": "Sync Plex Libraries",
"components.Settings.syncing": "Syncing…", "components.Settings.syncing": "Syncing…",
"components.Settings.validationHostnameRequired": "You must provide a hostname/IP",
"components.Settings.validationPortRequired": "You must provide a port",
"components.Setup.configureplex": "Configure Plex", "components.Setup.configureplex": "Configure Plex",
"components.Setup.configureservices": "Configure Services", "components.Setup.configureservices": "Configure Services",
"components.Setup.continue": "Continue", "components.Setup.continue": "Continue",