mirror of
https://github.com/seerr-team/seerr.git
synced 2026-06-15 11:59:11 -04:00
feat(settings): make code more dry
This commit is contained in:
@@ -2303,6 +2303,16 @@ paths:
|
||||
summary: Switch media server
|
||||
tags:
|
||||
- settings
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
targetServerType:
|
||||
type: string
|
||||
enum: [jellyfin, emby, plex]
|
||||
description: Target media server type. Required when switching from Plex (jellyfin or emby) or from Jellyfin/Emby (plex, jellyfin, or emby).
|
||||
responses:
|
||||
'200':
|
||||
description: Media server cleared
|
||||
|
||||
@@ -60,7 +60,6 @@ authRoutes.post('/plex', async (req, res, next) => {
|
||||
|
||||
const mediaServerType = settings.main.mediaServerType;
|
||||
|
||||
// When main server is Jellyfin/Emby, allow admin to store Plex token for settings (linking)
|
||||
if (
|
||||
mediaServerType === MediaServerType.JELLYFIN ||
|
||||
mediaServerType === MediaServerType.EMBY
|
||||
|
||||
@@ -451,6 +451,27 @@ settingsRoutes.post('/jellyfin/sync', (req, res) => {
|
||||
return res.status(200).json(jellyfinFullScanner.status());
|
||||
});
|
||||
|
||||
const EMPTY_PLEX_SETTINGS = {
|
||||
name: '',
|
||||
ip: '',
|
||||
port: 32400,
|
||||
useSsl: false,
|
||||
libraries: [] as never[],
|
||||
};
|
||||
|
||||
const EMPTY_JELLYFIN_SETTINGS = {
|
||||
name: '',
|
||||
ip: '',
|
||||
port: 8096,
|
||||
useSsl: false,
|
||||
urlBase: '',
|
||||
externalHostname: '',
|
||||
jellyfinForgotPasswordUrl: '',
|
||||
libraries: [] as never[],
|
||||
serverId: '',
|
||||
apiKey: '',
|
||||
};
|
||||
|
||||
settingsRoutes.post(
|
||||
'/switch-media-server',
|
||||
isAuthenticated(Permission.ADMIN),
|
||||
@@ -458,12 +479,14 @@ settingsRoutes.post(
|
||||
const settings = getSettings();
|
||||
const current = settings.main.mediaServerType;
|
||||
const body = (req.body as { targetServerType?: string }) ?? {};
|
||||
const target = body.targetServerType;
|
||||
|
||||
if (current === MediaServerType.NOT_CONFIGURED) {
|
||||
return res.status(400).json({
|
||||
error: 'No media server is configured.',
|
||||
});
|
||||
}
|
||||
const target = body.targetServerType;
|
||||
|
||||
if (current === MediaServerType.PLEX) {
|
||||
if (target !== 'jellyfin' && target !== 'emby') {
|
||||
return res.status(400).json({
|
||||
@@ -502,26 +525,20 @@ settingsRoutes.post(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (current === MediaServerType.PLEX) {
|
||||
const useEmby = body.targetServerType === 'emby';
|
||||
const useEmby = target === 'emby';
|
||||
settings.main.mediaServerType = useEmby
|
||||
? MediaServerType.EMBY
|
||||
: MediaServerType.JELLYFIN;
|
||||
settings.plex = {
|
||||
name: '',
|
||||
ip: '',
|
||||
port: 32400,
|
||||
useSsl: false,
|
||||
libraries: [],
|
||||
};
|
||||
const userRepository = getRepository(User);
|
||||
await userRepository
|
||||
settings.plex = { ...EMPTY_PLEX_SETTINGS };
|
||||
await getRepository(User)
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({ plexId: null, plexUsername: null, plexToken: null })
|
||||
.execute();
|
||||
await userRepository
|
||||
await getRepository(User)
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({
|
||||
@@ -529,15 +546,13 @@ settingsRoutes.post(
|
||||
})
|
||||
.where('user.jellyfinUserId IS NOT NULL')
|
||||
.execute();
|
||||
const mediaRepository = getRepository(Media);
|
||||
await mediaRepository
|
||||
await getRepository(Media)
|
||||
.createQueryBuilder()
|
||||
.update(Media)
|
||||
.set({ ratingKey: null, ratingKey4k: null })
|
||||
.where('media.ratingKey IS NOT NULL OR media.ratingKey4k IS NOT NULL')
|
||||
.execute();
|
||||
const watchlistRepository = getRepository(Watchlist);
|
||||
await watchlistRepository
|
||||
await getRepository(Watchlist)
|
||||
.createQueryBuilder()
|
||||
.update(Watchlist)
|
||||
.set({ ratingKey: '' })
|
||||
@@ -555,184 +570,81 @@ settingsRoutes.post(
|
||||
? 'Switched to Emby. All users have been logged out. Restart the server, then sign in with the new media server.'
|
||||
: 'Switched to Jellyfin. All users have been logged out. Restart the server, then sign in with the new media server.',
|
||||
});
|
||||
} else if (
|
||||
}
|
||||
|
||||
if (
|
||||
current === MediaServerType.JELLYFIN ||
|
||||
current === MediaServerType.EMBY
|
||||
) {
|
||||
const targetJellyfinType = body.targetServerType;
|
||||
const switchToJellyfin = targetJellyfinType === 'jellyfin';
|
||||
const switchToEmby = targetJellyfinType === 'emby';
|
||||
const switchToPlex = targetJellyfinType === 'plex';
|
||||
const newType =
|
||||
target === 'plex'
|
||||
? MediaServerType.PLEX
|
||||
: target === 'emby'
|
||||
? MediaServerType.EMBY
|
||||
: MediaServerType.JELLYFIN;
|
||||
const newUserType =
|
||||
target === 'plex'
|
||||
? UserType.PLEX
|
||||
: target === 'emby'
|
||||
? UserType.EMBY
|
||||
: UserType.JELLYFIN;
|
||||
const serverName =
|
||||
target === 'plex' ? 'Plex' : target === 'emby' ? 'Emby' : 'Jellyfin';
|
||||
|
||||
if (switchToJellyfin && current !== MediaServerType.JELLYFIN) {
|
||||
// Emby => Jellyfin
|
||||
settings.main.mediaServerType = MediaServerType.JELLYFIN;
|
||||
settings.jellyfin = {
|
||||
name: '',
|
||||
ip: '',
|
||||
port: 8096,
|
||||
useSsl: false,
|
||||
urlBase: '',
|
||||
externalHostname: '',
|
||||
jellyfinForgotPasswordUrl: '',
|
||||
libraries: [],
|
||||
serverId: '',
|
||||
apiKey: '',
|
||||
};
|
||||
const userRepository = getRepository(User);
|
||||
await userRepository
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({
|
||||
jellyfinUserId: null,
|
||||
jellyfinUsername: null,
|
||||
jellyfinAuthToken: null,
|
||||
jellyfinDeviceId: null,
|
||||
})
|
||||
.execute();
|
||||
await userRepository
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({ userType: UserType.JELLYFIN })
|
||||
.where('user.jellyfinUserId IS NOT NULL')
|
||||
.execute();
|
||||
const mediaRepository = getRepository(Media);
|
||||
await mediaRepository
|
||||
.createQueryBuilder()
|
||||
.update(Media)
|
||||
.set({ jellyfinMediaId: null, jellyfinMediaId4k: null })
|
||||
.where(
|
||||
'media.jellyfinMediaId IS NOT NULL OR media.jellyfinMediaId4k IS NOT NULL'
|
||||
)
|
||||
.execute();
|
||||
await settings.save();
|
||||
await getRepository(Session)
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.from(Session)
|
||||
.execute();
|
||||
startJobs();
|
||||
return res.status(200).json({
|
||||
message:
|
||||
'Switched to Jellyfin. All users have been logged out. Restart the server, then reconfigure and sign in with the new media server.',
|
||||
if (
|
||||
(target === 'jellyfin' && current === MediaServerType.JELLYFIN) ||
|
||||
(target === 'emby' && current === MediaServerType.EMBY)
|
||||
) {
|
||||
return res.status(400).json({
|
||||
error: `Already using ${serverName}. Choose a different target.`,
|
||||
});
|
||||
}
|
||||
|
||||
if (switchToEmby && current !== MediaServerType.EMBY) {
|
||||
// Jellyfin => Emby
|
||||
settings.main.mediaServerType = MediaServerType.EMBY;
|
||||
settings.jellyfin = {
|
||||
name: '',
|
||||
ip: '',
|
||||
port: 8096,
|
||||
useSsl: false,
|
||||
urlBase: '',
|
||||
externalHostname: '',
|
||||
jellyfinForgotPasswordUrl: '',
|
||||
libraries: [],
|
||||
serverId: '',
|
||||
apiKey: '',
|
||||
};
|
||||
const userRepository = getRepository(User);
|
||||
await userRepository
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({
|
||||
jellyfinUserId: null,
|
||||
jellyfinUsername: null,
|
||||
jellyfinAuthToken: null,
|
||||
jellyfinDeviceId: null,
|
||||
})
|
||||
.execute();
|
||||
await userRepository
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({ userType: UserType.EMBY })
|
||||
.execute();
|
||||
const mediaRepository = getRepository(Media);
|
||||
await mediaRepository
|
||||
.createQueryBuilder()
|
||||
.update(Media)
|
||||
.set({ jellyfinMediaId: null, jellyfinMediaId4k: null })
|
||||
.where(
|
||||
'media.jellyfinMediaId IS NOT NULL OR media.jellyfinMediaId4k IS NOT NULL'
|
||||
)
|
||||
.execute();
|
||||
await settings.save();
|
||||
await getRepository(Session)
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.from(Session)
|
||||
.execute();
|
||||
startJobs();
|
||||
return res.status(200).json({
|
||||
message:
|
||||
'Switched to Emby. All users have been logged out. Restart the server, then reconfigure and sign in with the new media server.',
|
||||
});
|
||||
}
|
||||
settings.main.mediaServerType = newType;
|
||||
settings.jellyfin = { ...EMPTY_JELLYFIN_SETTINGS };
|
||||
await getRepository(User)
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({
|
||||
jellyfinUserId: null,
|
||||
jellyfinUsername: null,
|
||||
jellyfinAuthToken: null,
|
||||
jellyfinDeviceId: null,
|
||||
})
|
||||
.execute();
|
||||
await getRepository(User)
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({ userType: newUserType })
|
||||
.execute();
|
||||
await getRepository(Media)
|
||||
.createQueryBuilder()
|
||||
.update(Media)
|
||||
.set({ jellyfinMediaId: null, jellyfinMediaId4k: null })
|
||||
.where(
|
||||
'media.jellyfinMediaId IS NOT NULL OR media.jellyfinMediaId4k IS NOT NULL'
|
||||
)
|
||||
.execute();
|
||||
await settings.save();
|
||||
await getRepository(Session)
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.from(Session)
|
||||
.execute();
|
||||
startJobs();
|
||||
|
||||
if (switchToPlex) {
|
||||
// Jellyfin/Emby => Plex
|
||||
settings.main.mediaServerType = MediaServerType.PLEX;
|
||||
settings.jellyfin = {
|
||||
name: '',
|
||||
ip: '',
|
||||
port: 8096,
|
||||
useSsl: false,
|
||||
urlBase: '',
|
||||
externalHostname: '',
|
||||
jellyfinForgotPasswordUrl: '',
|
||||
libraries: [],
|
||||
serverId: '',
|
||||
apiKey: '',
|
||||
};
|
||||
const userRepository = getRepository(User);
|
||||
await userRepository
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({
|
||||
jellyfinUserId: null,
|
||||
jellyfinUsername: null,
|
||||
jellyfinAuthToken: null,
|
||||
jellyfinDeviceId: null,
|
||||
})
|
||||
.execute();
|
||||
await userRepository
|
||||
.createQueryBuilder()
|
||||
.update(User)
|
||||
.set({ userType: UserType.PLEX })
|
||||
.execute();
|
||||
const mediaRepository = getRepository(Media);
|
||||
await mediaRepository
|
||||
.createQueryBuilder()
|
||||
.update(Media)
|
||||
.set({ jellyfinMediaId: null, jellyfinMediaId4k: null })
|
||||
.where(
|
||||
'media.jellyfinMediaId IS NOT NULL OR media.jellyfinMediaId4k IS NOT NULL'
|
||||
)
|
||||
.execute();
|
||||
await settings.save();
|
||||
await getRepository(Session)
|
||||
.createQueryBuilder()
|
||||
.delete()
|
||||
.from(Session)
|
||||
.execute();
|
||||
startJobs();
|
||||
return res.status(200).json({
|
||||
message:
|
||||
'Switched to Plex. All users have been logged out. Restart the server, then sign in with the new media server.',
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(400).json({
|
||||
error:
|
||||
'Specify targetServerType: "plex", "jellyfin", or "emby" to switch media server.',
|
||||
const reconfigure =
|
||||
target === 'jellyfin' || target === 'emby'
|
||||
? ' Restart the server, then reconfigure and sign in with the new media server.'
|
||||
: ' Restart the server, then sign in with the new media server.';
|
||||
return res.status(200).json({
|
||||
message: `Switched to ${serverName}. All users have been logged out.${reconfigure}`,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error('Switch media server failed', {
|
||||
label: 'Settings',
|
||||
errorMessage: e.message,
|
||||
errorMessage: (e as Error).message,
|
||||
});
|
||||
return next({ status: 500, message: 'Failed to switch media server.' });
|
||||
}
|
||||
|
||||
@@ -16,6 +16,14 @@ import useSWR from 'swr';
|
||||
|
||||
type SwitchTargetServerType = 'jellyfin' | 'emby' | 'plex';
|
||||
|
||||
function getTargetLabel(target: SwitchTargetServerType): string {
|
||||
return target === 'plex'
|
||||
? 'Plex'
|
||||
: target === 'jellyfin'
|
||||
? 'Jellyfin'
|
||||
: 'Emby';
|
||||
}
|
||||
|
||||
const messages = defineMessages('components.Settings', {
|
||||
switchMediaServerError:
|
||||
'Something went wrong while switching media server. Please try again.',
|
||||
@@ -49,6 +57,43 @@ const messages = defineMessages('components.Settings', {
|
||||
checkUsersLink: 'Users',
|
||||
});
|
||||
|
||||
type StepsVariant = 'plex' | 'jellyfinEmbyToPlex' | 'jellyfinEmbyToOther';
|
||||
|
||||
const STEP_KEYS: Record<
|
||||
StepsVariant,
|
||||
[
|
||||
keyof typeof messages,
|
||||
keyof typeof messages,
|
||||
keyof typeof messages,
|
||||
keyof typeof messages,
|
||||
]
|
||||
> = {
|
||||
plex: [
|
||||
'switchMediaServerStep1Plex',
|
||||
'switchMediaServerStep2Plex',
|
||||
'switchMediaServerStep3Plex',
|
||||
'switchMediaServerStep4Plex',
|
||||
],
|
||||
jellyfinEmbyToPlex: [
|
||||
'switchMediaServerStep1JellyfinEmby',
|
||||
'switchMediaServerStep2JellyfinEmby',
|
||||
'switchMediaServerStep3JellyfinEmby',
|
||||
'switchMediaServerStep4JellyfinEmby',
|
||||
],
|
||||
jellyfinEmbyToOther: [
|
||||
'switchMediaServerStep1JellyfinEmbyToOther',
|
||||
'switchMediaServerStep2JellyfinEmbyToOther',
|
||||
'switchMediaServerStep3JellyfinEmbyToOther',
|
||||
'switchMediaServerStep4JellyfinEmbyToOther',
|
||||
],
|
||||
};
|
||||
|
||||
const STEP_LINK_VALUES_INDEX: Record<StepsVariant, number[]> = {
|
||||
plex: [1, 2],
|
||||
jellyfinEmbyToPlex: [1, 2],
|
||||
jellyfinEmbyToOther: [],
|
||||
};
|
||||
|
||||
const SwitchMediaServerSection = () => {
|
||||
const settings = useSettings();
|
||||
const intl = useIntl();
|
||||
@@ -97,9 +142,13 @@ const SwitchMediaServerSection = () => {
|
||||
const effectiveTarget = validTargets.includes(switchTargetServerType)
|
||||
? switchTargetServerType
|
||||
: validTargets[0];
|
||||
const targetPayload: { targetServerType: SwitchTargetServerType } = {
|
||||
targetServerType: effectiveTarget,
|
||||
};
|
||||
const targetPayload = { targetServerType: effectiveTarget };
|
||||
const showPlexOnly = validTargets.length === 1 && validTargets[0] === 'plex';
|
||||
const stepsVariant: StepsVariant = isPlex
|
||||
? 'plex'
|
||||
: (isJellyfin || isEmby) && effectiveTarget !== 'plex'
|
||||
? 'jellyfinEmbyToOther'
|
||||
: 'jellyfinEmbyToPlex';
|
||||
|
||||
const handleSwitch = async () => {
|
||||
setSubmitting(true);
|
||||
@@ -115,17 +164,12 @@ const SwitchMediaServerSection = () => {
|
||||
setModalOpen(false);
|
||||
window.location.reload();
|
||||
} catch (err: unknown) {
|
||||
const extracted = axios.isAxiosError(err)
|
||||
? (err.response?.data?.error ??
|
||||
err.response?.data?.message ??
|
||||
err.message)
|
||||
: err instanceof Error
|
||||
? err.message
|
||||
: null;
|
||||
const message =
|
||||
extracted != null && String(extracted).trim() !== ''
|
||||
? String(extracted)
|
||||
: intl.formatMessage(messages.switchMediaServerError);
|
||||
axios.isAxiosError(err) && err.response?.data?.message
|
||||
? String(err.response.data.message)
|
||||
: axios.isAxiosError(err) && err.response?.data?.error
|
||||
? String(err.response.data.error)
|
||||
: intl.formatMessage(messages.switchMediaServerError);
|
||||
addToast(message, { appearance: 'error' });
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
@@ -150,7 +194,7 @@ const SwitchMediaServerSection = () => {
|
||||
return (
|
||||
<div className="mt-10 border-t border-gray-700 pt-8">
|
||||
<Button buttonType="danger" onClick={() => setModalOpen(true)}>
|
||||
{validTargets.length === 1 && validTargets[0] === 'plex' ? (
|
||||
{showPlexOnly ? (
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchToPlex"
|
||||
defaultMessage={messages.switchToPlex.defaultMessage}
|
||||
@@ -175,14 +219,14 @@ const SwitchMediaServerSection = () => {
|
||||
>
|
||||
<Modal
|
||||
title={
|
||||
validTargets.length === 1 && validTargets[0] === 'plex'
|
||||
showPlexOnly
|
||||
? intl.formatMessage(messages.switchToPlex)
|
||||
: intl.formatMessage(messages.switchMediaServerButton)
|
||||
}
|
||||
onCancel={() => !isSubmitting && setModalOpen(false)}
|
||||
onOk={handleSwitch}
|
||||
okText={
|
||||
validTargets.length === 1 && validTargets[0] === 'plex'
|
||||
showPlexOnly
|
||||
? intl.formatMessage(messages.switchToPlex)
|
||||
: intl.formatMessage(messages.switchMediaServerButton)
|
||||
}
|
||||
@@ -192,120 +236,19 @@ const SwitchMediaServerSection = () => {
|
||||
okDisabled={isSubmitting}
|
||||
>
|
||||
<div className="space-y-1 text-gray-300">
|
||||
{isPlex ? (
|
||||
<>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep1Plex"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep1Plex.defaultMessage
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep2Plex"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep2Plex.defaultMessage
|
||||
}
|
||||
values={linkValues}
|
||||
/>
|
||||
</p>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep3Plex"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep3Plex.defaultMessage
|
||||
}
|
||||
values={linkValues}
|
||||
/>
|
||||
</p>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep4Plex"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep4Plex.defaultMessage
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
</>
|
||||
) : (isJellyfin || isEmby) && effectiveTarget !== 'plex' ? (
|
||||
<>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep1JellyfinEmbyToOther"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep1JellyfinEmbyToOther
|
||||
.defaultMessage
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep2JellyfinEmbyToOther"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep2JellyfinEmbyToOther
|
||||
.defaultMessage
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep3JellyfinEmbyToOther"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep3JellyfinEmbyToOther
|
||||
.defaultMessage
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep4JellyfinEmbyToOther"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep4JellyfinEmbyToOther
|
||||
.defaultMessage
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep1JellyfinEmby"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep1JellyfinEmby.defaultMessage
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep2JellyfinEmby"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep2JellyfinEmby.defaultMessage
|
||||
}
|
||||
values={linkValues}
|
||||
/>
|
||||
</p>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep3JellyfinEmby"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep3JellyfinEmby.defaultMessage
|
||||
}
|
||||
values={linkValues}
|
||||
/>
|
||||
</p>
|
||||
<p className="m-0">
|
||||
<FormattedMessage
|
||||
id="components.Settings.switchMediaServerStep4JellyfinEmby"
|
||||
defaultMessage={
|
||||
messages.switchMediaServerStep4JellyfinEmby.defaultMessage
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
{STEP_KEYS[stepsVariant].map((key, i) => (
|
||||
<p key={key} className="m-0">
|
||||
<FormattedMessage
|
||||
id={`components.Settings.${key}`}
|
||||
defaultMessage={messages[key].defaultMessage}
|
||||
values={
|
||||
STEP_LINK_VALUES_INDEX[stepsVariant].includes(i)
|
||||
? linkValues
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<Alert
|
||||
@@ -335,21 +278,13 @@ const SwitchMediaServerSection = () => {
|
||||
>
|
||||
{validTargets.map((t) => (
|
||||
<option key={t} value={t}>
|
||||
{t === 'plex'
|
||||
? 'Plex'
|
||||
: t === 'jellyfin'
|
||||
? 'Jellyfin'
|
||||
: 'Emby'}
|
||||
{getTargetLabel(t)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
<span className="text-sm font-medium text-white">
|
||||
{effectiveTarget === 'plex'
|
||||
? 'Plex'
|
||||
: effectiveTarget === 'jellyfin'
|
||||
? 'Jellyfin'
|
||||
: 'Emby'}
|
||||
{getTargetLabel(effectiveTarget)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user