mirror of
https://github.com/fallenbagel/jellyseerr.git
synced 2025-12-30 21:49:11 -05:00
fix: properly pass qualityProfile and metadataProfile in music requests based on Lidarr configuration selection
This commit is contained in:
@@ -727,6 +727,12 @@ components:
|
||||
activeProfileName:
|
||||
type: string
|
||||
example: 128kps
|
||||
activeMetadataProfileId:
|
||||
type: number
|
||||
example: 1
|
||||
activeMetadataProfileName:
|
||||
type: string
|
||||
example: Standard
|
||||
activeDirectory:
|
||||
type: string
|
||||
example: '/music/'
|
||||
|
||||
@@ -278,6 +278,11 @@ export interface SearchCommand extends Record<string, unknown> {
|
||||
albumIds: number[];
|
||||
}
|
||||
|
||||
export interface MetadataProfile {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
class LidarrAPI extends ServarrBase<{ albumId: number }> {
|
||||
protected apiKey: string;
|
||||
constructor({ url, apiKey }: { url: string; apiKey: string }) {
|
||||
@@ -368,25 +373,13 @@ class LidarrAPI extends ServarrBase<{ albumId: number }> {
|
||||
}
|
||||
}
|
||||
|
||||
public async searchOnAdd(albumId: number): Promise<void> {
|
||||
logger.info('Executing album search command', {
|
||||
label: 'Lidarr API',
|
||||
albumId,
|
||||
});
|
||||
|
||||
public async getMetadataProfiles(): Promise<MetadataProfile[]> {
|
||||
try {
|
||||
await this.post('/command', {
|
||||
name: 'AlbumSearch',
|
||||
albumIds: [albumId],
|
||||
});
|
||||
const data = await this.get<MetadataProfile[]>('/metadataProfile');
|
||||
return data;
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
'Something went wrong while executing Lidarr album search.',
|
||||
{
|
||||
label: 'Lidarr API',
|
||||
errorMessage: e.message,
|
||||
albumId,
|
||||
}
|
||||
throw new Error(
|
||||
`[Lidarr] Failed to retrieve metadata profiles: ${e.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +83,6 @@ export interface RadarrSettings extends DVRSettings {
|
||||
minimumAvailability: string;
|
||||
}
|
||||
|
||||
export type LidarrSettings = DVRSettings;
|
||||
|
||||
export interface SonarrSettings extends DVRSettings {
|
||||
seriesType: 'standard' | 'daily' | 'anime';
|
||||
animeSeriesType: 'standard' | 'daily' | 'anime';
|
||||
@@ -97,6 +95,11 @@ export interface SonarrSettings extends DVRSettings {
|
||||
enableSeasonFolders: boolean;
|
||||
}
|
||||
|
||||
export interface LidarrSettings extends DVRSettings {
|
||||
activeMetadataProfileId?: number;
|
||||
activeMetadataProfileName?: string;
|
||||
}
|
||||
|
||||
interface Quota {
|
||||
quotaLimit?: number;
|
||||
quotaDays?: number;
|
||||
|
||||
@@ -251,8 +251,9 @@ serviceRoutes.get<{ id: string }>('/lidarr/:id', async (req, res, next) => {
|
||||
});
|
||||
|
||||
try {
|
||||
const [profiles, rootFolders, tags] = await Promise.all([
|
||||
const [profiles, metadataProfiles, rootFolders, tags] = await Promise.all([
|
||||
lidarr.getProfiles(),
|
||||
lidarr.getMetadataProfiles(),
|
||||
lidarr.getRootFolders(),
|
||||
lidarr.getTags(),
|
||||
]);
|
||||
@@ -264,8 +265,11 @@ serviceRoutes.get<{ id: string }>('/lidarr/:id', async (req, res, next) => {
|
||||
isDefault: lidarrSettings.isDefault,
|
||||
activeDirectory: lidarrSettings.activeDirectory,
|
||||
activeProfileId: lidarrSettings.activeProfileId,
|
||||
activeMetadataProfileId: lidarrSettings.activeMetadataProfileId,
|
||||
activeTags: lidarrSettings.tags ?? [],
|
||||
},
|
||||
profiles,
|
||||
metadataProfiles,
|
||||
rootFolders: rootFolders.map((folder) => ({
|
||||
id: folder.id,
|
||||
path: folder.path,
|
||||
|
||||
@@ -42,11 +42,13 @@ lidarrRoutes.post<
|
||||
.then((value) => value.urlBase)
|
||||
.catch(() => req.body.baseUrl);
|
||||
const profiles = await lidarr.getProfiles();
|
||||
const metadataProfiles = await lidarr.getMetadataProfiles();
|
||||
const folders = await lidarr.getRootFolders();
|
||||
const tags = await lidarr.getTags();
|
||||
|
||||
return res.status(200).json({
|
||||
profiles,
|
||||
metadataProfiles,
|
||||
rootFolders: folders.map((folder) => ({
|
||||
id: folder.id,
|
||||
path: folder.path,
|
||||
@@ -59,7 +61,6 @@ lidarrRoutes.post<
|
||||
label: 'Lidarr',
|
||||
message: e.message,
|
||||
});
|
||||
|
||||
next({ status: 500, message: 'Failed to connect to Lidarr' });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import CoverArtArchive from '@server/api/coverartarchive';
|
||||
import ListenBrainzAPI from '@server/api/listenbrainz';
|
||||
import MusicBrainz from '@server/api/musicbrainz';
|
||||
import type { LidarrAlbumOptions } from '@server/api/servarr/lidarr';
|
||||
import LidarrAPI from '@server/api/servarr/lidarr';
|
||||
import type { RadarrMovieOptions } from '@server/api/servarr/radarr';
|
||||
import RadarrAPI from '@server/api/servarr/radarr';
|
||||
@@ -915,6 +916,21 @@ export class MediaRequestSubscriber
|
||||
});
|
||||
}
|
||||
|
||||
let qualityProfile = lidarrSettings.activeProfileId;
|
||||
const metadataProfile = lidarrSettings.activeMetadataProfileId ?? 1;
|
||||
|
||||
if (entity.profileId && entity.profileId !== qualityProfile) {
|
||||
qualityProfile = entity.profileId;
|
||||
logger.info(
|
||||
`Request has an override quality profile ID: ${qualityProfile}`,
|
||||
{
|
||||
label: 'Media Request',
|
||||
requestId: entity.id,
|
||||
mediaId: entity.media.id,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const artistPath = `${rootFolder}/${albumInfo.artist.artistName}`;
|
||||
|
||||
const addAlbumPayload: LidarrAlbumOptions = {
|
||||
@@ -925,7 +941,7 @@ export class MediaRequestSubscriber
|
||||
foreignAlbumId: albumInfo.foreignAlbumId,
|
||||
monitored: true,
|
||||
anyReleaseOk: true,
|
||||
profileId: 1,
|
||||
profileId: qualityProfile,
|
||||
duration: albumInfo.duration || 0,
|
||||
albumType: albumInfo.albumType,
|
||||
secondaryTypes: [],
|
||||
@@ -948,8 +964,8 @@ export class MediaRequestSubscriber
|
||||
links: albumInfo.artist.links || [],
|
||||
images: albumInfo.artist.images || [],
|
||||
path: artistPath,
|
||||
qualityProfileId: 1,
|
||||
metadataProfileId: 2,
|
||||
qualityProfileId: qualityProfile,
|
||||
metadataProfileId: metadataProfile,
|
||||
monitored: true,
|
||||
monitorNewItems: 'none',
|
||||
rootFolderPath: rootFolder,
|
||||
@@ -978,15 +994,10 @@ export class MediaRequestSubscriber
|
||||
};
|
||||
|
||||
await mediaRepository.update({ id: entity.media.id }, updateFields);
|
||||
|
||||
if (addAlbumPayload.addOptions.searchForNewAlbum) {
|
||||
await lidarr.searchOnAdd(result.id);
|
||||
}
|
||||
})
|
||||
.catch(async (error) => {
|
||||
const requestRepository = getRepository(MediaRequest);
|
||||
|
||||
entity.status = MediaRequestStatus.FAILED;
|
||||
await requestRepository.update(
|
||||
{ id: entity.id },
|
||||
{ status: MediaRequestStatus.FAILED }
|
||||
|
||||
@@ -59,6 +59,11 @@ const messages = defineMessages('components.Settings.LidarrModal', {
|
||||
tags: 'Tags',
|
||||
notagoptions: 'No tags.',
|
||||
selecttags: 'Select tags',
|
||||
metadataprofile: 'Metadata Profile',
|
||||
selectMetadataProfile: 'Select metadata profile',
|
||||
loadingmetadataprofiles: 'Loading metadata profiles…',
|
||||
testFirstMetadataProfiles: 'Test connection to load metadata profiles',
|
||||
validationMetadataProfileRequired: 'You must select a metadata profile',
|
||||
});
|
||||
|
||||
interface TestResponse {
|
||||
@@ -66,6 +71,10 @@ interface TestResponse {
|
||||
id: number;
|
||||
name: string;
|
||||
}[];
|
||||
metadataProfiles: {
|
||||
id: number;
|
||||
name: string;
|
||||
}[];
|
||||
rootFolders: {
|
||||
id: number;
|
||||
path: string;
|
||||
@@ -91,6 +100,7 @@ const LidarrModal = ({ onClose, lidarr, onSave }: LidarrModalProps) => {
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const [testResponse, setTestResponse] = useState<TestResponse>({
|
||||
profiles: [],
|
||||
metadataProfiles: [],
|
||||
rootFolders: [],
|
||||
tags: [],
|
||||
});
|
||||
@@ -134,6 +144,9 @@ const LidarrModal = ({ onClose, lidarr, onSave }: LidarrModalProps) => {
|
||||
intl.formatMessage(messages.validationBaseUrlTrailingSlash),
|
||||
(value) => !value || !value.endsWith('/')
|
||||
),
|
||||
activeMetadataProfileId: Yup.string().required(
|
||||
intl.formatMessage(messages.validationMetadataProfileRequired)
|
||||
),
|
||||
});
|
||||
|
||||
const testConnection = useCallback(
|
||||
@@ -236,6 +249,7 @@ const LidarrModal = ({ onClose, lidarr, onSave }: LidarrModalProps) => {
|
||||
syncEnabled: lidarr?.syncEnabled ?? false,
|
||||
enableSearch: !lidarr?.preventSearch,
|
||||
tagRequests: lidarr?.tagRequests ?? false,
|
||||
activeMetadataProfileId: lidarr?.activeMetadataProfileId ?? 1,
|
||||
}}
|
||||
validationSchema={LidarrSettingsSchema}
|
||||
onSubmit={async (values) => {
|
||||
@@ -260,6 +274,11 @@ const LidarrModal = ({ onClose, lidarr, onSave }: LidarrModalProps) => {
|
||||
syncEnabled: values.syncEnabled,
|
||||
preventSearch: !values.enableSearch,
|
||||
tagRequests: values.tagRequests,
|
||||
activeMetadataProfileId: Number(values.activeMetadataProfileId),
|
||||
activeMetadataProfileName: testResponse.metadataProfiles.find(
|
||||
(profile) =>
|
||||
profile.id === Number(values.activeMetadataProfileId)
|
||||
)?.name,
|
||||
};
|
||||
|
||||
const response = await fetch(
|
||||
@@ -569,6 +588,55 @@ const LidarrModal = ({ onClose, lidarr, onSave }: LidarrModalProps) => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label
|
||||
htmlFor="activeMetadataProfileId"
|
||||
className="text-label"
|
||||
>
|
||||
{intl.formatMessage(messages.metadataprofile)}
|
||||
<span className="label-required">*</span>
|
||||
</label>
|
||||
<div className="form-input-area">
|
||||
<div className="form-input-field">
|
||||
<Field
|
||||
as="select"
|
||||
id="activeMetadataProfileId"
|
||||
name="activeMetadataProfileId"
|
||||
disabled={!isValidated || isTesting}
|
||||
>
|
||||
<option value="">
|
||||
{isTesting
|
||||
? intl.formatMessage(
|
||||
messages.loadingmetadataprofiles
|
||||
)
|
||||
: !isValidated
|
||||
? intl.formatMessage(
|
||||
messages.testFirstMetadataProfiles
|
||||
)
|
||||
: intl.formatMessage(
|
||||
messages.selectMetadataProfile
|
||||
)}
|
||||
</option>
|
||||
{testResponse.metadataProfiles.length > 0 &&
|
||||
testResponse.metadataProfiles.map((profile) => (
|
||||
<option
|
||||
key={`loaded-metadataprofile-${profile.id}`}
|
||||
value={profile.id}
|
||||
>
|
||||
{profile.name}
|
||||
</option>
|
||||
))}
|
||||
</Field>
|
||||
</div>
|
||||
{errors.activeMetadataProfileId &&
|
||||
touched.activeMetadataProfileId &&
|
||||
typeof errors.activeMetadataProfileId === 'string' && (
|
||||
<div className="error">
|
||||
{errors.activeMetadataProfileId}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<label htmlFor="tags" className="text-label">
|
||||
{intl.formatMessage(messages.tags)}
|
||||
|
||||
@@ -719,12 +719,15 @@
|
||||
"components.Settings.LidarrModal.externalUrl": "External URL",
|
||||
"components.Settings.LidarrModal.hostname": "Hostname or IP Address",
|
||||
"components.Settings.LidarrModal.loadingTags": "Loading tags…",
|
||||
"components.Settings.LidarrModal.loadingmetadataprofiles": "Loading metadata profiles…",
|
||||
"components.Settings.LidarrModal.loadingprofiles": "Loading quality profiles…",
|
||||
"components.Settings.LidarrModal.loadingrootfolders": "Loading root folders…",
|
||||
"components.Settings.LidarrModal.metadataprofile": "Metadata Profile",
|
||||
"components.Settings.LidarrModal.notagoptions": "No tags.",
|
||||
"components.Settings.LidarrModal.port": "Port",
|
||||
"components.Settings.LidarrModal.qualityprofile": "Quality Profile",
|
||||
"components.Settings.LidarrModal.rootfolder": "Root Folder",
|
||||
"components.Settings.LidarrModal.selectMetadataProfile": "Select metadata profile",
|
||||
"components.Settings.LidarrModal.selectQualityProfile": "Select quality profile",
|
||||
"components.Settings.LidarrModal.selectRootFolder": "Select root folder",
|
||||
"components.Settings.LidarrModal.selecttags": "Select tags",
|
||||
@@ -734,6 +737,7 @@
|
||||
"components.Settings.LidarrModal.tagRequests": "Tag Requests",
|
||||
"components.Settings.LidarrModal.tagRequestsInfo": "Automatically add an additional tag with the requester's user ID & display name",
|
||||
"components.Settings.LidarrModal.tags": "Tags",
|
||||
"components.Settings.LidarrModal.testFirstMetadataProfiles": "Test connection to load metadata profiles",
|
||||
"components.Settings.LidarrModal.testFirstQualityProfiles": "Test connection to load quality profiles",
|
||||
"components.Settings.LidarrModal.testFirstRootFolders": "Test connection to load root folders",
|
||||
"components.Settings.LidarrModal.testFirstTags": "Test connection to load tags",
|
||||
@@ -745,6 +749,7 @@
|
||||
"components.Settings.LidarrModal.validationBaseUrlLeadingSlash": "Base URL must have a leading slash",
|
||||
"components.Settings.LidarrModal.validationBaseUrlTrailingSlash": "Base URL must not end in a trailing slash",
|
||||
"components.Settings.LidarrModal.validationHostnameRequired": "You must provide a valid hostname or IP address",
|
||||
"components.Settings.LidarrModal.validationMetadataProfileRequired": "You must select a metadata profile",
|
||||
"components.Settings.LidarrModal.validationNameRequired": "You must provide a server name",
|
||||
"components.Settings.LidarrModal.validationPortRequired": "You must provide a valid port number",
|
||||
"components.Settings.LidarrModal.validationProfileRequired": "You must select a quality profile",
|
||||
|
||||
Reference in New Issue
Block a user