Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
477e640
feat(settings): add endpoint and UI for switching media server
0xSysR3ll Feb 20, 2026
2a69215
feat(auth, settings): enforce admin permissions
0xSysR3ll Feb 20, 2026
307cbab
fix(settings): enable reinitialization for Tautulli settings form
0xSysR3ll Feb 20, 2026
6f78305
fix(settings): use proper error messages
0xSysR3ll Feb 20, 2026
c452c83
fix(settings): allow jellyfin/emby unlinking before migration
0xSysR3ll Feb 20, 2026
3111cad
fix: missing translations
0xSysR3ll Feb 20, 2026
e161b3a
fix(settings): remove unnecessary user ID condition for plex and jell…
0xSysR3ll Feb 22, 2026
b9561cb
fix(MediaSubscriber): remove optional chaining for status checks
0xSysR3ll Feb 22, 2026
2ecf828
feat(settings): add switching logic to support Jellyfin and Emby tran…
0xSysR3ll Feb 22, 2026
6d0d344
fix(settings): remove condition for user plexId in update query
0xSysR3ll Feb 22, 2026
46a7099
fix(userSettings): improve account linking logic to prevent conflicts…
0xSysR3ll Feb 22, 2026
6b2d33b
fix(auth): update token storage logic for Plex when using Jellyfin or…
0xSysR3ll Feb 22, 2026
2bbb8ee
feat(settings): log out all users after successful switch
0xSysR3ll Feb 22, 2026
179e8b0
feat(userList): add badges for linked Plex and Jellyfin/Emby users
0xSysR3ll Feb 22, 2026
f313366
feat(settings): add a proper modal for switching
0xSysR3ll Feb 22, 2026
9f23bcb
fix(settings): update deprecation messages and improve media server s…
0xSysR3ll Feb 22, 2026
bb7e195
feat(settings): make code more dry
0xSysR3ll Feb 22, 2026
7133eed
fix(settings): refine media server switch logic and update user instr…
0xSysR3ll Feb 22, 2026
c27f9ba
fix(settings): wrong link for users page
0xSysR3ll Feb 22, 2026
af45e5c
fix(settings): correct SQL syntax for jellyfinUserId condition
0xSysR3ll Feb 22, 2026
3b6a72d
fix: quote columns
0xSysR3ll Feb 22, 2026
dc39b93
fix(settings): prefer typeorm over raw sql queries
0xSysR3ll Feb 24, 2026
5c95a64
refactor(settings): remove success message after media server switch
0xSysR3ll Feb 24, 2026
4161722
fix(settings): revalidate user after media server switch
0xSysR3ll Feb 25, 2026
0cfa841
fix(settings): handle email comparison for Jellyfin users
0xSysR3ll Feb 25, 2026
ce959d6
fix(settings): ensure jobs restart after media server switch
0xSysR3ll Feb 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions seerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2290,6 +2290,44 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/JellyfinSettings'
/settings/switch-media-server:
post:
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
content:
application/json:
schema:
type: object
properties:
message:
type: string
example: 'Media server cleared. Restart or reload to configure a new server.'
'400':
description: No media server is configured
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: 'No media server is configured.'
'500':
description: Failed to switch media server
/settings/jellyfin/library:
get:
summary: Get Jellyfin libraries
Expand Down
2 changes: 1 addition & 1 deletion server/middleware/deprecation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const deprecatedRoute = ({
}: DeprecationOptions) => {
return (req: Request, res: Response, next: NextFunction) => {
logger.warn(
`Deprecated API endpoint accessed: ${oldPath} use ${newPath} instead`,
`Deprecated API endpoint accessed: ${oldPath} => use ${newPath} instead`,
{
label: 'API Deprecation',
ip: req.ip,
Expand Down
52 changes: 49 additions & 3 deletions server/routes/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,47 @@ authRoutes.post('/plex', async (req, res, next) => {
});
}

const mediaServerType = settings.main.mediaServerType;

if (
mediaServerType === MediaServerType.JELLYFIN ||
mediaServerType === MediaServerType.EMBY
) {
if (!req.user) {
return next({
status: 401,
message: 'Authentication required.',
});
}
if (!req.user.hasPermission(Permission.ADMIN)) {
return next({
status: 403,
message: 'Admin permissions required.',
});
}
try {
const plextv = new PlexTvAPI(body.authToken);
const account = await plextv.getUser();
const admin = await userRepository.findOneOrFail({
where: { id: 1 },
});
admin.plexToken = body.authToken;
admin.plexId = account.id;
admin.plexUsername = account.username;
await userRepository.save(admin);
return res.status(200).json({ email: admin.email });
} catch (e) {
logger.error('Failed to store Plex token for settings', {
label: 'API',
errorMessage: (e as Error).message,
});
return next({
status: 500,
message: 'Unable to validate Plex token.',
});
}
}

if (
settings.main.mediaServerType != MediaServerType.NOT_CONFIGURED &&
(settings.main.mediaServerLogin === false ||
Expand Down Expand Up @@ -410,9 +451,7 @@ authRoutes.post('/jellyfin', async (req, res, next) => {
settings.jellyfin.apiKey = apiKey;
await settings.save();
startJobs();
}
// User already exists, let's update their information
else if (account.User.Id === user?.jellyfinUserId) {
} else if (account.User.Id === user?.jellyfinUserId) {
logger.info(
`Found matching ${
settings.main.mediaServerType === MediaServerType.JELLYFIN
Expand All @@ -431,6 +470,13 @@ authRoutes.post('/jellyfin', async (req, res, next) => {
);
user.avatar = getUserAvatarUrl(user);
user.jellyfinUsername = account.User.Name;
user.userType =
settings.main.mediaServerType === MediaServerType.JELLYFIN
? UserType.JELLYFIN
: UserType.EMBY;
user.plexId = null;
user.plexUsername = null;
user.plexToken = null;

if (user.username === account.User.Name) {
user.username = '';
Expand Down
Loading
Loading