diff --git a/server/lib/availabilitySync.ts b/server/lib/availabilitySync.ts index 6e4a49e46..b6b343d32 100644 --- a/server/lib/availabilitySync.ts +++ b/server/lib/availabilitySync.ts @@ -355,6 +355,7 @@ class AvailabilitySync { ); } + media.lastSeasonChange = new Date(); await mediaRepository.save(media); logger.info( diff --git a/server/subscriber/MediaRequestSubscriber.ts b/server/subscriber/MediaRequestSubscriber.ts index 46c4ee9a7..6b4a7ae85 100644 --- a/server/subscriber/MediaRequestSubscriber.ts +++ b/server/subscriber/MediaRequestSubscriber.ts @@ -58,19 +58,16 @@ export class MediaRequestSubscriber // Find all seasons in the related media entity // and see if they are available, then we can check // if the request contains the same seasons + const requestedSeasons = + entity.seasons?.map((entitySeason) => entitySeason.seasonNumber) ?? []; const availableSeasons = entity.media.seasons.filter( (season) => - season[entity.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE + season[entity.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE && + requestedSeasons.includes(season.seasonNumber) ); - const isMediaAvailable = availableSeasons.length > 0 && - availableSeasons.every((availableSeason) => - entity.seasons?.some( - (entitySeason) => - entitySeason.seasonNumber === availableSeason.seasonNumber - ) - ); + availableSeasons.length === requestedSeasons.length; if ( entity.media[entity.is4k ? 'status4k' : 'status'] === diff --git a/server/subscriber/MediaSubscriber.ts b/server/subscriber/MediaSubscriber.ts index 9ec002fe2..93d7d3fea 100644 --- a/server/subscriber/MediaSubscriber.ts +++ b/server/subscriber/MediaSubscriber.ts @@ -31,7 +31,11 @@ export class MediaSubscriber implements EntitySubscriberInterface { } } - private async updateRelatedMediaRequest(event: Media, is4k: boolean) { + private async updateRelatedMediaRequest( + event: Media, + databaseEvent: Media, + is4k: boolean + ) { const requestRepository = getRepository(MediaRequest); const seasonRequestRepository = getRepository(SeasonRequest); @@ -67,17 +71,39 @@ export class MediaSubscriber implements EntitySubscriberInterface { (mediaSeason) => mediaSeason.seasonNumber === requestSeason.seasonNumber ); + const matchingOldSeason = databaseEvent.seasons.find( + (oldSeason) => + oldSeason.seasonNumber === requestSeason.seasonNumber + ); if (!matchingSeason) { return false; } - return ( - matchingSeason[request.is4k ? 'status4k' : 'status'] === - MediaStatus.AVAILABLE || - matchingSeason[request.is4k ? 'status4k' : 'status'] === - MediaStatus.DELETED - ); + const currentSeasonStatus = + matchingSeason[request.is4k ? 'status4k' : 'status']; + const previousSeasonStatus = + matchingOldSeason?.[request.is4k ? 'status4k' : 'status']; + + const hasStatusChanged = + currentSeasonStatus !== previousSeasonStatus; + + const shouldUpdate = + (hasStatusChanged || + requestSeason.status === MediaRequestStatus.COMPLETED) && + (currentSeasonStatus === MediaStatus.AVAILABLE || + currentSeasonStatus === MediaStatus.DELETED); + + if (shouldUpdate) { + // Handle season requests and mark them completed when + // that specific season becomes available + seasonRequestRepository.update(requestSeason.id, { + status: MediaRequestStatus.COMPLETED, + }); + return true; + } + + return false; }); shouldComplete = allSeasonsReady; @@ -90,38 +116,6 @@ export class MediaSubscriber implements EntitySubscriberInterface { }); await requestRepository.save(completedRequests); - - // Handle season requests and mark them completed when - // that specific season becomes available - if (event.mediaType === 'tv') { - const seasonsToUpdate = relatedRequests.flatMap((request) => { - return request.seasons.filter((requestSeason) => { - const matchingSeason = event.seasons.find( - (mediaSeason) => - mediaSeason.seasonNumber === requestSeason.seasonNumber - ); - - if (!matchingSeason) { - return false; - } - - return ( - matchingSeason[request.is4k ? 'status4k' : 'status'] === - MediaStatus.AVAILABLE || - matchingSeason[request.is4k ? 'status4k' : 'status'] === - MediaStatus.DELETED - ); - }); - }); - - await Promise.all( - seasonsToUpdate.map((season) => - seasonRequestRepository.update(season.id, { - status: MediaRequestStatus.COMPLETED, - }) - ) - ); - } } } @@ -173,7 +167,7 @@ export class MediaSubscriber implements EntitySubscriberInterface { return ( season[is4k ? 'status4k' : 'status'] !== - previousSeason[is4k ? 'status4k' : 'status'] + previousSeason?.[is4k ? 'status4k' : 'status'] ); }); }; @@ -184,7 +178,11 @@ export class MediaSubscriber implements EntitySubscriberInterface { seasonStatusCheck(false))) && validStatuses.includes(event.entity.status) ) { - this.updateRelatedMediaRequest(event.entity as Media, false); + this.updateRelatedMediaRequest( + event.entity as Media, + event.databaseEntity as Media, + false + ); } if ( @@ -192,7 +190,11 @@ export class MediaSubscriber implements EntitySubscriberInterface { (event.entity.mediaType === MediaType.TV && seasonStatusCheck(true))) && validStatuses.includes(event.entity.status4k) ) { - this.updateRelatedMediaRequest(event.entity as Media, true); + this.updateRelatedMediaRequest( + event.entity as Media, + event.databaseEntity as Media, + true + ); } }