mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 04:40:09 +00:00
20798b3dc0
Introduce RDT-Client integration and related UI/behavior changes. - Add RDTClientService extending QBittorrentService with RDT-specific behavior (stale-torrent deletion, postProcess cleanup, no-op categories). - Register 'rdtclient' in supported client types, display names, and protocol mapping; create RDT client factory in DownloadClientManager. - Add RDT-Client card to DownloadClientManagement UI and placeholder URL in DownloadClientModal. - Update qbittorrent service: omit per-torrent savepath/sequential options (favor category/automatic management), make several methods protected, and clean up related comments. - Make organize-files.processor treat rdtclient as a special-case for cleanup (remove local torrent entries after organize). - Add prowlarr service singleton invalidation and call it when Prowlarr settings are updated so background jobs pick up new credentials. - Add confirmation flow when changing Prowlarr URL/API key: new useIndexersSettings logic to detect credential changes, prompt ConfirmModal from IndexersTab, and optionally clear configured indexers on confirmed change. These changes ensure Real-Debrid-backed qBittorrent-compatible clients are supported correctly and that switching Prowlarr credentials is handled safely.
144 lines
4.1 KiB
TypeScript
144 lines
4.1 KiB
TypeScript
/**
|
|
* Component: Indexers Settings Tab - Custom Hook
|
|
* Documentation: documentation/settings-pages.md
|
|
*/
|
|
|
|
'use client';
|
|
|
|
import { useState, useCallback } from 'react';
|
|
import { fetchWithAuth } from '@/lib/utils/api';
|
|
import type { TestResult } from '../../lib/types';
|
|
|
|
interface UseIndexersSettingsProps {
|
|
prowlarrUrl: string;
|
|
prowlarrApiKey: string;
|
|
originalProwlarrUrl: string;
|
|
originalProwlarrApiKey: string;
|
|
configuredIndexersCount: number;
|
|
onValidationChange: (isValid: boolean) => void;
|
|
onRefreshIndexers?: () => Promise<void>;
|
|
onClearIndexers: () => void;
|
|
}
|
|
|
|
export function useIndexersSettings({
|
|
prowlarrUrl,
|
|
prowlarrApiKey,
|
|
originalProwlarrUrl,
|
|
originalProwlarrApiKey,
|
|
configuredIndexersCount,
|
|
onValidationChange,
|
|
onRefreshIndexers,
|
|
onClearIndexers,
|
|
}: UseIndexersSettingsProps) {
|
|
const [testing, setTesting] = useState(false);
|
|
const [testResult, setTestResult] = useState<TestResult | null>(null);
|
|
const [showConnectionChangeConfirm, setShowConnectionChangeConfirm] = useState(false);
|
|
|
|
/**
|
|
* Detect if the Prowlarr URL or API key has changed from the saved values.
|
|
* A masked API key (starting with dots) means the user hasn't touched it.
|
|
*/
|
|
const hasConnectionChanged = useCallback((): boolean => {
|
|
const urlChanged = prowlarrUrl.trim() !== originalProwlarrUrl.trim();
|
|
const apiKeyChanged = !prowlarrApiKey.startsWith('••••') &&
|
|
prowlarrApiKey !== originalProwlarrApiKey;
|
|
return urlChanged || apiKeyChanged;
|
|
}, [prowlarrUrl, prowlarrApiKey, originalProwlarrUrl, originalProwlarrApiKey]);
|
|
|
|
/**
|
|
* Execute the actual Prowlarr connection test
|
|
*/
|
|
const executeTest = async (shouldClearIndexers: boolean) => {
|
|
setTesting(true);
|
|
setTestResult(null);
|
|
|
|
try {
|
|
const response = await fetchWithAuth('/api/admin/settings/test-prowlarr', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
url: prowlarrUrl,
|
|
apiKey: prowlarrApiKey,
|
|
}),
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.success) {
|
|
onValidationChange(true);
|
|
|
|
if (shouldClearIndexers) {
|
|
onClearIndexers();
|
|
setTestResult({
|
|
success: true,
|
|
message: `Connected to Prowlarr. Found ${data.indexers?.length || 0} indexers. Previous indexer configurations have been removed — please re-add indexers from the new instance.`,
|
|
});
|
|
} else {
|
|
setTestResult({
|
|
success: true,
|
|
message: `Connected to Prowlarr. Found ${data.indexers?.length || 0} indexers`,
|
|
});
|
|
|
|
// Refresh indexers from database if callback provided
|
|
if (onRefreshIndexers) {
|
|
await onRefreshIndexers();
|
|
}
|
|
}
|
|
} else {
|
|
onValidationChange(false);
|
|
setTestResult({
|
|
success: false,
|
|
message: data.error || 'Connection failed',
|
|
});
|
|
}
|
|
} catch (error) {
|
|
onValidationChange(false);
|
|
const errorMsg = error instanceof Error ? error.message : 'Failed to test connection';
|
|
setTestResult({
|
|
success: false,
|
|
message: errorMsg,
|
|
});
|
|
} finally {
|
|
setTesting(false);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle test connection click — shows confirmation if credentials changed
|
|
* and there are existing configured indexers.
|
|
*/
|
|
const testConnection = async () => {
|
|
if (hasConnectionChanged() && configuredIndexersCount > 0) {
|
|
setShowConnectionChangeConfirm(true);
|
|
return;
|
|
}
|
|
|
|
await executeTest(false);
|
|
};
|
|
|
|
/**
|
|
* User confirmed the credential change — proceed with test and clear indexers on success
|
|
*/
|
|
const confirmConnectionChange = async () => {
|
|
setShowConnectionChangeConfirm(false);
|
|
await executeTest(true);
|
|
};
|
|
|
|
/**
|
|
* User cancelled the credential change confirmation
|
|
*/
|
|
const cancelConnectionChange = () => {
|
|
setShowConnectionChangeConfirm(false);
|
|
};
|
|
|
|
return {
|
|
testing,
|
|
testResult,
|
|
testConnection,
|
|
showConnectionChangeConfirm,
|
|
confirmConnectionChange,
|
|
cancelConnectionChange,
|
|
configuredIndexersCount,
|
|
};
|
|
}
|