1
+ import type { SonarrSeason } from '@server/api/servarr/sonarr' ;
1
2
import TheMovieDb from '@server/api/themoviedb' ;
2
3
import { MediaStatus , MediaType } from '@server/constants/media' ;
3
4
import { getRepository } from '@server/datasource' ;
4
5
import Media from '@server/entity/Media' ;
6
+ import { MediaRequest } from '@server/entity/MediaRequest' ;
5
7
import Season from '@server/entity/Season' ;
8
+ import SeasonRequest from '@server/entity/SeasonRequest' ;
6
9
import { getSettings } from '@server/lib/settings' ;
7
10
import logger from '@server/logger' ;
8
11
import AsyncLock from '@server/utils/asyncLock' ;
@@ -48,6 +51,7 @@ export interface ProcessableSeason {
48
51
episodes4k : number ;
49
52
is4kOverride ?: boolean ;
50
53
processing ?: boolean ;
54
+ monitored ?: boolean ;
51
55
}
52
56
53
57
class BaseScanner < T > {
@@ -211,7 +215,7 @@ class BaseScanner<T> {
211
215
212
216
/**
213
217
* processShow takes a TMDB ID and an array of ProcessableSeasons, which
214
- * should include the total episodes a sesaon has + the total available
218
+ * should include the total episodes a season has + the total available
215
219
* episodes that each season currently has. Unlike processMovie, this method
216
220
* does not take an `is4k` option. We handle both the 4k _and_ non 4k status
217
221
* in one method.
@@ -234,6 +238,7 @@ class BaseScanner<T> {
234
238
} : ProcessOptions = { }
235
239
) : Promise < void > {
236
240
const mediaRepository = getRepository ( Media ) ;
241
+ const settings = getSettings ( ) ;
237
242
238
243
await this . asyncLock . dispatch ( tmdbId , async ( ) => {
239
244
const media = await this . getExisting ( tmdbId , MediaType . TV ) ;
@@ -277,25 +282,35 @@ class BaseScanner<T> {
277
282
// force it to stay available (to avoid competing scanners)
278
283
existingSeason . status =
279
284
( season . totalEpisodes === season . episodes && season . episodes > 0 ) ||
280
- existingSeason . status === MediaStatus . AVAILABLE
285
+ ( existingSeason . status === MediaStatus . AVAILABLE &&
286
+ season . episodes > 0 )
281
287
? MediaStatus . AVAILABLE
282
288
: season . episodes > 0
283
289
? MediaStatus . PARTIALLY_AVAILABLE
284
290
: ! season . is4kOverride && season . processing
285
291
? MediaStatus . PROCESSING
292
+ : settings . main . removeUnmonitoredEnabled &&
293
+ ! season . monitored &&
294
+ season . episodes == 0
295
+ ? MediaStatus . UNKNOWN
286
296
: existingSeason . status ;
287
297
288
298
// Same thing here, except we only do updates if 4k is enabled
289
299
existingSeason . status4k =
290
300
( this . enable4kShow &&
291
301
season . episodes4k === season . totalEpisodes &&
292
302
season . episodes4k > 0 ) ||
293
- existingSeason . status4k === MediaStatus . AVAILABLE
303
+ ( existingSeason . status4k === MediaStatus . AVAILABLE &&
304
+ season . episodes > 0 )
294
305
? MediaStatus . AVAILABLE
295
306
: this . enable4kShow && season . episodes4k > 0
296
307
? MediaStatus . PARTIALLY_AVAILABLE
297
308
: season . is4kOverride && season . processing
298
309
? MediaStatus . PROCESSING
310
+ : settings . main . removeUnmonitoredEnabled &&
311
+ ! season . monitored &&
312
+ season . episodes4k == 0
313
+ ? MediaStatus . UNKNOWN
299
314
: existingSeason . status4k ;
300
315
} else {
301
316
newSeasons . push (
@@ -618,6 +633,56 @@ class BaseScanner<T> {
618
633
get protectedBundleSize ( ) : number {
619
634
return this . bundleSize ;
620
635
}
636
+
637
+ protected async processUnmonitoredMovie ( tmdbId : number ) : Promise < void > {
638
+ const mediaRepository = getRepository ( Media ) ;
639
+ await this . asyncLock . dispatch ( tmdbId , async ( ) => {
640
+ const existing = await this . getExisting ( tmdbId , MediaType . MOVIE ) ;
641
+ if ( existing && existing . status === MediaStatus . PROCESSING ) {
642
+ existing . status = MediaStatus . UNKNOWN ;
643
+ await mediaRepository . save ( existing ) ;
644
+ this . log (
645
+ `Movie TMDB ID ${ tmdbId } unmonitored from Radarr. Media status set to UNKNOWN.` ,
646
+ 'info'
647
+ ) ;
648
+ }
649
+ } ) ;
650
+ }
651
+
652
+ protected async processUnmonitoredSeason (
653
+ tmdbId : number ,
654
+ season : SonarrSeason
655
+ ) : Promise < void > {
656
+ // Remove unmonitored seasons from Requests
657
+ const requestRepository = getRepository ( MediaRequest ) ;
658
+ const seasonRequestRepository = getRepository ( SeasonRequest ) ;
659
+
660
+ const existingRequests = await requestRepository
661
+ . createQueryBuilder ( 'request' )
662
+ . innerJoinAndSelect ( 'request.media' , 'media' )
663
+ . innerJoinAndSelect ( 'request.seasons' , 'seasons' )
664
+ . where ( 'media.tmdbId = :tmdbId' , { tmdbId : tmdbId } )
665
+ . andWhere ( 'media.mediaType = :mediaType' , {
666
+ mediaType : MediaType . TV ,
667
+ } )
668
+ . andWhere ( 'seasons.seasonNumber = :seasonNumber' , {
669
+ seasonNumber : season . seasonNumber ,
670
+ } )
671
+ . getMany ( ) ;
672
+
673
+ if ( existingRequests && existingRequests . length > 0 ) {
674
+ for ( const existingRequest of existingRequests ) {
675
+ for ( const requestedSeason of existingRequest . seasons ) {
676
+ if ( requestedSeason . seasonNumber === season . seasonNumber ) {
677
+ this . log (
678
+ `Removing request for Season ${ season . seasonNumber } of tmdbId ${ tmdbId } as it is unmonitored`
679
+ ) ;
680
+ await seasonRequestRepository . remove ( requestedSeason ) ;
681
+ }
682
+ }
683
+ }
684
+ }
685
+ }
621
686
}
622
687
623
688
export default BaseScanner ;
0 commit comments