mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-03 12:50:09 +00:00
Add remote path mapping for qBittorrent integration
Implements remote-to-local path mapping for qBittorrent downloads, allowing the app to handle differing filesystem paths between qBittorrent and the local environment (e.g., remote seedboxes, Docker). Adds UI controls in admin settings and setup wizard, validates mapping configuration, and applies path transformation in download and import processors. Updates documentation, API routes, and data models to support the new feature. Also improves library scan logic to remove stale records and reset orphaned audiobooks and requests. Increases minimum torrent score threshold from 30 to 50 in search and ranking logic, and exposes torrent source URLs in the admin UI.
This commit is contained in:
@@ -70,6 +70,9 @@ interface Settings {
|
||||
url: string;
|
||||
username: string;
|
||||
password: string;
|
||||
remotePathMappingEnabled: boolean;
|
||||
remotePath: string;
|
||||
localPath: string;
|
||||
};
|
||||
paths: {
|
||||
downloadDir: string;
|
||||
@@ -648,6 +651,9 @@ export default function AdminSettings() {
|
||||
url: settings.downloadClient.url,
|
||||
username: settings.downloadClient.username,
|
||||
password: settings.downloadClient.password,
|
||||
remotePathMappingEnabled: settings.downloadClient.remotePathMappingEnabled,
|
||||
remotePath: settings.downloadClient.remotePath,
|
||||
localPath: settings.downloadClient.localPath,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1196,7 +1202,7 @@ export default function AdminSettings() {
|
||||
<option value="">Select a library...</option>
|
||||
{absLibraries.map((lib) => (
|
||||
<option key={lib.id} value={lib.id}>
|
||||
{lib.name} ({lib.itemCount} items)
|
||||
{lib.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -1545,6 +1551,104 @@ export default function AdminSettings() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Remote Path Mapping */}
|
||||
<div className="mt-6 bg-gray-50 dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
|
||||
<div className="flex items-start gap-4">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="remote-path-mapping"
|
||||
checked={settings.downloadClient.remotePathMappingEnabled}
|
||||
onChange={(e) => {
|
||||
setSettings({
|
||||
...settings,
|
||||
downloadClient: {
|
||||
...settings.downloadClient,
|
||||
remotePathMappingEnabled: e.target.checked,
|
||||
},
|
||||
});
|
||||
setValidated({ ...validated, download: false });
|
||||
}}
|
||||
className="mt-1 h-5 w-5 rounded border-gray-300 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<label
|
||||
htmlFor="remote-path-mapping"
|
||||
className="block text-sm font-medium text-gray-900 dark:text-gray-100 cursor-pointer"
|
||||
>
|
||||
Enable Remote Path Mapping
|
||||
</label>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
Use this when qBittorrent runs on a different machine or uses different mount points (e.g., remote seedbox, Docker containers)
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2 font-mono">
|
||||
Example: Remote <span className="text-blue-600 dark:text-blue-400">/remote/mnt/d/done</span> → Local <span className="text-green-600 dark:text-green-400">/downloads</span>
|
||||
</p>
|
||||
|
||||
{/* Warning for existing downloads */}
|
||||
{settings.downloadClient.remotePathMappingEnabled && (
|
||||
<div className="mt-3 p-3 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
||||
<p className="text-sm text-yellow-800 dark:text-yellow-200">
|
||||
⚠️ <strong>Note:</strong> Path mapping only affects new downloads. In-progress downloads will continue using their original paths.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Conditional Fields */}
|
||||
{settings.downloadClient.remotePathMappingEnabled && (
|
||||
<div className="mt-4 grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Remote Path (from qBittorrent)
|
||||
</label>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="/remote/mnt/d/done"
|
||||
value={settings.downloadClient.remotePath}
|
||||
onChange={(e) => {
|
||||
setSettings({
|
||||
...settings,
|
||||
downloadClient: {
|
||||
...settings.downloadClient,
|
||||
remotePath: e.target.value,
|
||||
},
|
||||
});
|
||||
setValidated({ ...validated, download: false });
|
||||
}}
|
||||
/>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
The path prefix as reported by qBittorrent
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Local Path (for ReadMeABook)
|
||||
</label>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="/downloads"
|
||||
value={settings.downloadClient.localPath}
|
||||
onChange={(e) => {
|
||||
setSettings({
|
||||
...settings,
|
||||
downloadClient: {
|
||||
...settings.downloadClient,
|
||||
localPath: e.target.value,
|
||||
},
|
||||
});
|
||||
setValidated({ ...validated, download: false });
|
||||
}}
|
||||
/>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
The actual path where files are accessible
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-200 dark:border-gray-700 pt-6">
|
||||
<Button
|
||||
onClick={testDownloadClientConnection}
|
||||
|
||||
Reference in New Issue
Block a user