diff --git a/server/subscriber/MediaRequestSubscriber.ts b/server/subscriber/MediaRequestSubscriber.ts index f9bfeabe..f8fb799b 100644 --- a/server/subscriber/MediaRequestSubscriber.ts +++ b/server/subscriber/MediaRequestSubscriber.ts @@ -399,8 +399,10 @@ export class MediaRequestSubscriber implements EntitySubscriberInterface { const requestRepository = getRepository(MediaRequest); - entity.status = MediaRequestStatus.FAILED; - requestRepository.save(entity); + if (entity.status !== MediaRequestStatus.FAILED) { + entity.status = MediaRequestStatus.FAILED; + await requestRepository.save(entity); + } logger.warn( 'Something went wrong sending movie request to Radarr, marking status as FAILED', @@ -503,7 +505,6 @@ export class MediaRequestSubscriber implements EntitySubscriberInterface { const requestRepository = getRepository(MediaRequest); - entity.status = MediaRequestStatus.FAILED; - requestRepository.save(entity); + if (entity.status !== MediaRequestStatus.FAILED) { + entity.status = MediaRequestStatus.FAILED; + await requestRepository.save(entity); + } logger.warn( 'Something went wrong sending series request to Sonarr, marking status as FAILED', @@ -758,7 +760,6 @@ export class MediaRequestSubscriber implements EntitySubscriberInterface request.status === MediaRequestStatus.PENDING - ).length === 0 && - media[entity.is4k ? 'status4k' : 'status'] === MediaStatus.PENDING && - media[entity.is4k ? 'status4k' : 'status'] !== MediaStatus.DELETED + media[statusKey] === MediaStatus.PENDING ) { - media[entity.is4k ? 'status4k' : 'status'] = MediaStatus.UNKNOWN; - mediaRepository.save(media); + const requestRepository = getRepository(MediaRequest); + const pendingCount = await requestRepository.count({ + where: { media: { id: media.id }, status: MediaRequestStatus.PENDING }, + }); + + logger.debug('updateParentStatus: TV declined check', { + label: 'Media Request', + requestId: entity.id, + mediaId: media.id, + pendingCount, + }); + + if (pendingCount === 0) { + // Re-fetch media without requests to avoid cascade issues + const freshMedia = await mediaRepository.findOne({ + where: { id: media.id }, + }); + if (freshMedia) { + freshMedia[statusKey] = MediaStatus.UNKNOWN; + await mediaRepository.save(freshMedia); + } + } } // Approve child seasons if parent is approved @@ -815,6 +852,12 @@ export class MediaRequestSubscriber implements EntitySubscriberInterface { + logger.debug('updateParentStatus: approving season request', { + label: 'Media Request', + requestId: entity.id, + seasonRequestId: season.id, + seasonNumber: season.seasonNumber, + }); season.status = MediaRequestStatus.APPROVED; seasonRequestRepository.save(season); }); @@ -832,21 +875,39 @@ export class MediaRequestSubscriber implements EntitySubscriberInterface !request.is4k) && - fullMedia.status !== MediaStatus.AVAILABLE - ) { - fullMedia.status = MediaStatus.UNKNOWN; - } + fullMedia.status !== MediaStatus.AVAILABLE; - if ( + const needs4kStatusUpdate = !fullMedia.requests.some((request) => request.is4k) && - fullMedia.status4k !== MediaStatus.AVAILABLE - ) { - fullMedia.status4k = MediaStatus.UNKNOWN; - } + fullMedia.status4k !== MediaStatus.AVAILABLE; - await manager.save(fullMedia); + if (needsStatusUpdate || needs4kStatusUpdate) { + // Re-fetch WITHOUT requests to avoid cascade issues on save + const cleanMedia = await manager.findOneOrFail(Media, { + where: { id: entity.media.id }, + }); + + if (needsStatusUpdate) { + logger.debug('handleRemoveParentUpdate: setting status to UNKNOWN', { + label: 'Media Request', + requestId: entity.id, + mediaId: cleanMedia.id, + }); + cleanMedia.status = MediaStatus.UNKNOWN; + } + if (needs4kStatusUpdate) { + logger.debug('handleRemoveParentUpdate: setting status4k to UNKNOWN', { + label: 'Media Request', + requestId: entity.id, + mediaId: cleanMedia.id, + }); + cleanMedia.status4k = MediaStatus.UNKNOWN; + } + + await manager.save(cleanMedia); + } } public afterUpdate(event: UpdateEvent): void {