feat: radarr/sonarr tag support (#1366)
This commit is contained in:
188
server/api/servarr/radarr.ts
Normal file
188
server/api/servarr/radarr.ts
Normal file
@@ -0,0 +1,188 @@
|
||||
import logger from '../../logger';
|
||||
import ServarrBase from './base';
|
||||
|
||||
interface RadarrMovieOptions {
|
||||
title: string;
|
||||
qualityProfileId: number;
|
||||
minimumAvailability: string;
|
||||
tags: number[];
|
||||
profileId: number;
|
||||
year: number;
|
||||
rootFolderPath: string;
|
||||
tmdbId: number;
|
||||
monitored?: boolean;
|
||||
searchNow?: boolean;
|
||||
}
|
||||
|
||||
export interface RadarrMovie {
|
||||
id: number;
|
||||
title: string;
|
||||
isAvailable: boolean;
|
||||
monitored: boolean;
|
||||
tmdbId: number;
|
||||
imdbId: string;
|
||||
titleSlug: string;
|
||||
folderName: string;
|
||||
path: string;
|
||||
profileId: number;
|
||||
qualityProfileId: number;
|
||||
added: string;
|
||||
downloaded: boolean;
|
||||
hasFile: boolean;
|
||||
}
|
||||
|
||||
class RadarrAPI extends ServarrBase<{ movieId: number }> {
|
||||
constructor({ url, apiKey }: { url: string; apiKey: string }) {
|
||||
super({ url, apiKey, cacheName: 'radarr', apiName: 'Radarr' });
|
||||
}
|
||||
|
||||
public getMovies = async (): Promise<RadarrMovie[]> => {
|
||||
try {
|
||||
const response = await this.axios.get<RadarrMovie[]>('/movie');
|
||||
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
throw new Error(`[Radarr] Failed to retrieve movies: ${e.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
public getMovie = async ({ id }: { id: number }): Promise<RadarrMovie> => {
|
||||
try {
|
||||
const response = await this.axios.get<RadarrMovie>(`/movie/${id}`);
|
||||
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
throw new Error(`[Radarr] Failed to retrieve movie: ${e.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
public async getMovieByTmdbId(id: number): Promise<RadarrMovie> {
|
||||
try {
|
||||
const response = await this.axios.get<RadarrMovie[]>('/movie/lookup', {
|
||||
params: {
|
||||
term: `tmdb:${id}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.data[0]) {
|
||||
throw new Error('Movie not found');
|
||||
}
|
||||
|
||||
return response.data[0];
|
||||
} catch (e) {
|
||||
logger.error('Error retrieving movie by TMDb ID', {
|
||||
label: 'Radarr API',
|
||||
message: e.message,
|
||||
});
|
||||
throw new Error('Movie not found');
|
||||
}
|
||||
}
|
||||
|
||||
public addMovie = async (
|
||||
options: RadarrMovieOptions
|
||||
): Promise<RadarrMovie> => {
|
||||
try {
|
||||
const movie = await this.getMovieByTmdbId(options.tmdbId);
|
||||
|
||||
if (movie.downloaded) {
|
||||
logger.info(
|
||||
'Title already exists and is available. Skipping add and returning success',
|
||||
{
|
||||
label: 'Radarr',
|
||||
}
|
||||
);
|
||||
return movie;
|
||||
}
|
||||
|
||||
// movie exists in radarr but is neither downloaded nor monitored
|
||||
if (movie.id && !movie.monitored) {
|
||||
const response = await this.axios.put<RadarrMovie>(`/movie`, {
|
||||
...movie,
|
||||
title: options.title,
|
||||
qualityProfileId: options.qualityProfileId,
|
||||
profileId: options.profileId,
|
||||
titleSlug: options.tmdbId.toString(),
|
||||
minimumAvailability: options.minimumAvailability,
|
||||
tmdbId: options.tmdbId,
|
||||
year: options.year,
|
||||
tags: options.tags,
|
||||
rootFolderPath: options.rootFolderPath,
|
||||
monitored: options.monitored,
|
||||
addOptions: {
|
||||
searchForMovie: options.searchNow,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data.monitored) {
|
||||
logger.info(
|
||||
'Found existing title in Radarr and set it to monitored. Returning success',
|
||||
{ label: 'Radarr' }
|
||||
);
|
||||
logger.debug('Radarr update details', {
|
||||
label: 'Radarr',
|
||||
movie: response.data,
|
||||
});
|
||||
return response.data;
|
||||
} else {
|
||||
logger.error('Failed to update existing movie in Radarr', {
|
||||
label: 'Radarr',
|
||||
options,
|
||||
});
|
||||
throw new Error('Failed to update existing movie in Radarr');
|
||||
}
|
||||
}
|
||||
|
||||
if (movie.id) {
|
||||
logger.info(
|
||||
'Movie is already monitored in Radarr. Skipping add and returning success',
|
||||
{ label: 'Radarr' }
|
||||
);
|
||||
return movie;
|
||||
}
|
||||
|
||||
const response = await this.axios.post<RadarrMovie>(`/movie`, {
|
||||
title: options.title,
|
||||
qualityProfileId: options.qualityProfileId,
|
||||
profileId: options.profileId,
|
||||
titleSlug: options.tmdbId.toString(),
|
||||
minimumAvailability: options.minimumAvailability,
|
||||
tmdbId: options.tmdbId,
|
||||
year: options.year,
|
||||
rootFolderPath: options.rootFolderPath,
|
||||
monitored: options.monitored,
|
||||
tags: options.tags,
|
||||
addOptions: {
|
||||
searchForMovie: options.searchNow,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.data.id) {
|
||||
logger.info('Radarr accepted request', { label: 'Radarr' });
|
||||
logger.debug('Radarr add details', {
|
||||
label: 'Radarr',
|
||||
movie: response.data,
|
||||
});
|
||||
} else {
|
||||
logger.error('Failed to add movie to Radarr', {
|
||||
label: 'Radarr',
|
||||
options,
|
||||
});
|
||||
throw new Error('Failed to add movie to Radarr');
|
||||
}
|
||||
return response.data;
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
'Failed to add movie to Radarr. This might happen if the movie already exists, in which case you can safely ignore this error.',
|
||||
{
|
||||
label: 'Radarr',
|
||||
errorMessage: e.message,
|
||||
options,
|
||||
response: e?.response?.data,
|
||||
}
|
||||
);
|
||||
throw new Error('Failed to add movie to Radarr');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default RadarrAPI;
|
||||
Reference in New Issue
Block a user