From 355d08c91b82caee6f4c48ebd55b6a6367aec1a6 Mon Sep 17 00:00:00 2001
From: 0xsysr3ll <0xsysr3ll@pm.me>
Date: Mon, 18 Aug 2025 23:37:08 +0200
Subject: [PATCH 1/6] feat(settings): add 'Hide Requested Media' option to
settings
This PR introduces a new setting that allows users to hide media that has been requested but is not yet available from the "Discover" home page and related categories.
Signed-off-by: 0xsysr3ll <0xsysr3ll@pm.me>
---
docs/using-seerr/settings/general.md | 8 ++++++
seerr-api.yml | 3 +++
server/entity/Media.ts | 3 ++-
server/interfaces/api/settingsInterfaces.ts | 1 +
server/lib/settings/index.ts | 4 +++
src/components/MediaSlider/index.tsx | 8 ++++++
src/components/Search/index.tsx | 2 +-
.../Settings/SettingsMain/index.tsx | 25 +++++++++++++++++++
src/context/SettingsContext.tsx | 1 +
src/hooks/useDiscover.ts | 14 ++++++++++-
src/pages/_app.tsx | 1 +
11 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/docs/using-seerr/settings/general.md b/docs/using-seerr/settings/general.md
index 65b337495f..24bf19daa9 100644
--- a/docs/using-seerr/settings/general.md
+++ b/docs/using-seerr/settings/general.md
@@ -71,6 +71,14 @@ When enabled, media that has been blocklisted will not appear on the "Discover"
This setting is **disabled** by default.
+## Hide Requested Media
+
+When enabled, media that has been requested (but not yet available) will not appear on the "Discover" home page, or in the "Recommended" or "Similar" categories or other links on media detail pages.
+
+Requested media will still appear in search results, however, so it is possible to locate and view hidden items by searching for them by title.
+
+This setting is **disabled** by default.
+
## Allow Partial Series Requests
When enabled, users will be able to submit requests for specific seasons of TV series. If disabled, users will only be able to submit requests for all unavailable seasons.
diff --git a/seerr-api.yml b/seerr-api.yml
index cd0012b679..89539bf5fa 100644
--- a/seerr-api.yml
+++ b/seerr-api.yml
@@ -232,6 +232,9 @@ components:
hideAvailable:
type: boolean
example: false
+ hideRequested:
+ type: boolean
+ example: false
partialRequestsEnabled:
type: boolean
example: false
diff --git a/server/entity/Media.ts b/server/entity/Media.ts
index a63003df66..6b418de398 100644
--- a/server/entity/Media.ts
+++ b/server/entity/Media.ts
@@ -49,7 +49,8 @@ class Media {
'watchlist',
'media.id= watchlist.media and watchlist.requestedBy = :userId',
{ userId: user?.id }
- ) //,
+ )
+ .leftJoinAndSelect('media.requests', 'requests')
.where(' media.tmdbId in (:...finalIds)', { finalIds })
.getMany();
diff --git a/server/interfaces/api/settingsInterfaces.ts b/server/interfaces/api/settingsInterfaces.ts
index 3dfa619205..c044683b7f 100644
--- a/server/interfaces/api/settingsInterfaces.ts
+++ b/server/interfaces/api/settingsInterfaces.ts
@@ -31,6 +31,7 @@ export interface PublicSettingsResponse {
applicationUrl: string;
hideAvailable: boolean;
hideBlocklisted: boolean;
+ hideRequested: boolean;
localLogin: boolean;
mediaServerLogin: boolean;
movie4kEnabled: boolean;
diff --git a/server/lib/settings/index.ts b/server/lib/settings/index.ts
index 010c43d81d..b85571d651 100644
--- a/server/lib/settings/index.ts
+++ b/server/lib/settings/index.ts
@@ -141,6 +141,7 @@ export interface MainSettings {
};
hideAvailable: boolean;
hideBlocklisted: boolean;
+ hideRequested: boolean;
localLogin: boolean;
mediaServerLogin: boolean;
newPlexLogin: boolean;
@@ -193,6 +194,7 @@ interface FullPublicSettings extends PublicSettings {
applicationUrl: string;
hideAvailable: boolean;
hideBlocklisted: boolean;
+ hideRequested: boolean;
localLogin: boolean;
mediaServerLogin: boolean;
movie4kEnabled: boolean;
@@ -414,6 +416,7 @@ class Settings {
},
hideAvailable: false,
hideBlocklisted: false,
+ hideRequested: false,
localLogin: true,
mediaServerLogin: true,
newPlexLogin: true,
@@ -709,6 +712,7 @@ class Settings {
applicationUrl: this.data.main.applicationUrl,
hideAvailable: this.data.main.hideAvailable,
hideBlocklisted: this.data.main.hideBlocklisted,
+ hideRequested: this.data.main.hideRequested,
localLogin: this.data.main.localLogin,
mediaServerLogin: this.data.main.mediaServerLogin,
jellyfinExternalHost: this.data.jellyfin.externalHostname,
diff --git a/src/components/MediaSlider/index.tsx b/src/components/MediaSlider/index.tsx
index 4418c12314..53b75f3c11 100644
--- a/src/components/MediaSlider/index.tsx
+++ b/src/components/MediaSlider/index.tsx
@@ -82,6 +82,14 @@ const MediaSlider = ({
);
}
+ if (settings.currentSettings.hideRequested) {
+ titles = titles.filter(
+ (i) =>
+ (i.mediaType === 'movie' || i.mediaType === 'tv') &&
+ (!i.mediaInfo?.requests || i.mediaInfo.requests.length === 0)
+ );
+ }
+
useEffect(() => {
if (
titles.length < 24 &&
diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx
index e5a54180bb..bf0a83317d 100644
--- a/src/components/Search/index.tsx
+++ b/src/components/Search/index.tsx
@@ -34,7 +34,7 @@ const Search = () => {
{
query: router.query.query,
},
- { hideAvailable: false, hideBlocklisted: false }
+ { hideAvailable: false, hideBlocklisted: false, hideRequested: false }
);
if (error) {
diff --git a/src/components/Settings/SettingsMain/index.tsx b/src/components/Settings/SettingsMain/index.tsx
index 00703ddd37..2535433815 100644
--- a/src/components/Settings/SettingsMain/index.tsx
+++ b/src/components/Settings/SettingsMain/index.tsx
@@ -62,6 +62,9 @@ const messages = defineMessages('components.Settings.SettingsMain', {
hideAvailable: 'Hide Available Media',
hideAvailableTip:
'Hide available media from the discover pages but not search results',
+ hideRequested: 'Hide Requested Media',
+ hideRequestedTip:
+ 'Hide media that has been requested from the discover pages but not search results',
cacheImages: 'Enable Image Caching',
cacheImagesTip:
'Cache externally sourced images (requires a significant amount of disk space)',
@@ -171,6 +174,7 @@ const SettingsMain = () => {
applicationUrl: data?.applicationUrl,
hideAvailable: data?.hideAvailable,
hideBlocklisted: data?.hideBlocklisted,
+ hideRequested: data?.hideRequested,
locale: data?.locale ?? 'en',
discoverRegion: data?.discoverRegion,
originalLanguage: data?.originalLanguage,
@@ -193,6 +197,7 @@ const SettingsMain = () => {
applicationUrl: values.applicationUrl,
hideAvailable: values.hideAvailable,
hideBlocklisted: values.hideBlocklisted,
+ hideRequested: values.hideRequested,
locale: values.locale,
discoverRegion: values.discoverRegion,
streamingRegion: values.streamingRegion,
@@ -538,6 +543,26 @@ const SettingsMain = () => {
/>
+
+
+
+ {
+ setFieldValue('hideRequested', !values.hideRequested);
+ }}
+ />
+
+