Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
140 changes: 140 additions & 0 deletions server/api/servarr/radarr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { afterEach, describe, it, mock } from 'node:test';

import type { AxiosInstance } from 'axios';

import type { RadarrMovieOptions } from '@server/api/servarr/radarr';
import RadarrAPI from '@server/api/servarr/radarr';

function buildRadarr(): RadarrAPI {
Expand Down Expand Up @@ -117,3 +118,142 @@ describe('RadarrAPI getMovieByTmdbId', () => {
});
});
});

describe('RadarrAPI addMovie', () => {
afterEach(() => mock.restoreAll());

it('does not trigger a search for an existing, monitored movie that is not yet available', async () => {
const radarr = buildRadarr();
const options: RadarrMovieOptions = {
title: 'Test Movie',
qualityProfileId: 1,
minimumAvailability: 'Released',
tags: [],
profileId: 1,
year: 2026,
rootFolderPath: '/movies',
tmdbId: 7,
searchNow: true,
};
mock.method(RadarrAPI.prototype, 'getMovieByTmdbId', async () => ({
id: 7,
title: 'Test Movie',
monitored: true,
hasFile: false,
isAvailable: false,
}));

const search = mock.method(
RadarrAPI.prototype,
'searchMovie',
async () => {}
);
await radarr.addMovie(options);

assert.strictEqual(search.mock.callCount(), 0);
});

it('triggers a search for an existing, monitored movie that is already available', async () => {
const radarr = buildRadarr();
const options: RadarrMovieOptions = {
title: 'Test Movie',
qualityProfileId: 1,
minimumAvailability: 'Released',
tags: [],
profileId: 1,
year: 2026,
rootFolderPath: '/movies',
tmdbId: 7,
searchNow: true,
};
mock.method(RadarrAPI.prototype, 'getMovieByTmdbId', async () => ({
id: 7,
title: 'Test Movie',
monitored: true,
hasFile: false,
isAvailable: true,
}));

const search = mock.method(
RadarrAPI.prototype,
'searchMovie',
async () => {}
);
await radarr.addMovie(options);

assert.strictEqual(search.mock.callCount(), 1);
});

it('does not trigger a search for an existing, previously unmonitored movie that is not yet available', async () => {
const radarr = buildRadarr();
const options: RadarrMovieOptions = {
title: 'Test Movie',
qualityProfileId: 1,
minimumAvailability: 'Released',
tags: [],
profileId: 1,
year: 2026,
rootFolderPath: '/movies',
tmdbId: 7,
monitored: true,
searchNow: true,
};
mock.method(RadarrAPI.prototype, 'getMovieByTmdbId', async () => ({
id: 7,
title: 'Test Movie',
monitored: false,
hasFile: false,
tags: [],
}));
const put = mock.method(getAxios(radarr), 'put', async () => ({
data: { id: 7, title: 'Test Movie', monitored: true, isAvailable: false },
}));

const search = mock.method(
RadarrAPI.prototype,
'searchMovie',
async () => {}
);
await radarr.addMovie(options);

assert.strictEqual(put.mock.callCount(), 1);
assert.strictEqual(search.mock.callCount(), 0);
});

it('triggers a search for an existing, previously unmonitored movie that is already available', async () => {
const radarr = buildRadarr();
const options: RadarrMovieOptions = {
title: 'Test Movie',
qualityProfileId: 1,
minimumAvailability: 'Released',
tags: [],
profileId: 1,
year: 2026,
rootFolderPath: '/movies',
tmdbId: 7,
monitored: true,
searchNow: true,
};
mock.method(RadarrAPI.prototype, 'getMovieByTmdbId', async () => ({
id: 7,
title: 'Test Movie',
monitored: false,
hasFile: false,
tags: [],
}));
const put = mock.method(getAxios(radarr), 'put', async () => ({
data: { id: 7, title: 'Test Movie', monitored: true, isAvailable: true },
}));

const search = mock.method(
RadarrAPI.prototype,
'searchMovie',
async () => {}
);
await radarr.addMovie(options);

assert.strictEqual(put.mock.callCount(), 1);
assert.strictEqual(search.mock.callCount(), 1);
assert.strictEqual(search.mock.calls[0].arguments[0], 7);
});
});
13 changes: 9 additions & 4 deletions server/api/servarr/radarr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,12 @@ class RadarrAPI extends ServarrBase<{ movieId: number }> {
movie: response.data,
});

if (options.searchNow) {
if (options.searchNow && response.data.isAvailable) {
logger.info('Movie is available, triggering Radarr search.', {
label: 'Radarr',
movieId: response.data.id,
movieTitle: response.data.title,
});
this.searchMovie(response.data.id);
}

Expand All @@ -207,10 +212,10 @@ class RadarrAPI extends ServarrBase<{ movieId: number }> {
hasFile: movie.hasFile,
});

// If searchNow is requested and movie doesn't have a file, trigger search
if (options.searchNow && !movie.hasFile) {
// If searchNow is requested, movie doesn't have a file, and Radarr considers the movie 'available' then trigger search
if (options.searchNow && !movie.hasFile && movie.isAvailable) {
logger.info(
'Triggering search for existing monitored movie without file',
'Triggering search for existing, available, monitored movie without file',
{
label: 'Radarr',
movieId: movie.id,
Expand Down