feat: auto tagging requested media with username (#3338)
* feat: auto tagging requested media with username Relating to discussion: https://github.com/sct/overseerr/discussions/3313 Adding an option to the Radarr and Sonarr service to enable automatic tagging with the username requesting the media. Current format, to reduce tag clutter if a user changes displayname: `[user.id] - [user.displayName]` * fix: modified new secondary tip language --------- Co-authored-by: Brandon Cohen <brandon@z3hn.dev>
This commit is contained in:
@@ -764,6 +764,38 @@ export class MediaRequest {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (radarrSettings.tagRequests) {
|
||||||
|
let userTag = (await radarr.getTags()).find((v) =>
|
||||||
|
v.label.startsWith(this.requestedBy.id + ' - ')
|
||||||
|
);
|
||||||
|
if (!userTag) {
|
||||||
|
logger.info(`Requester has no active tag. Creating new`, {
|
||||||
|
label: 'Media Request',
|
||||||
|
requestId: this.id,
|
||||||
|
mediaId: this.media.id,
|
||||||
|
userId: this.requestedBy.id,
|
||||||
|
newTag:
|
||||||
|
this.requestedBy.id + ' - ' + this.requestedBy.displayName,
|
||||||
|
});
|
||||||
|
userTag = await radarr.createTag({
|
||||||
|
label: this.requestedBy.id + ' - ' + this.requestedBy.displayName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (userTag.id) {
|
||||||
|
if (!tags?.find((v) => v === userTag?.id)) {
|
||||||
|
tags?.push(userTag.id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warn(`Requester has no tag and failed to add one`, {
|
||||||
|
label: 'Media Request',
|
||||||
|
requestId: this.id,
|
||||||
|
mediaId: this.media.id,
|
||||||
|
userId: this.requestedBy.id,
|
||||||
|
radarrServer: radarrSettings.hostname + ':' + radarrSettings.port,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
media[this.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE
|
media[this.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE
|
||||||
) {
|
) {
|
||||||
@@ -1022,6 +1054,38 @@ export class MediaRequest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sonarrSettings.tagRequests) {
|
||||||
|
let userTag = (await sonarr.getTags()).find((v) =>
|
||||||
|
v.label.startsWith(this.requestedBy.id + ' - ')
|
||||||
|
);
|
||||||
|
if (!userTag) {
|
||||||
|
logger.info(`Requester has no active tag. Creating new`, {
|
||||||
|
label: 'Media Request',
|
||||||
|
requestId: this.id,
|
||||||
|
mediaId: this.media.id,
|
||||||
|
userId: this.requestedBy.id,
|
||||||
|
newTag:
|
||||||
|
this.requestedBy.id + ' - ' + this.requestedBy.displayName,
|
||||||
|
});
|
||||||
|
userTag = await sonarr.createTag({
|
||||||
|
label: this.requestedBy.id + ' - ' + this.requestedBy.displayName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (userTag.id) {
|
||||||
|
if (!tags?.find((v) => v === userTag?.id)) {
|
||||||
|
tags?.push(userTag.id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warn(`Requester has no tag and failed to add one`, {
|
||||||
|
label: 'Media Request',
|
||||||
|
requestId: this.id,
|
||||||
|
mediaId: this.media.id,
|
||||||
|
userId: this.requestedBy.id,
|
||||||
|
sonarrServer: sonarrSettings.hostname + ':' + sonarrSettings.port,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const sonarrSeriesOptions: AddSeriesOptions = {
|
const sonarrSeriesOptions: AddSeriesOptions = {
|
||||||
profileId: qualityProfile,
|
profileId: qualityProfile,
|
||||||
languageProfileId: languageProfile,
|
languageProfileId: languageProfile,
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ export interface DVRSettings {
|
|||||||
externalUrl?: string;
|
externalUrl?: string;
|
||||||
syncEnabled: boolean;
|
syncEnabled: boolean;
|
||||||
preventSearch: boolean;
|
preventSearch: boolean;
|
||||||
|
tagRequests: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RadarrSettings extends DVRSettings {
|
export interface RadarrSettings extends DVRSettings {
|
||||||
|
|||||||
@@ -57,6 +57,9 @@ const messages = defineMessages({
|
|||||||
testFirstTags: 'Test connection to load tags',
|
testFirstTags: 'Test connection to load tags',
|
||||||
tags: 'Tags',
|
tags: 'Tags',
|
||||||
enableSearch: 'Enable Automatic Search',
|
enableSearch: 'Enable Automatic Search',
|
||||||
|
tagRequests: 'Tag Requests',
|
||||||
|
tagRequestsInfo:
|
||||||
|
"Automatically add an additional tag with the requester's user ID & display name",
|
||||||
validationApplicationUrl: 'You must provide a valid URL',
|
validationApplicationUrl: 'You must provide a valid URL',
|
||||||
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||||
validationBaseUrlLeadingSlash: 'URL base must have a leading slash',
|
validationBaseUrlLeadingSlash: 'URL base must have a leading slash',
|
||||||
@@ -238,6 +241,7 @@ const RadarrModal = ({ onClose, radarr, onSave }: RadarrModalProps) => {
|
|||||||
externalUrl: radarr?.externalUrl,
|
externalUrl: radarr?.externalUrl,
|
||||||
syncEnabled: radarr?.syncEnabled ?? false,
|
syncEnabled: radarr?.syncEnabled ?? false,
|
||||||
enableSearch: !radarr?.preventSearch,
|
enableSearch: !radarr?.preventSearch,
|
||||||
|
tagRequests: radarr?.tagRequests ?? false,
|
||||||
}}
|
}}
|
||||||
validationSchema={RadarrSettingsSchema}
|
validationSchema={RadarrSettingsSchema}
|
||||||
onSubmit={async (values) => {
|
onSubmit={async (values) => {
|
||||||
@@ -263,6 +267,7 @@ const RadarrModal = ({ onClose, radarr, onSave }: RadarrModalProps) => {
|
|||||||
externalUrl: values.externalUrl,
|
externalUrl: values.externalUrl,
|
||||||
syncEnabled: values.syncEnabled,
|
syncEnabled: values.syncEnabled,
|
||||||
preventSearch: !values.enableSearch,
|
preventSearch: !values.enableSearch,
|
||||||
|
tagRequests: values.tagRequests,
|
||||||
};
|
};
|
||||||
if (!radarr) {
|
if (!radarr) {
|
||||||
await axios.post('/api/v1/settings/radarr', submission);
|
await axios.post('/api/v1/settings/radarr', submission);
|
||||||
@@ -713,6 +718,21 @@ const RadarrModal = ({ onClose, radarr, onSave }: RadarrModalProps) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="form-row">
|
||||||
|
<label htmlFor="tagRequests" className="checkbox-label">
|
||||||
|
{intl.formatMessage(messages.tagRequests)}
|
||||||
|
<span className="label-tip">
|
||||||
|
{intl.formatMessage(messages.tagRequestsInfo)}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div className="form-input-area">
|
||||||
|
<Field
|
||||||
|
type="checkbox"
|
||||||
|
id="tagRequests"
|
||||||
|
name="tagRequests"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ const messages = defineMessages({
|
|||||||
syncEnabled: 'Enable Scan',
|
syncEnabled: 'Enable Scan',
|
||||||
externalUrl: 'External URL',
|
externalUrl: 'External URL',
|
||||||
enableSearch: 'Enable Automatic Search',
|
enableSearch: 'Enable Automatic Search',
|
||||||
|
tagRequests: 'Tag Requests',
|
||||||
|
tagRequestsInfo:
|
||||||
|
"Automatically add an additional tag with the requester's user ID & display name",
|
||||||
validationApplicationUrl: 'You must provide a valid URL',
|
validationApplicationUrl: 'You must provide a valid URL',
|
||||||
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
|
||||||
validationBaseUrlLeadingSlash: 'Base URL must have a leading slash',
|
validationBaseUrlLeadingSlash: 'Base URL must have a leading slash',
|
||||||
@@ -252,6 +255,7 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
|
|||||||
externalUrl: sonarr?.externalUrl,
|
externalUrl: sonarr?.externalUrl,
|
||||||
syncEnabled: sonarr?.syncEnabled ?? false,
|
syncEnabled: sonarr?.syncEnabled ?? false,
|
||||||
enableSearch: !sonarr?.preventSearch,
|
enableSearch: !sonarr?.preventSearch,
|
||||||
|
tagRequests: sonarr?.tagRequests ?? false,
|
||||||
}}
|
}}
|
||||||
validationSchema={SonarrSettingsSchema}
|
validationSchema={SonarrSettingsSchema}
|
||||||
onSubmit={async (values) => {
|
onSubmit={async (values) => {
|
||||||
@@ -292,6 +296,7 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
|
|||||||
externalUrl: values.externalUrl,
|
externalUrl: values.externalUrl,
|
||||||
syncEnabled: values.syncEnabled,
|
syncEnabled: values.syncEnabled,
|
||||||
preventSearch: !values.enableSearch,
|
preventSearch: !values.enableSearch,
|
||||||
|
tagRequests: values.tagRequests,
|
||||||
};
|
};
|
||||||
if (!sonarr) {
|
if (!sonarr) {
|
||||||
await axios.post('/api/v1/settings/sonarr', submission);
|
await axios.post('/api/v1/settings/sonarr', submission);
|
||||||
@@ -960,6 +965,21 @@ const SonarrModal = ({ onClose, sonarr, onSave }: SonarrModalProps) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="form-row">
|
||||||
|
<label htmlFor="tagRequests" className="checkbox-label">
|
||||||
|
{intl.formatMessage(messages.tagRequests)}
|
||||||
|
<span className="label-tip">
|
||||||
|
{intl.formatMessage(messages.tagRequestsInfo)}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div className="form-input-area">
|
||||||
|
<Field
|
||||||
|
type="checkbox"
|
||||||
|
id="tagRequests"
|
||||||
|
name="tagRequests"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -684,6 +684,8 @@
|
|||||||
"components.Settings.RadarrModal.servername": "Server Name",
|
"components.Settings.RadarrModal.servername": "Server Name",
|
||||||
"components.Settings.RadarrModal.ssl": "Use SSL",
|
"components.Settings.RadarrModal.ssl": "Use SSL",
|
||||||
"components.Settings.RadarrModal.syncEnabled": "Enable Scan",
|
"components.Settings.RadarrModal.syncEnabled": "Enable Scan",
|
||||||
|
"components.Settings.RadarrModal.tagRequests": "Tag Requests",
|
||||||
|
"components.Settings.RadarrModal.tagRequestsInfo": "Automatically add an additional tag with the requester's user ID & display name",
|
||||||
"components.Settings.RadarrModal.tags": "Tags",
|
"components.Settings.RadarrModal.tags": "Tags",
|
||||||
"components.Settings.RadarrModal.testFirstQualityProfiles": "Test connection to load quality profiles",
|
"components.Settings.RadarrModal.testFirstQualityProfiles": "Test connection to load quality profiles",
|
||||||
"components.Settings.RadarrModal.testFirstRootFolders": "Test connection to load root folders",
|
"components.Settings.RadarrModal.testFirstRootFolders": "Test connection to load root folders",
|
||||||
@@ -861,6 +863,8 @@
|
|||||||
"components.Settings.SonarrModal.servername": "Server Name",
|
"components.Settings.SonarrModal.servername": "Server Name",
|
||||||
"components.Settings.SonarrModal.ssl": "Use SSL",
|
"components.Settings.SonarrModal.ssl": "Use SSL",
|
||||||
"components.Settings.SonarrModal.syncEnabled": "Enable Scan",
|
"components.Settings.SonarrModal.syncEnabled": "Enable Scan",
|
||||||
|
"components.Settings.SonarrModal.tagRequests": "Tag Requests",
|
||||||
|
"components.Settings.SonarrModal.tagRequestsInfo": "Automatically add an additional tag with the requester's user ID & display name",
|
||||||
"components.Settings.SonarrModal.tags": "Tags",
|
"components.Settings.SonarrModal.tags": "Tags",
|
||||||
"components.Settings.SonarrModal.testFirstLanguageProfiles": "Test connection to load language profiles",
|
"components.Settings.SonarrModal.testFirstLanguageProfiles": "Test connection to load language profiles",
|
||||||
"components.Settings.SonarrModal.testFirstQualityProfiles": "Test connection to load quality profiles",
|
"components.Settings.SonarrModal.testFirstQualityProfiles": "Test connection to load quality profiles",
|
||||||
@@ -1178,6 +1182,7 @@
|
|||||||
"i18n.cancel": "Cancel",
|
"i18n.cancel": "Cancel",
|
||||||
"i18n.canceling": "Canceling…",
|
"i18n.canceling": "Canceling…",
|
||||||
"i18n.close": "Close",
|
"i18n.close": "Close",
|
||||||
|
"i18n.collection": "Collection",
|
||||||
"i18n.decline": "Decline",
|
"i18n.decline": "Decline",
|
||||||
"i18n.declined": "Declined",
|
"i18n.declined": "Declined",
|
||||||
"i18n.delete": "Delete",
|
"i18n.delete": "Delete",
|
||||||
|
|||||||
Reference in New Issue
Block a user