Skip to content

Commit 4ec57ac

Browse files
committed
feat(tvrequestmodal,movierequestmodal): warning for no not yeat released
1 parent dbe1fca commit 4ec57ac

11 files changed

Lines changed: 124 additions & 0 deletions

File tree

cypress/config/settings.cypress.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"tv": {}
1414
},
1515
"hideAvailable": false,
16+
"warnNonReleased": false,
1617
"localLogin": true,
1718
"newPlexLogin": true,
1819
"discoverRegion": "",

docs/using-seerr/settings/general.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ Available media will still appear in search results, however, so it is possible
7878

7979
This setting is **disabled** by default.
8080

81+
## Warn about Non-released
82+
83+
When enabled, Movies or Series that don't have any release (still only in theatres, or not yet released) will show a warning : this prevents requests that can't yet be fulfilled
84+
85+
This setting is **disabled** by default.
86+
8187
## Hide Blocklisted Items
8288

8389
When enabled, media that has been blocklisted will not appear on the "Discover" home page, for all administrators. This can be useful to hide content that you don't want to see, such as content with specific tags or content that has been manually blocklisted when you have the "Manage Blocklist" permission.

seerr-api.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ components:
236236
hideAvailable:
237237
type: boolean
238238
example: false
239+
warnNonReleased:
240+
type: boolean
241+
example: false
239242
partialRequestsEnabled:
240243
type: boolean
241244
example: false

