radarr_review_setup
Analyze Radarr movie management configuration to identify issues and optimize settings for quality profiles, download clients, naming, storage, and indexers.
Instructions
Get comprehensive configuration review for Radarr (Movies). Returns all settings for analysis: quality profiles, download clients, naming, storage, indexers, health warnings, and more. Use this to analyze the setup and suggest improvements.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/index.ts:163-170 (registration)Tool registration and schema definition for generic {service}_review_setup (instantiated as radarr_review_setup when serviceName='radarr') added to TOOLS array.name: `${serviceName}_review_setup`, description: `Get comprehensive configuration review for ${displayName}. Returns all settings for analysis: quality profiles, download clients, naming, storage, indexers, health warnings, and more. Use this to analyze the setup and suggest improvements.`, inputSchema: { type: "object" as const, properties: {}, required: [], }, }
- src/index.ts:176-176 (registration)Conditional invocation of addConfigTools('radarr') which registers the radarr_review_setup tool if Radarr client is configured.if (clients.radarr) addConfigTools('radarr', 'Radarr (Movies)');
- src/index.ts:950-1054 (handler)Main handler logic for radarr_review_setup tool. Extracts service name, fetches all relevant configuration data using RadarrClient methods, assembles and returns a structured JSON review of the setup.case "sonarr_review_setup": case "radarr_review_setup": case "lidarr_review_setup": case "readarr_review_setup": { const serviceName = name.split('_')[0] as keyof typeof clients; const client = clients[serviceName]; if (!client) throw new Error(`${serviceName} not configured`); // Gather all configuration data const [status, health, qualityProfiles, qualityDefinitions, downloadClients, naming, mediaManagement, rootFolders, tags, indexers] = await Promise.all([ client.getStatus(), client.getHealth(), client.getQualityProfiles(), client.getQualityDefinitions(), client.getDownloadClients(), client.getNamingConfig(), client.getMediaManagement(), client.getRootFoldersDetailed(), client.getTags(), client.getIndexers(), ]); // For Lidarr/Readarr, also get metadata profiles let metadataProfiles = null; if (serviceName === 'lidarr' && clients.lidarr) { metadataProfiles = await clients.lidarr.getMetadataProfiles(); } else if (serviceName === 'readarr' && clients.readarr) { metadataProfiles = await clients.readarr.getMetadataProfiles(); } const review = { service: serviceName, version: status.version, appName: status.appName, platform: { os: status.osName, isDocker: status.isDocker, }, health: { issueCount: health.length, issues: health, }, storage: { rootFolders: rootFolders.map(f => ({ path: f.path, accessible: f.accessible, freeSpace: formatBytes(f.freeSpace), freeSpaceBytes: f.freeSpace, unmappedFolderCount: f.unmappedFolders?.length || 0, })), }, qualityProfiles: qualityProfiles.map(p => ({ id: p.id, name: p.name, upgradeAllowed: p.upgradeAllowed, cutoff: p.cutoff, allowedQualities: p.items .filter(i => i.allowed) .map(i => i.quality?.name || i.name || (i.items?.map(q => q.quality.name).join(', '))) .filter(Boolean), customFormatsWithScores: p.formatItems?.filter(f => f.score !== 0).length || 0, minFormatScore: p.minFormatScore, })), qualityDefinitions: qualityDefinitions.map(d => ({ quality: d.quality.name, minSize: d.minSize + ' MB/min', maxSize: d.maxSize === 0 ? 'unlimited' : d.maxSize + ' MB/min', preferredSize: d.preferredSize + ' MB/min', })), downloadClients: downloadClients.map(c => ({ name: c.name, type: c.implementationName, protocol: c.protocol, enabled: c.enable, priority: c.priority, })), indexers: indexers.map(i => ({ name: i.name, protocol: i.protocol, enableRss: i.enableRss, enableAutomaticSearch: i.enableAutomaticSearch, enableInteractiveSearch: i.enableInteractiveSearch, priority: i.priority, })), naming: naming, mediaManagement: { recycleBin: mediaManagement.recycleBin || 'not set', recycleBinCleanupDays: mediaManagement.recycleBinCleanupDays, downloadPropersAndRepacks: mediaManagement.downloadPropersAndRepacks, deleteEmptyFolders: mediaManagement.deleteEmptyFolders, copyUsingHardlinks: mediaManagement.copyUsingHardlinks, importExtraFiles: mediaManagement.importExtraFiles, extraFileExtensions: mediaManagement.extraFileExtensions, }, tags: tags.map(t => t.label), ...(metadataProfiles && { metadataProfiles }), }; return { content: [{ type: "text", text: JSON.stringify(review, null, 2), }], }; }
- src/arr-client.ts:673-727 (helper)RadarrClient class providing API client methods (inherits from ArrClient which implements getStatus, getHealth, getQualityProfiles, etc. used by the review handler).export class RadarrClient extends ArrClient { constructor(config: ArrConfig) { super('radarr', config); } /** * Get all movies */ async getMovies(): Promise<Movie[]> { return this['request']<Movie[]>('/movie'); } /** * Get a specific movie */ async getMovieById(id: number): Promise<Movie> { return this['request']<Movie>(`/movie/${id}`); } /** * Search for movies */ async searchMovies(term: string): Promise<SearchResult[]> { return this['request']<SearchResult[]>(`/movie/lookup?term=${encodeURIComponent(term)}`); } /** * Add a movie */ async addMovie(movie: Partial<Movie> & { tmdbId: number; rootFolderPath: string; qualityProfileId: number }): Promise<Movie> { return this['request']<Movie>('/movie', { method: 'POST', body: JSON.stringify({ ...movie, monitored: movie.monitored ?? true, addOptions: { searchForMovie: true, }, }), }); } /** * Trigger a search for a movie */ async searchMovie(movieId: number): Promise<{ id: number }> { return this['request']<{ id: number }>('/command', { method: 'POST', body: JSON.stringify({ name: 'MoviesSearch', movieIds: [movieId], }), }); } }