Skip to content
This repository was archived by the owner on Feb 15, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cypress/config/settings.cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"originalLanguage": "",
"trustProxy": false,
"partialRequestsEnabled": true,
"hideSpecials": false,
"locale": "en"
},
"plex": {
Expand Down
3 changes: 3 additions & 0 deletions overseerr-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ components:
partialRequestsEnabled:
type: boolean
example: false
hideSpecials:
type: boolean
example: false
localLogin:
type: boolean
example: true
Expand Down
1 change: 1 addition & 0 deletions server/interfaces/api/settingsInterfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface PublicSettingsResponse {
originalLanguage: string;
partialRequestsEnabled: boolean;
cacheImages: boolean;
hideSpecials: boolean;
vapidPublic: string;
enablePushRegistration: boolean;
locale: string;
Expand Down
4 changes: 4 additions & 0 deletions server/lib/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export interface MainSettings {
trustProxy: boolean;
partialRequestsEnabled: boolean;
locale: string;
hideSpecials: boolean;
}

interface PublicSettings {
Expand All @@ -126,6 +127,7 @@ interface FullPublicSettings extends PublicSettings {
locale: string;
emailEnabled: boolean;
newPlexLogin: boolean;
hideSpecials: boolean;
}

export interface NotificationAgentConfig {
Expand Down Expand Up @@ -301,6 +303,7 @@ class Settings {
trustProxy: false,
partialRequestsEnabled: true,
locale: 'en',
hideSpecials: false,
},
plex: {
name: '',
Expand Down Expand Up @@ -507,6 +510,7 @@ class Settings {
originalLanguage: this.data.main.originalLanguage,
partialRequestsEnabled: this.data.main.partialRequestsEnabled,
cacheImages: this.data.main.cacheImages,
hideSpecials: this.data.main.hideSpecials,
vapidPublic: this.vapidPublic,
enablePushRegistration: this.data.notifications.agents.webpush.enabled,
locale: this.data.main.locale,
Expand Down
4 changes: 3 additions & 1 deletion src/components/ManageSlideOver/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ const ManageSlideOver = ({
await axios.post(`/api/v1/media/${data.mediaInfo?.id}/available`, {
is4k,
...(mediaType === 'tv' && {
seasons: data.seasons.filter((season) => season.seasonNumber !== 0),
seasons: data.seasons.filter((season) =>
settings.currentSettings.hideSpecials ? season.seasonNumber !== 0 : true
),
Comment thread
ryansonshine marked this conversation as resolved.
}),
});
revalidate();
Expand Down
18 changes: 11 additions & 7 deletions src/components/RequestModal/TvRequestModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ const TvRequestModal = ({
? selectedSeasons
: getAllSeasons().filter(
(season) =>
!getAllRequestedSeasons().includes(season) && season !== 0
!getAllRequestedSeasons().includes(season) && (!settings.currentSettings.hideSpecials || season !== 0)
),
...overrideParams,
});
Expand Down Expand Up @@ -235,7 +235,7 @@ const TvRequestModal = ({

const getAllSeasons = (): number[] => {
return (data?.seasons ?? [])
.filter((season) => season.episodeCount !== 0)
.filter((season) => season.episodeCount !== 0 && (!settings.currentSettings.hideSpecials || season.seasonNumber !== 0))
.map((season) => season.seasonNumber);
};

Expand Down Expand Up @@ -568,11 +568,15 @@ const TvRequestModal = ({
</thead>
<tbody className="divide-y divide-gray-700">
{data?.seasons
.filter((season) =>
!settings.currentSettings.partialRequestsEnabled
? season.episodeCount !== 0 && season.seasonNumber !== 0
: season.episodeCount !== 0
)
.filter((season) => {
if (settings.currentSettings.hideSpecials && season.seasonNumber === 0) {
return false;
}
if (!settings.currentSettings.partialRequestsEnabled) {
return season.episodeCount !== 0 && season.seasonNumber !== 0;
}
return season.episodeCount !== 0;
})
.map((season) => {
const seasonRequest = getSeasonRequest(
season.seasonNumber
Expand Down
29 changes: 29 additions & 0 deletions src/components/Settings/SettingsMain/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ const messages = defineMessages({
validationApplicationUrl: 'You must provide a valid URL',
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
partialRequestsEnabled: 'Allow Partial Series Requests',
hideSpecials: 'Hide Specials Season',
hideSpecialsTip: 'Hide specials season and prevent requesting specials',
locale: 'Display Language',
});

Expand Down Expand Up @@ -132,6 +134,7 @@ const SettingsMain = () => {
region: data?.region,
originalLanguage: data?.originalLanguage,
partialRequestsEnabled: data?.partialRequestsEnabled,
hideSpecials: data?.hideSpecials,
trustProxy: data?.trustProxy,
cacheImages: data?.cacheImages,
}}
Expand All @@ -148,6 +151,7 @@ const SettingsMain = () => {
region: values.region,
originalLanguage: values.originalLanguage,
partialRequestsEnabled: values.partialRequestsEnabled,
hideSpecials: values.hideSpecials,
trustProxy: values.trustProxy,
cacheImages: values.cacheImages,
});
Expand Down Expand Up @@ -401,6 +405,31 @@ const SettingsMain = () => {
onChange={() => {
setFieldValue('hideAvailable', !values.hideAvailable);
}}
/> </div>
</div>
<div className="form-row">
<label
htmlFor="hideSpecials"
className="checkbox-label"
>
<span className="mr-2">
{intl.formatMessage(messages.hideSpecials)}
</span>
<span className="label-tip">
{intl.formatMessage(messages.hideSpecialsTip)}
</span>
</label>
<div className="form-input-area">
<Field
type="checkbox"
id="hideSpecials"
name="hideSpecials"
onChange={() => {
setFieldValue(
'hideSpecials',
!values.hideSpecials
);
}}
/>
</div>
</div>
Expand Down
21 changes: 9 additions & 12 deletions src/components/TvDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ const TvDetails = ({ tv }: TvDetailsProps) => {

// Does NOT include "Specials"
const seasonCount = data.seasons.filter(
(season) => season.seasonNumber !== 0 && season.episodeCount !== 0
(season) => (settings.currentSettings.hideSpecials ? season.seasonNumber !== 0 : true) && season.episodeCount !== 0
Comment thread
ryansonshine marked this conversation as resolved.
).length;

if (seasonCount) {
Expand Down Expand Up @@ -259,17 +259,13 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
return [...requestedSeasons, ...availableSeasons];
};

const showHasSpecials = data.seasons.some(
(season) => season.seasonNumber === 0
);

const isComplete =
(showHasSpecials ? seasonCount + 1 : seasonCount) <=
getAllRequestedSeasons(false).length;

const is4kComplete =
(showHasSpecials ? seasonCount + 1 : seasonCount) <=
getAllRequestedSeasons(true).length;
// Calculate total seasons to consider for completion status
const totalSeasons = settings.currentSettings.hideSpecials
? seasonCount
: (data.seasons.some(s => s.seasonNumber === 0) ? seasonCount + 1 : seasonCount);
Comment thread
ryansonshine marked this conversation as resolved.

const isComplete = totalSeasons <= getAllRequestedSeasons(false).length;
const is4kComplete = totalSeasons <= getAllRequestedSeasons(true).length;

const streamingProviders =
data?.watchProviders?.find((provider) => provider.iso_3166_1 === region)
Expand Down Expand Up @@ -530,6 +526,7 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
<h2 className="py-4">{intl.formatMessage(messages.seasonstitle)}</h2>
<div className="flex w-full flex-col space-y-2">
{data.seasons
.filter((season) => !settings.currentSettings.hideSpecials || season.seasonNumber !== 0)
.slice()
.reverse()
.map((season) => {
Expand Down
1 change: 1 addition & 0 deletions src/context/SettingsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const defaultSettings = {
locale: 'en',
emailEnabled: false,
newPlexLogin: true,
hideSpecials: false,
};

export const SettingsContext = React.createContext<SettingsContextProps>({
Expand Down
2 changes: 2 additions & 0 deletions src/i18n/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,8 @@
"components.Settings.SettingsMain.generalsettings": "General Settings",
"components.Settings.SettingsMain.generalsettingsDescription": "Configure global and default settings for Overseerr.",
"components.Settings.SettingsMain.hideAvailable": "Hide Available Media",
"components.Settings.SettingsMain.hideSpecials": "Hide Specials Season",
"components.Settings.SettingsMain.hideSpecialsTip": "Hide specials season and prevent requesting specials",
"components.Settings.SettingsMain.locale": "Display Language",
"components.Settings.SettingsMain.originallanguage": "Discover Language",
"components.Settings.SettingsMain.originallanguageTip": "Filter content by original language",
Expand Down
1 change: 1 addition & 0 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ CoreApp.getInitialProps = async (initialProps) => {
locale: 'en',
emailEnabled: false,
newPlexLogin: true,
hideSpecials: false,
};

if (ctx.res) {
Expand Down