- Add request domain, repository, service, and reconcile task - Add Radarr/Sonarr fulfillment adapters and TMDB discovery - Expose user and admin request APIs with quota and approval rules - Add web UI for browsing, requesting, and admin queue management - Migration 139 introduces media_requests and related tables
11 KiB
Media Request System Spec
Goal
Build a Silo-native request system that lets authenticated users discover and search TMDB movies and series, request missing media, and have approved requests fulfilled through Radarr and Sonarr.
Silo owns request state, request limits, approval policy, visibility, and catalog availability detection. Radarr and Sonarr are external fulfillment adapters.
V1 Scope
- TMDB movie and series search.
- Direct TMDB-backed discovery sections for requestable media.
- One canonical request per media item.
- Radarr fulfillment for movies.
- Sonarr fulfillment for whole series.
- Manual approval and configurable auto approval.
- Global rolling request limits with per-user overrides.
- User-facing request status badges on search and discovery results.
- Admin queue for all requests.
- Background reconciliation with Radarr, Sonarr, and the Silo catalog.
Non-Goals For V1
- Season-specific or episode-specific requests.
- Multiple Radarr or Sonarr instance routing.
- User-selected quality tiers per request.
- Public/global request lists for non-admin users.
- Request comments or conversation threads.
- Client app updates outside the server web UI.
- Collection-backed request discovery.
Request Visibility
Requests are not treated as highly private, but Silo should avoid exposing a global request list to normal users.
- Non-admin users can list only their own submitted requests.
- Admin users can list all requests and see requester, profile, and audit details.
- Search and discovery results include lightweight request state for the item.
- Search and discovery results must not expose requester identity, notes, or user counts to non-admin users.
If an item has already been requested, other users cannot request it. The item should show the existing request status instead.
Example search/discovery item state:
{
"request": {
"status": "queued",
"requestable": false
}
}
Status Model
The primary request status tracks the normal fulfillment path:
pending: submitted and waiting for approval.approved: approved in Silo, but not yet handed to Radarr or Sonarr.queued: accepted by Radarr or Sonarr and waiting/searching.downloading: Radarr or Sonarr reports active download/import activity.completed: Silo catalog contains the requested media after a scan and provider-ID match.
Exceptional outcomes are separate from the main status ladder:
declinedcancelledfailed
V1 assumption: declined, cancelled, and failed requests no longer block a new request for the same item, but they still count against historical request limits.
Request Limits
Admins configure a global rolling quota:
enabledmax_requestswindow_days
Admins can define per-user override modes:
- inherit global
- custom
max_requestsandwindow_days - unlimited
- blocked from requesting
Quota rules:
- A new request counts when a request row is created.
- Every created request counts regardless of final status or outcome.
- Pending, approved, queued, downloading, completed, declined, cancelled, and failed requests all count during the rolling window.
- Duplicate attempts for an already-requested item do not count because no new request is created.
- Limits are enforced per Silo user account, not per household profile.
- The active profile is still recorded for audit and display.
Auto Approval
Auto approval supports a global default plus per-user override:
- inherit global
- always manual
- auto approve
- blocked
Auto approval only applies when:
- Requests are enabled.
- The user is within quota.
- The item is not already available in Silo.
- The item does not already have an active request.
- The relevant Radarr or Sonarr integration is configured.
Discovery
Request discovery is separate from Silo collections. It should call TMDB
directly and enrich the results with Silo availability and request state. It
must not create, sync, or depend on library_collections.
V1 discovery sections:
trending_movies:/trending/movie/weektrending_series:/trending/tv/weekpopular_movies:/movie/popularpopular_series:/tv/popularupcoming_movies:/movie/upcomingon_air_series:/tv/on_the_air
Discovery responses should include:
- media type
- TMDB ID
- title
- year or first air year
- overview
- poster/backdrop URLs or paths
- local availability
- lightweight request state
Example:
{
"media_type": "movie",
"tmdb_id": 550,
"title": "Fight Club",
"year": 1999,
"poster_path": "/pB8BM7pdSp6B6Ih7QZ4DrQ3PmJK.jpg",
"availability": "missing",
"request": {
"status": null,
"requestable": true
}
}
Discovery implementation notes:
- Add a dedicated request discovery service under the request system.
- It may extend or reuse the low-level TMDB HTTP client.
- It must not use collection templates, collection sync, or collection persistence.
- Cache raw TMDB section responses briefly, for example 15-60 minutes.
- Enrich request and availability state at request time so status remains current.
Search
Search should call TMDB directly for movie and TV results, then enrich each result with:
- local Silo availability
- existing request status
- requestability under current settings and quota
Search should not require the item to exist in the Silo catalog.
Fulfillment
Movies
- User selects a TMDB movie search/discovery result.
- Silo validates quota, availability, duplicate request state, and policy.
- Silo creates a request.
- If auto approved, or after manual admin approval, Silo looks up/adds the movie in Radarr.
- Silo stores the Radarr movie ID and moves the request to
queued. - Background reconciliation updates the request to
downloadingfrom Radarr activity/history. - Silo marks the request
completedonly after the Silo catalog sees the matching TMDB ID.
Series
- User selects a TMDB TV search/discovery result.
- Silo resolves the TVDB ID needed by Sonarr.
- Silo validates quota, availability, duplicate request state, and policy.
- Silo creates a request.
- If auto approved, or after manual admin approval, Silo adds the whole series in Sonarr using the default add behavior.
- Silo stores the Sonarr series ID and moves the request to
queued. - Background reconciliation updates the request to
downloadingfrom Sonarr activity/history. - Silo marks the request
completedonly after the Silo catalog sees the matching TMDB or TVDB ID.
Radarr Integration
The Radarr adapter should use Radarr v3 API endpoints:
GET /api/v3/system/statusfor connection checks.GET /api/v3/rootfolderfor root folder choices.GET /api/v3/qualityprofilefor quality profiles.GET /api/v3/tagfor tag choices.GET /api/v3/movie?tmdbId={id}to detect existing Radarr items.GET /api/v3/movie/lookup/tmdb?tmdbId={id}to hydrate add payloads.POST /api/v3/movieto add approved movies.
Configured movie options:
- root folder
- quality profile
- tags
- minimum availability
- search on add
Sonarr Integration
The Sonarr adapter should use Sonarr v3 API endpoints:
GET /api/v3/system/statusfor connection checks.GET /api/v3/rootfolderfor root folder choices.GET /api/v3/qualityprofilefor quality profiles.GET /api/v3/tagfor tag choices.GET /api/v3/series?tvdbId={id}to detect existing Sonarr items.GET /api/v3/series/lookup?term={term}to hydrate add payloads.POST /api/v3/seriesto add approved series.
Configured series options:
- root folder
- quality profile
- tags
- series type
- season folder
- search for missing episodes on add
API Surface
Profile-scoped routes:
GET /api/v1/requests/search?q=&media_type=movie|seriesGET /api/v1/requests/discoverGET /api/v1/requests/discover/{section}?page=1POST /api/v1/requestsGET /api/v1/requests/mineGET /api/v1/requests/{id}
Admin routes:
GET /api/v1/admin/requestsPOST /api/v1/admin/requests/{id}/approvePOST /api/v1/admin/requests/{id}/declinePOST /api/v1/admin/requests/{id}/retryGET /api/v1/admin/request-settingsPUT /api/v1/admin/request-settingsGET /api/v1/admin/request-users/{user_id}/limitPUT /api/v1/admin/request-users/{user_id}/limitGET /api/v1/admin/request-integrationsPUT /api/v1/admin/request-integrations
Data Model
media_requests
Canonical media request records.
Suggested fields:
idmedia_typeprovidertmdb_idtvdb_idimdb_idtitleyearposter_pathoverviewstatusoutcomerequested_by_user_idrequested_by_profile_idintegration_kindexternal_idexternal_statuslast_errorcreated_atupdated_atapproved_atcompleted_at
Add a uniqueness constraint for active requests by (media_type, provider, tmdb_id). Declined, cancelled, failed, and completed requests should not block
a future request.
media_request_events
Audit trail for request lifecycle changes.
Suggested fields:
idrequest_idevent_typeactor_user_idactor_profile_idmessagemetadatacreated_at
request_user_limits
Per-user quota and approval overrides.
Suggested fields:
user_idlimit_modemax_requestswindow_daysapproval_modeupdated_at
request_settings
Global request settings.
Suggested fields:
requests_enabledglobal_max_requestsglobal_window_daysglobal_auto_approval_enabledupdated_at
request_integrations
Radarr and Sonarr configuration. API keys should use the existing sensitive
settings pattern rather than being returned from API responses. The expected
sensitive setting references are requests.radarr.api_key and
requests.sonarr.api_key.
Suggested fields:
kindenabledbase_urlapi_key_refroot_folderquality_profile_idtagsoptionslast_check_atlast_check_statuslast_check_errorupdated_at
UI Requirements
User UI:
- Request discovery page with TMDB sections.
- Search page or search mode that includes TMDB results.
- Clear badges for available, requested, and requestable states.
- Own requests page.
- Request button disabled when unavailable due to existing request, local availability, quota, or disabled system settings.
Admin UI:
- Request queue with filters by status and outcome.
- Approve, decline, and retry actions.
- Request settings page.
- Radarr and Sonarr configuration with connection checks.
- Per-user limit and approval override controls.
Acceptance Criteria
- A user can discover trending/popular/upcoming TMDB movies and series without touching Silo collections.
- A user can search TMDB and request a missing movie or whole series.
- Search and discovery items show whether they are available, already requested, or requestable.
- A user cannot request an item that already has an active request.
- Request limits count every created request within the rolling window, regardless of final status.
- Admins can configure global limits and per-user overrides.
- Admins can configure Radarr and Sonarr, approve/decline/retry requests, and see request audit history.
- Auto-approved requests are submitted to Radarr/Sonarr without admin action.
- Requests progress through
pending,approved,queued,downloading, andcompleted. completedmeans Silo has scanned and matched the media in its catalog, not merely that Radarr or Sonarr reports completion.