Ombi's TV API nests all request data (requestedUser, approved, available,
denied, requested, requestedDate) inside childRequests[] sub-objects.
The application previously only inspected top-level properties, causing
TV shows to consistently display 'unknown' status, 'unknown' user, and
no request date.
Changes:
- OmbiRetriever._hydrateRequest(): hydrate requestedUser on each
childRequests entry and promote requestedDate to top level
- getRequestStatus() (server + client): aggregate status flags from
childRequests[] when top-level properties are absent
- Client date display: fallback to childRequests[0].requestedDate
- Add 18 unit tests covering childRequests hydration, status
aggregation, and date promotion
Closes#53
Fixes the root cause of the regression from v1.7.16. The v1.7.16 fix
correctly cast arrQueueId to String, but the lookup was performed
against downloadClientRegistry.getAllDownloads() which returns raw
download client data (qBittorrent, SABnzbd, etc.) that never has
arrQueueId populated.
The fix now looks up the queue record directly from the Sonarr/Radarr
queue cache where record.id is the numeric queue ID, using String()
casting on both sides to handle the DOM-dataset (string) vs API
response (number) type difference.
Resolves Gitea Issue #48Closes#48
- Cast arrQueueId to String in both sides of the download lookup comparison
in /api/dashboard/blocklist-search to resolve false-negative match failure
caused by DOM dataset string vs Radarr/Sonarr API number type mismatch
- Add regression integration test for string-vs-number arrQueueId matching
- Bump version to 1.7.16, update CHANGELOG.md, openapi.yaml, and JSDoc examples
Resolves#48
- Created server/utils/logCapture.js to intercept and buffer server output, stripping ANSI escape codes.
- Created server/middleware/logStreamAuth.js enforcing subnet IP filtering (LOG_ALLOW_SUBNETS), Emby session cookie, Basic Auth fallback, and X-Webhook-Secret header bypass.
- Created server/routes/debug.js with SSE streams /api/debug/server-logs, /api/debug/client-logs and batched POST /api/debug/client-logs. Exposes public configuration status at /api/debug/status.
- Integrated log capture and mounted debug routes in server/app.js and server/index.js.
- Implemented client/src/utils/clientLogCapture.js in the frontend SPA to hook console log/warn/error and flush batched console events.
- Documented all endpoints in OpenAPI server/openapi.yaml, ARCHITECTURE.md, and README.md.
- Wrote route integration tests and frontend console capture tests, with full validation in swagger-coverage.
- Expose ARR ID fields (arrQueueId, arrType, arrInstanceUrl, arrContentId, arrContentType) to non-admins in DownloadMatcher.js for blocklist functionality
- Replace blanket admin check in dashboard.js with canBlocklist() validation and server-side API key lookup
- Update integration tests to reflect new permission model
- Non-admins can now blocklist downloads with import issues or stale low-availability torrents
- Deleted redundant unit test file tests/unit/dashboard.test.js
- Enabled skipped frontend DOM state and API tests in tests/frontend/state.test.js
- Fixed Supertest client socket abort exception in SSE stream integration tests using new graceful testClose parameter
- Consolidated duplicate helpers in server/routes/history.js and server/utils/arrRetrievers.js to unified services TagMatcher and DownloadAssembler
- Added comprehensive unit tests for loadSecrets.js, PollingSonarrRetriever.js, PollingRadarrRetriever.js, and ombiHelpers.js
- Achieved a 100% Vitest pass rate (834/834 tests) with robust code coverage
- Add requireAuth to GET /api/webhook/config to enforce authentication
- Add SOFARR_BASE_URL and SOFARR_WEBHOOK_SECRET validation to POST /api/ombi/webhook/enable and /test
- Return 400 with descriptive errors when webhook config is missing on Ombi routes
- Clean up test environment in webhook.test.js afterEach
- Add regression tests for all new validation logic
- Update CHANGELOG.md with security fixes
The Ombi API returns requestedUser as an OmbiUser object instead of a string.
Add extractRequestedUser helper to extract username from various fields
(alias, userAlias, userName, normalizedUserName) with fallback to legacy string format.
Update client and server routes to use the helper for consistent username extraction.
- Add Ombi requests tab UI with movie/TV request display
- Add showAll parameter support for Ombi requests (API and SSE)
- Add Ombi webhook panel with enable/test functionality
- Add Ombi webhook status endpoint with metrics
- Add Ombi webhook test endpoint
- Change GET /api/ombi/requests to use OmbiRetriever instead of cache
- Add Ombi webhook state and API functions to frontend
- Update SSE payload to include Ombi baseUrl and requests
- Replace Ombi API-based matching with simple TMDB ID link generation
- Movies link to {ombiBaseUrl}/details/movie/{tmdbId}
- TV shows link to {ombiBaseUrl}/details/tv/{tmdbId}
- Add ombiLink to all history items (Sonarr + Radarr) for all users
- Add ombiLink to torrent history matches that were previously missing it
- addOmbiMatching is now synchronous (no Ombi API calls)
Add arrType field to Sonarr and Radarr history items for admin users to enable proper icon display in the recently downloaded section. This mirrors the existing behavior in active downloads where arrType is set by DownloadMatcher.
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The buildUserDownloads function was calling async matcher functions
without awaiting them, causing Promise objects to be returned instead
of resolved arrays. This resulted in empty download lists and 17 failing
tests.
- Made buildUserDownloads async
- Added await to matchSabSlots, matchSabHistory, and matchTorrents calls
- Updated unit tests to await buildUserDownloads calls
All 759 tests now pass.
- Add OmbiRetriever extending ArrRetriever for PALDRA compliance
- Add OmbiClient for low-level Ombi API communication
- Add getOmbiInstances() to config.js following multi-instance pattern
- Register Ombi in PALDRA registry with Ombi-specific methods
- Add external ID matching (TMDB/TVDB/IMDB) to Ombi requests
- Update DownloadMatcher to be async and enrich downloads with Ombi links
- Add getOmbiLink/getOmbiSearchLink helpers to DownloadAssembler
- Implement new service icon layout (Ombi + Sonarr/Radarr icons)
- Add CSS styling for service icons
- Update dashboard routes to include Ombi configuration
- Extend OpenAPI with Ombi tag and NormalizedDownload properties
- Update documentation (README, ARCHITECTURE, SECURITY, CHANGELOG)
- Add Ombi configuration to .env.sample
- Change swaggerUi.setup to pass null and fetch spec from /api/swagger.json
- Update /api/swagger.json handler to dynamically set server URL based on request
- Remove dead client-side detection script (swagger-server-detection.js)
- Server-side detection respects TRUST_PROXY for reverse proxy scenarios
- req.protocol and req.get('host') automatically use X-Forwarded headers when configured
- Fixes issue where placeholder URL was never replaced due to window.ui being unavailable
- Update openapi.yaml to use single placeholder server URL
- Add swagger-server-detection.js to auto-detect current server URL from window.location
- Configure protocol, host, and port detection based on browser connection
- Fallback to placeholder URL if detection fails
- Include detection script in both app.js and index.js Swagger UI configurations
- /api/swagger.json endpoint returns static placeholder for external consumers
- Add GET /api/emby/users/:id endpoint to fetch individual user by ID
- Fix YAML semantic errors in dashboard.js and history.js by quoting parameter descriptions with colons
- Add x-integration-notes to /api/dashboard/stream endpoint description
- All 644 tests now passing
- GET /health: returns uptime, no auth/rate-limit
- GET /ready: checks EMBY_URL configuration, returns 503 if not ready
- Document Docker HEALTHCHECK usage
- GET /api/dashboard/user-downloads: deprecated, use SSE
- GET /api/dashboard/cover-art: image proxy for CSP compliance
- GET /api/dashboard/stream: SSE real-time updates, no CSRF needed
- POST /api/dashboard/blocklist-search: admin-only, removes + re-searches
- Document SSE event format and heartbeat
- Include admin-only constraints and error responses