Introduce manual import workflow and download permission support. Adds a Prisma migration and schema field (users.download_access) to track per-user download access, and updates admin UI to toggle global and per-user download access. Implements new APIs: filesystem browse, manual-import endpoint, download-access settings, audiobook download-status, and on-demand download-token generation. Adds frontend components for manual import and related tests, plus documentation for the manual-import feature and the documentation-agent prompt. Key files: prisma/migrations/20260212000000_add_download_access_permission/migration.sql, prisma/schema.prisma, src/app/api/admin/filesystem/browse/route.ts, src/app/api/admin/manual-import/route.ts, src/app/api/admin/settings/download-access/route.ts, src/app/api/requests/[id]/download-token/route.ts, src/app/api/audiobooks/[asin]/download-status/route.ts, and updated admin users pages/components and permissions util.
Document an optional 'bookdrop' host folder in docker-compose.yml with a commented example volume mount for the Manual Import (Admin → audiobook → Manual Import) file picker, and add /bookdrop to .gitignore so local bookdrop mounts are not tracked.
- jwt.ts: Use JWT_DOWNLOAD_SECRET instead of JWT_SECRET for download tokens
- audio-formats.ts: Add EBOOK_EXTENSIONS export alongside AUDIO_EXTENSIONS
- request-statuses.ts: New shared COMPLETED_STATUSES constant used across requests API, download route, and RequestCard
- requests/route.ts: Import COMPLETED_STATUSES; strip filePath from audiobook in API response
- download/route.ts: Import format/status constants; add archiver dependency and replace adm-zip with streaming archiver for multi-file zips
- RequestCard.tsx: Use shared COMPLETED_STATUSES constant
Embeds a signed JWT download token (30-day expiry) in the requests API
response so users can download completed audiobook/ebook files directly
from the UI or by sharing the URL to apps like BookPlayer — no session
cookie required.
- jwt.ts: add generateDownloadToken / verifyDownloadToken helpers
- api/requests: append downloadUrl to completed requests with a filePath
- api/requests/[id]/download: new token-authenticated streaming endpoint;
serves single files directly or zips multi-file audiobooks with adm-zip
- RequestCard: add Download link in the actions area for completed requests
Always use qBittorrent's content_path as the canonical downloadPath and expose savePath on DownloadInfo instead of reconstructing paths from save_path + basename. Add path-waiting logic to the monitor: track consecutive pathWaitCount polls, re-queue the monitor with exponential-ish backoff while content_path remains outside save_path (to handle TempPathEnabled races), and give up after a configurable max attempts. Extend the MonitorDownload payload and JobQueue APIs to carry pathWaitCount. Organize-files processor now attempts to refresh the stored downloadPath from the download client and updates downloadHistory if the client reports a different path (applying path mapping). Update tests to reflect the new behavior and expectations.
When a torrent is finished (seeding/completed), build the download path from save_path combined with the basename of content_path instead of using torrent.name or the full content_path. This fixes a race with qBittorrent's TempPathEnabled (where content_path may still point to the temp dir) and addresses cases where the displayed torrent.name differs from the actual root folder/filename on disk. Added/updated tests to cover the TempPathEnabled race, name-mismatch scenarios, empty content_path fallback, and single-file torrents.
Add support for admin-driven interactive torrent selection and a file rename/template feature. Integrates an InteractiveTorrentSearchModal into the pending-approval admin UI, adds an admin approve flow that accepts an admin-selected torrent, and surfaces user/admin-selected torrent details in the UI. Introduces fileRenameEnabled and fileRenameTemplate settings (API + UI), persists them to configuration, and clears related caches. Pass renameConfig through the organize/organizeEbook flows and implement renaming in the FileOrganizer (single/multi-file handling). Enhance path-template utilities with conditional block resolution, filename-template validation, mock filename previews, and a buildRenamedFilename helper. Update tests to cover conditional templates and filename preview behavior.
Resolve downloadPath using save_path for finished torrents to avoid TempPathEnabled race conditions where content_path can point to a stale temp location. Compute status once, treat 'seeding'/'completed' as finished, and prefer path.join(save_path, name) for those states while still using content_path (or falling back to save_path) for active downloads. Added tests covering multiple qBittorrent states (seeding/stalledUP/pausedUP/stoppedUP/forcedUP/queuedUP/downloading and empty content_path) and imported path in tests.
Add DOWNLOAD_CLIENT_TIMEOUT (60000ms) in src/lib/constants/download-timeouts.ts and replace hardcoded 60000ms timeouts across Deluge, Prowlarr, qBittorrent and Transmission integrations. This centralizes the download/API timeout (gives headroom for indexers that enforce ~30s waits) and makes future adjustments easier without changing behavior.
Trim whitespace in the French stopWords array (add missing space after comma) to keep formatting consistent, and rename AUDIBLE_REGIONS.fr.name from "French" to "France" to better reflect the region label used for the Audible configuration.
Delete legacy configuration API handlers and their tests. Removes src/app/api/config/route.ts (GET/PUT for config), src/app/api/config/[category]/route.ts (category GET), and tests/api/config.routes.test.ts. This cleans up deprecated/duplicated config endpoints and associated tests from the codebase.
Introduce Deluge download client service and tests, remove obsolete rdtclient service, and update qbittorrent integration/tests and download-client interfaces/manager. Large UI refactor for admin pages: Jobs and Logs were redesigned to be responsive (mobile card views + desktop tables), improved headers, dialogs, controls, and better status/detail rendering. Also updated DownloadClient components (card, management, modal), organize-files processor, audible-series integration, and related unit tests to align with integration changes. Minor UX and accessibility tweaks, cron handling/validation adjustments, and a few formatting/cleanup fixes throughout.
Introduce full support for Audible series exploration: API routes, frontend pages, components, hooks, and integrations. Key changes:
- Prisma: add Audiobook.seriesAsin for linking audiobooks to series detail pages.
- Backend: add /api/series/search and /api/series/[asin] routes that require auth; scrape Audible series data and enrich books with library availability.
- Integrations/services: add audible-series integration and update request/HTTP services to support the workflow.
- Frontend: add /series and /series/[asin] pages, new components (SeriesCard, SeriesGrid, SeriesDetailCard, SimilarSeriesRow) and wire them to a new useSeries hook; update AudiobookDetailsModal to show/link series; add Series link to Header.
- Misc: extend audiobook types with series fields and add seriesLabels to language-config for scraping.
These changes enable users to search for series, view series metadata and books, and navigate between audiobook and series detail pages.
Introduce centralized language configuration and wire locale-aware behavior across scraping and ranking. Adds src/lib/constants/language-config.ts with per-language scraping rules, stop words, and character replacements; replaces AudibleRegion.isEnglish with a language field in types and AUDIBLE_REGIONS. Update AudibleService, ebook scraper, processors, and API routes to use getLanguageForRegion so Anna's Archive searches, scraping selectors, runtime/rating parsing, and ranking use language-specific params and filters. Extend ranking algorithm to accept stopWords and characterReplacements and apply them during normalization and matching. Update UI selects to mark non-English regions and adjust tests accordingly.
Pass sanitizedCustomPath through directly instead of using `sanitizedCustomPath || undefined`. The previous fallback converted falsy values (e.g. empty string) to undefined; this change preserves explicit empty or falsy values so downstream logic can distinguish them from undefined.
Add connection pool params to DATABASE_URL and configure Prisma to use the pooled URL (connection_limit=20, pool_timeout=30) to reduce connection exhaustion. Introduce safeguards and throttling across processors: limit in-flight progress DB updates in direct-download, add short delays when processing RSS, retry-failed-imports, and retry-missing-torrents, and stagger scheduler triggers to avoid bursts. Implement adaptive monitor-download polling with stallCount/lastProgress and exponential backoff, and thread these fields through JobQueueService (including reduced worker concurrency for several queues). Batch audiobook enrichment queries to small parallel batches to limit DB load. Update tests to reflect new monitor payload parameters. Overall intent: reduce DB connection pool pressure and smooth load spikes during startup and heavy processing.
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.
Wait for the Next.js server and DB to be healthy before initializing services in docker/unified/app-start.sh. Adds a health probe with configurable timeout and retries, backoff retries for the /api/init call, improved logging, and error handling when the server process exits.
In src/lib/services/scheduler.service.ts, make re-encryption of notification backends non-fatal by catching and logging errors, and make creation of default scheduled jobs robust by creating each job independently with per-job error handling and logging. Summary counts are logged for created/failed defaults so failures don't block the scheduler from starting.
Add a getBaseUrl mock to audibleServiceMock in audiobooks-browse route tests that returns 'https://www.audible.com'. This ensures tests have a defined base URL for Audible service calls and prevents issues caused by an undefined method during test execution.
Improve entrypoint handling for external services and startup wrappers. entrypoint.sh now more robustly parses REDIS_URL (handles optional :password@host) and masks credentials when printing DATABASE_URL/REDIS_URL. It exports USE_EXTERNAL_POSTGRES and USE_EXTERNAL_REDIS so supervisor wrappers can decide behavior without re-parsing URLs. The temporary PostgreSQL shutdown was moved to after Prisma migrations and a warning was added when pushing schema to an external DB. postgres-start.sh and redis-start.sh were simplified to check the USE_EXTERNAL_* flags and sleep if an external service is configured. Also cleaned up formatting of the PostgreSQL ownership error message.
Introduce full authors browsing/detail feature and enhance notifications to support type-specific titles.
- Add server APIs: authors search, author detail, and author books routes (audnexus integration) that require auth and enrich results with library matches.
- Add frontend pages/components: /authors listing and /authors/[asin] detail pages; AuthorCard, AuthorGrid, AuthorDetailCard, SimilarAuthorsRow, and related skeletons.
- Add hook and integration stubs: new useAuthors hook and audnexus-authors integration; update audible service to expose audibleBaseUrl.
- Update AudiobookDetailsModal to use audibleBaseUrl and link author names to author detail pages.
- Add header navigation link to Authors.
- Notifications: extend docs and code to include requestType (audiobook|ebook), add getEventTitle/getEventMeta helpers, update queue signature and providers/processors/tests to pass/handle requestType so titles can be resolved per request type.
- Misc: job queue, processors, provider tests and notification tests updated to reflect new behavior.
This change enables browsing authors and provides type-aware notification titles without per-provider changes.
Try the full Goodreads title first; if no ASIN is found, strip trailing parenthetical series info (e.g. "(Series, #2)"), retry the Audible search with the cleaned title, and add informative logs. This fixes failed Audible lookups caused by Goodreads titles that include series metadata.
Implements smart detection that allows users to provide external DATABASE_URL
or REDIS_URL. When external services are detected, internal instances are
automatically disabled to save resources. Maintains full backward compatibility
with existing setup