fix(servarr): replace spaces in arr user tags with - (#2231)

* fix: sanitize disallowed characters in arr tags

Updates the tag creation to normalize diacritics, replace spaces with hyphens and stip any
non-alphanumeric characters from display name

fix #2229, fix #1897

* refactor: improve display name sanitization in tag creation

* fix: include displayName in user selection for tag migration

* fix(migrator): retrieve all user fields in tag migration

This is a one time migration so performance is neglible. This should trigger the @AfterLoad hooks
which sets the `displayName`
This commit is contained in:
fallenbagel
2026-01-06 00:18:06 +05:00
committed by GitHub
parent 0c95b5ec91
commit f91a26befe
2 changed files with 51 additions and 13 deletions

View File

@@ -13,9 +13,7 @@ const migrationArrTags = async (settings: any): Promise<AllSettings> => {
}
const userRepository = getRepository(User);
const users = await userRepository.find({
select: ['id'],
});
const users = await userRepository.find();
let errorOccurred = false;
@@ -30,15 +28,26 @@ const migrationArrTags = async (settings: any): Promise<AllSettings> => {
});
const radarrTags = await radarr.getTags();
for (const user of users) {
const userTag = radarrTags.find((v) =>
v.label.startsWith(user.id + ' - ')
const userTag = radarrTags.find(
(v) =>
v.label.startsWith(user.id + ' - ') ||
v.label.startsWith(user.id + '-')
);
if (!userTag) {
continue;
}
await radarr.renameTag({
id: userTag.id,
label: userTag.label.replace(`${user.id} - `, `${user.id}-`),
label:
user.id +
'-' +
user.displayName
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/\s+/g, '-')
.replace(/[^a-z0-9-]/gi, '')
.replace(/-+/g, '-')
.replace(/^-|-$/g, ''),
});
}
} catch (error) {
@@ -61,15 +70,26 @@ const migrationArrTags = async (settings: any): Promise<AllSettings> => {
});
const sonarrTags = await sonarr.getTags();
for (const user of users) {
const userTag = sonarrTags.find((v) =>
v.label.startsWith(user.id + ' - ')
const userTag = sonarrTags.find(
(v) =>
v.label.startsWith(user.id + ' - ') ||
v.label.startsWith(user.id + '-')
);
if (!userTag) {
continue;
}
await sonarr.renameTag({
id: userTag.id,
label: userTag.label.replace(`${user.id} - `, `${user.id}-`),
label:
user.id +
'-' +
user.displayName
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/\s+/g, '-')
.replace(/[^a-z0-9-]/gi, '')
.replace(/-+/g, '-')
.replace(/^-|-$/g, ''),
});
}
} catch (error) {

View File

@@ -29,6 +29,16 @@ import type {
} from 'typeorm';
import { EventSubscriber } from 'typeorm';
const sanitizeDisplayName = (displayName: string): string => {
return displayName
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/\s+/g, '-')
.replace(/[^a-z0-9-]/gi, '')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '');
};
@EventSubscriber()
export class MediaRequestSubscriber
implements EntitySubscriberInterface<MediaRequest>
@@ -310,11 +320,15 @@ export class MediaRequestSubscriber
mediaId: entity.media.id,
userId: entity.requestedBy.id,
newTag:
entity.requestedBy.id + '-' + entity.requestedBy.displayName,
entity.requestedBy.id +
'-' +
sanitizeDisplayName(entity.requestedBy.displayName),
});
userTag = await radarr.createTag({
label:
entity.requestedBy.id + '-' + entity.requestedBy.displayName,
entity.requestedBy.id +
'-' +
sanitizeDisplayName(entity.requestedBy.displayName),
});
}
if (userTag.id) {
@@ -631,11 +645,15 @@ export class MediaRequestSubscriber
mediaId: entity.media.id,
userId: entity.requestedBy.id,
newTag:
entity.requestedBy.id + '-' + entity.requestedBy.displayName,
entity.requestedBy.id +
'-' +
sanitizeDisplayName(entity.requestedBy.displayName),
});
userTag = await sonarr.createTag({
label:
entity.requestedBy.id + '-' + entity.requestedBy.displayName,
entity.requestedBy.id +
'-' +
sanitizeDisplayName(entity.requestedBy.displayName),
});
}
if (userTag.id) {