diff --git a/cypress/config/settings.cypress.json b/cypress/config/settings.cypress.json index e49d8888b..f44d2dadf 100644 --- a/cypress/config/settings.cypress.json +++ b/cypress/config/settings.cypress.json @@ -25,6 +25,7 @@ "enableSpecialEpisodes": false, "forceIpv4First": false, "dnsServers": "", + "removeUnmonitoredEnabled": false, "locale": "en" }, "plex": { diff --git a/overseerr-api.yml b/overseerr-api.yml index f3be28ad2..560bcb5c8 100644 --- a/overseerr-api.yml +++ b/overseerr-api.yml @@ -176,6 +176,9 @@ components: partialRequestsEnabled: type: boolean example: false + removeUnmonitoredEnabled: + type: boolean + example: false localLogin: type: boolean example: true diff --git a/publish.sh b/publish.sh new file mode 100755 index 000000000..3d43c2a71 --- /dev/null +++ b/publish.sh @@ -0,0 +1,3 @@ +#/bin/sh +COMMIT_TAG=`git rev-parse HEAD` +docker build --build-arg COMMIT_TAG=${COMMIT_TAG} -t bonswouar/jellyseerr -f Dockerfile . && docker push bonswouar/jellyseerr diff --git a/server/interfaces/api/settingsInterfaces.ts b/server/interfaces/api/settingsInterfaces.ts index 017eef856..03f65843c 100644 --- a/server/interfaces/api/settingsInterfaces.ts +++ b/server/interfaces/api/settingsInterfaces.ts @@ -38,6 +38,7 @@ export interface PublicSettingsResponse { mediaServerType: number; partialRequestsEnabled: boolean; enableSpecialEpisodes: boolean; + removeUnmonitoredEnabled: boolean; cacheImages: boolean; vapidPublic: string; enablePushRegistration: boolean; diff --git a/server/lib/scanners/baseScanner.ts b/server/lib/scanners/baseScanner.ts index f0f3db7e6..03f426c5b 100644 --- a/server/lib/scanners/baseScanner.ts +++ b/server/lib/scanners/baseScanner.ts @@ -211,7 +211,7 @@ class BaseScanner { /** * processShow takes a TMDB ID and an array of ProcessableSeasons, which - * should include the total episodes a sesaon has + the total available + * should include the total episodes a season has + the total available * episodes that each season currently has. Unlike processMovie, this method * does not take an `is4k` option. We handle both the 4k _and_ non 4k status * in one method. @@ -618,6 +618,21 @@ class BaseScanner { get protectedBundleSize(): number { return this.bundleSize; } + + protected async processUnmonitoredMovie(tmdbId: number): Promise { + const mediaRepository = getRepository(Media); + await this.asyncLock.dispatch(tmdbId, async () => { + const existing = await this.getExisting(tmdbId, MediaType.MOVIE); + if (existing && existing.status === MediaStatus.PROCESSING) { + existing.status = MediaStatus.UNKNOWN; + await mediaRepository.save(existing); + this.log( + `Movie TMDB ID ${tmdbId} unmonitored from Radarr. Media status set to UNKNOWN.`, + 'info' + ); + } + }); + } } export default BaseScanner; diff --git a/server/lib/scanners/radarr/index.ts b/server/lib/scanners/radarr/index.ts index bc299d7b1..465204590 100644 --- a/server/lib/scanners/radarr/index.ts +++ b/server/lib/scanners/radarr/index.ts @@ -79,14 +79,13 @@ class RadarrScanner } private async processRadarrMovie(radarrMovie: RadarrMovie): Promise { - if (!radarrMovie.monitored && !radarrMovie.hasFile) { - this.log( - 'Title is unmonitored and has not been downloaded. Skipping item.', - 'debug', - { - title: radarrMovie.title, - } - ); + const settings = getSettings(); + if ( + settings.main.removeUnmonitoredEnabled && + !radarrMovie.monitored && + !radarrMovie.hasFile + ) { + this.processUnmonitoredMovie(radarrMovie.tmdbId); return; } diff --git a/server/lib/settings/index.ts b/server/lib/settings/index.ts index 343c01e2f..64b0c401d 100644 --- a/server/lib/settings/index.ts +++ b/server/lib/settings/index.ts @@ -134,6 +134,7 @@ export interface MainSettings { enableSpecialEpisodes: boolean; forceIpv4First: boolean; dnsServers: string; + removeUnmonitoredEnabled: boolean; locale: string; proxy: ProxySettings; } @@ -158,6 +159,7 @@ interface FullPublicSettings extends PublicSettings { jellyfinServerName?: string; partialRequestsEnabled: boolean; enableSpecialEpisodes: boolean; + removeUnmonitoredEnabled: boolean; cacheImages: boolean; vapidPublic: string; enablePushRegistration: boolean; @@ -350,6 +352,7 @@ class Settings { enableSpecialEpisodes: false, forceIpv4First: false, dnsServers: '', + removeUnmonitoredEnabled: false, locale: 'en', proxy: { enabled: false, @@ -595,6 +598,7 @@ class Settings { mediaServerType: this.main.mediaServerType, partialRequestsEnabled: this.data.main.partialRequestsEnabled, enableSpecialEpisodes: this.data.main.enableSpecialEpisodes, + removeUnmonitoredEnabled: this.data.main.removeUnmonitoredEnabled, cacheImages: this.data.main.cacheImages, vapidPublic: this.vapidPublic, enablePushRegistration: this.data.notifications.agents.webpush.enabled, diff --git a/src/components/Settings/SettingsMain/index.tsx b/src/components/Settings/SettingsMain/index.tsx index fb1df6b5e..29750d95d 100644 --- a/src/components/Settings/SettingsMain/index.tsx +++ b/src/components/Settings/SettingsMain/index.tsx @@ -63,6 +63,9 @@ const messages = defineMessages('components.Settings.SettingsMain', { dnsServers: 'Custom DNS Servers', dnsServersTip: 'Comma-separated list of custom DNS servers, e.g. "1.1.1.1,[2606:4700:4700::1111]"', + removeUnmonitoredEnabled: 'Remove Unmonitored Media', + removeUnmonitoredExplanation: + 'Remove Movies/Seasons from Jellyseerr that are not available and have been un-monitored since', locale: 'Display Language', proxyEnabled: 'HTTP(S) Proxy', proxyHostname: 'Proxy Hostname', @@ -171,6 +174,7 @@ const SettingsMain = () => { trustProxy: data?.trustProxy, cacheImages: data?.cacheImages, proxyEnabled: data?.proxy?.enabled, + removeUnmonitoredEnabled: data?.removeUnmonitoredEnabled, proxyHostname: data?.proxy?.hostname, proxyPort: data?.proxy?.port, proxySsl: data?.proxy?.useSsl, @@ -201,6 +205,7 @@ const SettingsMain = () => { enableSpecialEpisodes: values.enableSpecialEpisodes, forceIpv4First: values.forceIpv4First, dnsServers: values.dnsServers, + removeUnmonitoredEnabled: values.removeUnmonitoredEnabled, trustProxy: values.trustProxy, cacheImages: values.cacheImages, proxy: { @@ -556,6 +561,35 @@ const SettingsMain = () => { /> +
+ +
+ { + setFieldValue( + 'removeUnmonitoredEnabled', + !values.removeUnmonitoredEnabled + ); + }} + /> +
+