Refactor arr routes: explicit dependency injection
- Updated all arr route modules to use destructured dependencies - Added JSDoc comments for factory functions - Replaced ctx. references with direct parameter access - Updated arr/index.js to extract and pass explicit dependencies - Maintained backward compatibility with context pattern - All files pass syntax validation Files refactored: - routes/arr/detect.js - routes/arr/credentials.js - routes/arr/config.js (579 lines) - routes/arr/smart-connect.js - routes/arr/plex.js - routes/arr/helpers.js - routes/arr/index.js (orchestrator)
This commit is contained in:
@@ -1,11 +1,22 @@
|
||||
const express = require('express');
|
||||
const { APP_PORTS } = require('../../constants');
|
||||
|
||||
module.exports = function(ctx, helpers) {
|
||||
/**
|
||||
* Arr smart-connect routes factory
|
||||
* @param {Object} deps - Explicit dependencies
|
||||
* @param {Object} deps.credentialManager - Credential manager
|
||||
* @param {Function} deps.fetchT - Timeout-wrapped fetch
|
||||
* @param {Function} deps.asyncHandler - Async route handler wrapper
|
||||
* @param {Function} deps.errorResponse - Error response helper
|
||||
* @param {Object} deps.log - Logger instance
|
||||
* @param {Object} deps.helpers - Arr helpers module
|
||||
* @returns {express.Router}
|
||||
*/
|
||||
module.exports = function({ credentialManager, fetchT, asyncHandler, errorResponse, log, helpers }) {
|
||||
const router = express.Router();
|
||||
|
||||
// Smart Connect: Unified orchestration endpoint
|
||||
router.post('/arr/smart-connect', ctx.asyncHandler(async (req, res) => {
|
||||
router.post('/arr/smart-connect', asyncHandler(async (req, res) => {
|
||||
const { services: inputServices, configurePlex, configureProwlarr, configureSeerr, saveCredentials } = req.body;
|
||||
const steps = [];
|
||||
const connectedServices = {}; // { radarr: { url, apiKey }, sonarr: { url, apiKey }, ... }
|
||||
@@ -20,9 +31,9 @@ module.exports = function(ctx, helpers) {
|
||||
// Fallback to stored credentials
|
||||
if (!apiKey) {
|
||||
const credKey = `arr.${svc}.apikey`;
|
||||
apiKey = await ctx.credentialManager.retrieve(credKey);
|
||||
apiKey = await credentialManager.retrieve(credKey);
|
||||
if (!url) {
|
||||
const metadata = await ctx.credentialManager.getMetadata(credKey);
|
||||
const metadata = await credentialManager.getMetadata(credKey);
|
||||
url = metadata?.url;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +63,7 @@ module.exports = function(ctx, helpers) {
|
||||
|
||||
// Save credentials
|
||||
if (saveCredentials) {
|
||||
const stored = await ctx.credentialManager.store(`arr.${svc}.apikey`, apiKey, {
|
||||
const stored = await credentialManager.store(`arr.${svc}.apikey`, apiKey, {
|
||||
service: svc, source: 'external', url,
|
||||
lastVerified: new Date().toISOString(),
|
||||
version: test.version
|
||||
@@ -71,7 +82,7 @@ module.exports = function(ctx, helpers) {
|
||||
let plexUrl = null;
|
||||
if (configurePlex) {
|
||||
plexToken = await helpers.getPlexToken('plex');
|
||||
if (!plexToken) plexToken = await ctx.credentialManager.retrieve('arr.plex.token');
|
||||
if (!plexToken) plexToken = await credentialManager.retrieve('arr.plex.token');
|
||||
|
||||
if (plexToken) {
|
||||
// Get Plex URL
|
||||
@@ -108,14 +119,14 @@ module.exports = function(ctx, helpers) {
|
||||
const radarrBasePath = radarrUrlObj.pathname.replace(/\/+$/, '');
|
||||
|
||||
// Fetch quality profiles
|
||||
const profilesRes = await ctx.fetchT(`${radarrUrl}/api/v3/qualityprofile`, {
|
||||
const profilesRes = await fetchT(`${radarrUrl}/api/v3/qualityprofile`, {
|
||||
headers: { 'X-Api-Key': connectedServices.radarr.apiKey },
|
||||
signal: AbortSignal.timeout(10000)
|
||||
});
|
||||
const profiles = profilesRes.ok ? await profilesRes.json() : [];
|
||||
|
||||
// Use stored quality profile preference, fallback to first profile
|
||||
const radarrMeta = await ctx.credentialManager.getMetadata('arr.radarr.apikey');
|
||||
const radarrMeta = await credentialManager.getMetadata('arr.radarr.apikey');
|
||||
let defaultProfile = profiles[0] || { id: 1, name: 'Any' };
|
||||
if (radarrMeta?.qualityProfileId) {
|
||||
const stored = profiles.find(p => p.id === radarrMeta.qualityProfileId);
|
||||
@@ -123,7 +134,7 @@ module.exports = function(ctx, helpers) {
|
||||
}
|
||||
|
||||
// Fetch root folders
|
||||
const rootFoldersRes = await ctx.fetchT(`${radarrUrl}/api/v3/rootfolder`, {
|
||||
const rootFoldersRes = await fetchT(`${radarrUrl}/api/v3/rootfolder`, {
|
||||
headers: { 'X-Api-Key': connectedServices.radarr.apiKey },
|
||||
signal: AbortSignal.timeout(10000)
|
||||
});
|
||||
@@ -151,7 +162,7 @@ module.exports = function(ctx, helpers) {
|
||||
tags: []
|
||||
};
|
||||
|
||||
const radarrRes = await ctx.fetchT(`${overseerrUrl}/api/v1/settings/radarr`, {
|
||||
const radarrRes = await fetchT(`${overseerrUrl}/api/v1/settings/radarr`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Cookie': overseerrCookie },
|
||||
body: JSON.stringify(radarrConfig),
|
||||
@@ -175,21 +186,21 @@ module.exports = function(ctx, helpers) {
|
||||
const sonarrUrlObj = new URL(sonarrUrl);
|
||||
const sonarrBasePath = sonarrUrlObj.pathname.replace(/\/+$/, '');
|
||||
|
||||
const profilesRes = await ctx.fetchT(`${sonarrUrl}/api/v3/qualityprofile`, {
|
||||
const profilesRes = await fetchT(`${sonarrUrl}/api/v3/qualityprofile`, {
|
||||
headers: { 'X-Api-Key': connectedServices.sonarr.apiKey },
|
||||
signal: AbortSignal.timeout(10000)
|
||||
});
|
||||
const profiles = profilesRes.ok ? await profilesRes.json() : [];
|
||||
|
||||
// Use stored quality profile preference, fallback to first profile
|
||||
const sonarrMeta = await ctx.credentialManager.getMetadata('arr.sonarr.apikey');
|
||||
const sonarrMeta = await credentialManager.getMetadata('arr.sonarr.apikey');
|
||||
let defaultProfile = profiles[0] || { id: 1, name: 'Any' };
|
||||
if (sonarrMeta?.qualityProfileId) {
|
||||
const stored = profiles.find(p => p.id === sonarrMeta.qualityProfileId);
|
||||
if (stored) defaultProfile = stored;
|
||||
}
|
||||
|
||||
const rootFoldersRes = await ctx.fetchT(`${sonarrUrl}/api/v3/rootfolder`, {
|
||||
const rootFoldersRes = await fetchT(`${sonarrUrl}/api/v3/rootfolder`, {
|
||||
headers: { 'X-Api-Key': connectedServices.sonarr.apiKey },
|
||||
signal: AbortSignal.timeout(10000)
|
||||
});
|
||||
@@ -198,7 +209,7 @@ module.exports = function(ctx, helpers) {
|
||||
|
||||
let languageProfileId = 1;
|
||||
try {
|
||||
const langRes = await ctx.fetchT(`${sonarrUrl}/api/v3/languageprofile`, {
|
||||
const langRes = await fetchT(`${sonarrUrl}/api/v3/languageprofile`, {
|
||||
headers: { 'X-Api-Key': connectedServices.sonarr.apiKey },
|
||||
signal: AbortSignal.timeout(5000)
|
||||
});
|
||||
@@ -229,7 +240,7 @@ module.exports = function(ctx, helpers) {
|
||||
tags: []
|
||||
};
|
||||
|
||||
const sonarrRes = await ctx.fetchT(`${overseerrUrl}/api/v1/settings/sonarr`, {
|
||||
const sonarrRes = await fetchT(`${overseerrUrl}/api/v1/settings/sonarr`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Cookie': overseerrCookie },
|
||||
body: JSON.stringify(sonarrConfig),
|
||||
|
||||
Reference in New Issue
Block a user