server/interfaces/api/settingsInterfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface PublicSettingsResponse {
3131
applicationUrl: string;
3232
hideAvailable: boolean;
3333
hideBlocklisted: boolean;
34+
warnNonReleased: boolean;
3435
localLogin: boolean;
3536
mediaServerLogin: boolean;
3637
movie4kEnabled: boolean;

server/lib/settings/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export interface MainSettings {
140140
};
141141
hideAvailable: boolean;
142142
hideBlocklisted: boolean;
143+
warnNonReleased: boolean;
143144
localLogin: boolean;
144145
mediaServerLogin: boolean;
145146
newPlexLogin: boolean;
@@ -190,6 +191,7 @@ interface FullPublicSettings extends PublicSettings {
190191
applicationUrl: string;
191192
hideAvailable: boolean;
192193
hideBlocklisted: boolean;
194+
warnNonReleased: boolean;
193195
localLogin: boolean;
194196
mediaServerLogin: boolean;
195197
movie4kEnabled: boolean;
@@ -401,6 +403,7 @@ class Settings {
401403
},
402404
hideAvailable: false,
403405
hideBlocklisted: false,
406+
warnNonReleased: false,
404407
localLogin: true,
405408
mediaServerLogin: true,
406409
newPlexLogin: true,
@@ -688,6 +691,7 @@ class Settings {
688691
applicationUrl: this.data.main.applicationUrl,
689692
hideAvailable: this.data.main.hideAvailable,
690693
hideBlocklisted: this.data.main.hideBlocklisted,
694+
warnNonReleased: this.data.main.warnNonReleased,
691695
localLogin: this.data.main.localLogin,
692696
mediaServerLogin: this.data.main.mediaServerLogin,
693697
jellyfinExternalHost: this.data.jellyfin.externalHostname,

src/components/RequestModal/MovieRequestModal.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import Modal from '@app/components/Common/Modal';
33
import type { RequestOverrides } from '@app/components/RequestModal/AdvancedRequester';
44
import AdvancedRequester from '@app/components/RequestModal/AdvancedRequester';
55
import QuotaDisplay from '@app/components/RequestModal/QuotaDisplay';
6+
import useSettings from '@app/hooks/useSettings';
67
import { useUser } from '@app/hooks/useUser';
78
import globalMessages from '@app/i18n/globalMessages';
89
import defineMessages from '@app/utils/defineMessages';
@@ -24,6 +25,7 @@ const messages = defineMessages('components.RequestModal', {
2425
requestCancel: 'Request for <strong>{title}</strong> canceled.',
2526
requestmovietitle: 'Request Movie',
2627
requestmovie4ktitle: 'Request Movie in 4K',
28+
requestmovieNotReleased: 'This movie release is in the future',
2729
edit: 'Edit Request',
2830
approve: 'Approve Request',
2931
cancel: 'Cancel Request',
@@ -61,8 +63,23 @@ const MovieRequestModal = ({
6163
const { data, error } = useSWR<MovieDetails>(`/api/v1/movie/${tmdbId}`, {
6264
revalidateOnMount: true,
6365
});
66+
6467
const intl = useIntl();
6568
const { user, hasPermission } = useUser();
69+
const settings = useSettings();
70+
71+
const discoverRegion = user?.settings?.discoverRegion
72+
? user.settings.discoverRegion
73+
: settings.currentSettings.discoverRegion
74+
? settings.currentSettings.discoverRegion
75+
: 'US';
76+
const nonTheatricalReleases = data?.releases.results
77+
.find((r) => r.iso_3166_1 === discoverRegion)
78+
?.release_dates?.filter((r) => r.type > 3 && r.type < 6);
79+
const nonTheatricalInTheFuture =
80+
(!nonTheatricalReleases || nonTheatricalReleases.length > 0) &&
81+
nonTheatricalReleases?.every((r) => new Date(r.release_date) > new Date());
82+
6683
const { data: quota } = useSWR<QuotaResponse>(
6784
user &&
6885
(!requestOverrides?.user?.id || hasPermission(Permission.MANAGE_USERS))
@@ -335,6 +352,15 @@ const MovieRequestModal = ({
335352
okButtonType={'primary'}
336353
backdrop={`https://image.tmdb.org/t/p/w1920_and_h800_multi_faces/${data?.backdropPath}`}
337354
>
355+
{settings.currentSettings.warnNonReleased &&
356+
(!nonTheatricalReleases?.length || nonTheatricalInTheFuture) && (
357+
<div className="mt-6">
358+
<Alert
359+
title={intl.formatMessage(messages.requestmovieNotReleased)}
360+
type="warning"
361+
/>
362+
</div>
363+
)}
338364
{hasAutoApprove && !quota?.movie.restricted && (
339365
<div className="mt-6">
340366
<Alert

src/components/RequestModal/TvRequestModal.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ const messages = defineMessages('components.RequestModal', {
3838
'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}',
3939
requestseasons4k:
4040
'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}} in 4K',
41+
requesttvNoAirDate: 'The Air Date is absent',
42+
requesttvNotReleased: 'The Air Date is in the future',
4143
alreadyrequested: 'Already Requested',
4244
selectseason: 'Select Season(s)',
4345
season: 'Season',
@@ -382,6 +384,20 @@ const TvRequestModal = ({
382384

383385
const isOwner = editRequest && editRequest.requestedBy.id === user?.id;
384386

387+
const dateNow = new Date();
388+
const selectedSeasonsAirDates = selectedSeasons.map(
389+
(season) => data?.seasons?.find((s) => s.seasonNumber === season)?.airDate
390+
);
391+
const selectedSeasonsPresentAirDates = selectedSeasonsAirDates
392+
.filter((i) => i !== undefined)
393+
.map((element) => new Date(Date.parse(element)));
394+
const selectedSeasonsAirDateInTheFuture =
395+
selectedSeasonsPresentAirDates.filter((element) => element > dateNow);
396+
397+
const selectedSeasonsAirDateNotPresent = selectedSeasonsAirDates.some(
398+
(element) => element === undefined
399+
);
400+
385401
return data && !error && !data.externalIds.tvdbId && searchModal.show ? (
386402
<SearchByNameModal
387403
tvdbId={tvdbId}
@@ -498,6 +514,37 @@ const TvRequestModal = ({
498514
/>
499515
</p>
500516
)}
517+
{settings.currentSettings.warnNonReleased &&
518+
selectedSeasonsAirDateInTheFuture.length > 0 && (
519+
<div className="mt-6">
520+
<Alert
521+
title={
522+
intl.formatMessage(messages.requesttvNotReleased) +
523+
` (
524+
${selectedSeasonsAirDateInTheFuture
525+
.map((element) =>
526+
intl.formatDate(element, {
527+
year: 'numeric',
528+
month: 'long',
529+
day: 'numeric',
530+
})
531+
)
532+
.join(', ')}
533+
)`
534+
}
535+
type="warning"
536+
/>
537+
</div>
538+
)}
539+
{settings.currentSettings.warnNonReleased &&
540+
selectedSeasonsAirDates.some((element) => element == undefined) && (
541+
<div className="mt-6">
542+
<Alert
543+
title={intl.formatMessage(messages.requesttvNoAirDate)}
544+
type="warning"
545+
/>
546+
</div>
547+
)}
501548
{(quota?.tv.limit ?? 0) > 0 && (
502549
<QuotaDisplay
503550
mediaType="tv"

src/components/Settings/SettingsMain/index.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ const messages = defineMessages('components.Settings.SettingsMain', {
5353
toastApiKeyFailure: 'Something went wrong while generating a new API key.',
5454
toastSettingsSuccess: 'Settings saved successfully!',
5555
toastSettingsFailure: 'Something went wrong while saving settings.',
56+
warnNonReleased: 'Warn if Non released',
57+
warnNonReleasedTip:
58+
"If still only in theatres, or not yet released, Seerr will show a warning to the would-be requester : This helps warn about requests that can't yet be fulfilled",
5659
hideAvailable: 'Hide Available Media',
5760
hideAvailableTip:
5861
'Hide available media from the discover pages but not search results',
@@ -165,6 +168,7 @@ const SettingsMain = () => {
165168
applicationUrl: data?.applicationUrl,
166169
hideAvailable: data?.hideAvailable,
167170
hideBlocklisted: data?.hideBlocklisted,
171+
warnNonReleased: data?.warnNonReleased,
168172
locale: data?.locale ?? 'en',
169173
discoverRegion: data?.discoverRegion,
170174
originalLanguage: data?.originalLanguage,
@@ -185,6 +189,7 @@ const SettingsMain = () => {
185189
applicationUrl: values.applicationUrl,
186190
hideAvailable: values.hideAvailable,
187191
hideBlocklisted: values.hideBlocklisted,
192+
warnNonReleased: values.warnNonReleased,
188193
locale: values.locale,
189194
discoverRegion: values.discoverRegion,
190195
streamingRegion: values.streamingRegion,
@@ -489,6 +494,30 @@ const SettingsMain = () => {
489494
/>
490495
</div>
491496
</div>
497+
<div className="form-row">
498+
<label htmlFor="warnNonReleased" className="checkbox-label">
499+
<span className="mr-2">
500+
{intl.formatMessage(messages.warnNonReleased)}
501+
</span>
502+
<SettingsBadge badgeType="experimental" />
503+
<span className="label-tip">
504+
{intl.formatMessage(messages.warnNonReleasedTip)}
505+
</span>
506+
</label>
507+
<div className="form-input-area">
508+
<Field
509+
type="checkbox"
510+
id="warnNonReleased"
511+
name="warnNonReleased"
512+
onChange={() => {
513+
setFieldValue(
514+
'warnNonReleased',
515+
!values.warnNonReleased
516+
);
517+
}}
518+
/>
519+
</div>
520+
</div>
492521
<div className="form-row">
493522
<label
494523
htmlFor="partialRequestsEnabled"

src/context/SettingsContext.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const defaultSettings = {
1414
applicationUrl: '',
1515
hideAvailable: false,
1616
hideBlocklisted: false,
17+
warnNonReleased: false,
1718
localLogin: true,
1819
mediaServerLogin: true,
1920
movie4kEnabled: false,

src/i18n/locale/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,13 +568,16 @@
568568
"components.RequestModal.requesterror": "Something went wrong while submitting the request.",
569569
"components.RequestModal.requestfrom": "{username}'s request is pending approval.",
570570
"components.RequestModal.requestmovie4ktitle": "Request Movie in 4K",
571+
"components.RequestModal.requestmovieNotReleased": "This movie release is in the future",
571572
"components.RequestModal.requestmovies": "Request {count} {count, plural, one {Movie} other {Movies}}",
572573
"components.RequestModal.requestmovies4k": "Request {count} {count, plural, one {Movie} other {Movies}} in 4K",
573574
"components.RequestModal.requestmovietitle": "Request Movie",
574575
"components.RequestModal.requestseasons": "Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}",
575576
"components.RequestModal.requestseasons4k": "Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}} in 4K",
576577
"components.RequestModal.requestseries4ktitle": "Request Series in 4K",
577578
"components.RequestModal.requestseriestitle": "Request Series",
579+
"components.RequestModal.requesttvNoAirDate": "The Air Date is absent",
580+
"components.RequestModal.requesttvNotReleased": "The Air Date is in the future",
578581
"components.RequestModal.season": "Season",
579582
"components.RequestModal.seasonnumber": "Season {number}",
580583
"components.RequestModal.selectmovies": "Select Movie(s)",
@@ -1008,6 +1011,8 @@
10081011
"components.Settings.SettingsMain.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash",
10091012
"components.Settings.SettingsMain.validationUrl": "You must provide a valid URL",
10101013
"components.Settings.SettingsMain.validationUrlTrailingSlash": "URL must not end in a trailing slash",
1014+
"components.Settings.SettingsMain.warnNonReleased": "Warn if Non released",
1015+
"components.Settings.SettingsMain.warnNonReleasedTip": "If still only in theatres, or not yet released, Seerr will show a warning to the would-be requester : This helps warn about requests that can't yet be fulfilled",
10111016
"components.Settings.SettingsMain.youtubeUrl": "YouTube URL",
10121017
"components.Settings.SettingsMain.youtubeUrlTip": "Base URL for YouTube videos if a self-hosted YouTube instance is used.",
10131018
"components.Settings.SettingsNetwork.apiRequestTimeout": "API Request Timeout",

0 commit comments

Comments
 (0)