diff --git a/server/subscriber/MediaRequestSubscriber.ts b/server/subscriber/MediaRequestSubscriber.ts index 22166da3..530b3a5a 100644 --- a/server/subscriber/MediaRequestSubscriber.ts +++ b/server/subscriber/MediaRequestSubscriber.ts @@ -33,21 +33,17 @@ import { EventSubscriber } from 'typeorm'; export class MediaRequestSubscriber implements EntitySubscriberInterface { - /** - * Get the latest media state using event manager or fallback to repository - */ - private async getLatestMediaState( + private async notifyAvailableMovie( entity: MediaRequest, event?: UpdateEvent - ): Promise { + ) { + // Get fresh media state using event manager let latestMedia: Media | null = null; - if (event?.manager) { latestMedia = await event.manager.findOne(Media, { where: { id: entity.media.id }, }); } - if (!latestMedia) { const mediaRepository = getRepository(Media); latestMedia = await mediaRepository.findOne({ @@ -55,93 +51,59 @@ export class MediaRequestSubscriber }); } - return latestMedia; - } - - /** - * Check if media is available for notification - */ - private isMediaAvailable(entity: MediaRequest, media: Media): boolean { - const mediaStatus = media[entity.is4k ? 'status4k' : 'status']; - return mediaStatus === MediaStatus.AVAILABLE; - } - - /** - * Send notification for available media - */ - private async sendAvailableNotification( - entity: MediaRequest, - media: Media, - notificationData: { - event: string; - subject: string; - message: string; - image: string; - extra?: { name: string; value: string }[]; + // Check availability using fresh media state + if ( + !latestMedia || + latestMedia[entity.is4k ? 'status4k' : 'status'] !== MediaStatus.AVAILABLE + ) { + return; } - ): Promise { + + const tmdb = new TheMovieDb(); + try { + const movie = await tmdb.getMovie({ + movieId: entity.media.tmdbId, + }); + notificationManager.sendNotification(Notification.MEDIA_AVAILABLE, { - ...notificationData, + event: `${entity.is4k ? '4K ' : ''}Movie Request Now Available`, notifyAdmin: false, notifySystem: true, notifyUser: entity.requestedBy, - media, + subject: `${movie.title}${ + movie.release_date ? ` (${movie.release_date.slice(0, 4)})` : '' + }`, + message: truncate(movie.overview, { + length: 500, + separator: /\s/, + omission: '…', + }), + media: latestMedia, + image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${movie.poster_path}`, request: entity, }); } catch (e) { logger.error('Something went wrong sending media notification(s)', { label: 'Notifications', errorMessage: e.message, - requestId: entity.id, - mediaId: entity.media.id, + mediaId: entity.id, }); } } - private async notifyAvailableMovie( + private async notifyAvailableSeries( entity: MediaRequest, event?: UpdateEvent ) { - const latestMedia = await this.getLatestMediaState(entity, event); - - if (!latestMedia || !this.isMediaAvailable(entity, latestMedia)) { - return; - } - - const tmdb = new TheMovieDb(); - const movie = await tmdb.getMovie({ movieId: entity.media.tmdbId }); - - await this.sendAvailableNotification(entity, latestMedia, { - event: `${entity.is4k ? '4K ' : ''}Movie Request Now Available`, - subject: `${movie.title}${ - movie.release_date ? ` (${movie.release_date.slice(0, 4)})` : '' - }`, - message: truncate(movie.overview, { - length: 500, - separator: /\s/, - omission: '…', - }), - image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${movie.poster_path}`, - }); - } - - /** - * Get the latest media state with seasons for series - */ - private async getLatestMediaStateWithSeasons( - entity: MediaRequest, - event?: UpdateEvent - ): Promise { + // Get fresh media state with seasons using event manager let latestMedia: Media | null = null; - if (event?.manager) { latestMedia = await event.manager.findOne(Media, { where: { id: entity.media.id }, relations: { seasons: true }, }); } - if (!latestMedia) { const mediaRepository = getRepository(Media); latestMedia = await mediaRepository.findOne({ @@ -150,78 +112,63 @@ export class MediaRequestSubscriber }); } - return latestMedia; - } - - /** - * Check if series is available for notification - */ - private isSeriesAvailable( - entity: MediaRequest, - media: Media - ): { - isAvailable: boolean; - requestedSeasons: number[]; - availableSeasons: number[]; - } { - const requestedSeasons = - entity.seasons?.map((entitySeason) => entitySeason.seasonNumber) ?? []; - const availableSeasons = media.seasons.filter( - (season) => - season[entity.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE && - requestedSeasons.includes(season.seasonNumber) - ); - const isAvailable = - availableSeasons.length > 0 && - availableSeasons.length === requestedSeasons.length; - - return { - isAvailable, - requestedSeasons, - availableSeasons: availableSeasons.map((s) => s.seasonNumber), - }; - } - - private async notifyAvailableSeries( - entity: MediaRequest, - event?: UpdateEvent - ) { - const latestMedia = await this.getLatestMediaStateWithSeasons( - entity, - event - ); - if (!latestMedia) { return; } - const { isAvailable } = this.isSeriesAvailable(entity, latestMedia); + // Check availability using fresh media state + const requestedSeasons = + entity.seasons?.map((entitySeason) => entitySeason.seasonNumber) ?? []; + const availableSeasons = latestMedia.seasons.filter( + (season) => + season[entity.is4k ? 'status4k' : 'status'] === MediaStatus.AVAILABLE && + requestedSeasons.includes(season.seasonNumber) + ); + const isMediaAvailable = + availableSeasons.length > 0 && + availableSeasons.length === requestedSeasons.length; - if (!isAvailable) { + if (!isMediaAvailable) { return; } const tmdb = new TheMovieDb(); - const tv = await tmdb.getTvShow({ tvId: entity.media.tmdbId }); - await this.sendAvailableNotification(entity, latestMedia, { - event: `${entity.is4k ? '4K ' : ''}Series Request Now Available`, - subject: `${tv.name}${ - tv.first_air_date ? ` (${tv.first_air_date.slice(0, 4)})` : '' - }`, - message: truncate(tv.overview, { - length: 500, - separator: /\s/, - omission: '…', - }), - image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tv.poster_path}`, - extra: [ - { - name: 'Requested Seasons', - value: entity.seasons.map((season) => season.seasonNumber).join(', '), - }, - ], - }); + try { + const tv = await tmdb.getTvShow({ tvId: entity.media.tmdbId }); + + notificationManager.sendNotification(Notification.MEDIA_AVAILABLE, { + event: `${entity.is4k ? '4K ' : ''}Series Request Now Available`, + subject: `${tv.name}${ + tv.first_air_date ? ` (${tv.first_air_date.slice(0, 4)})` : '' + }`, + message: truncate(tv.overview, { + length: 500, + separator: /\s/, + omission: '…', + }), + notifyAdmin: false, + notifySystem: true, + notifyUser: entity.requestedBy, + image: `https://image.tmdb.org/t/p/w600_and_h900_bestv2${tv.poster_path}`, + media: latestMedia, + extra: [ + { + name: 'Requested Seasons', + value: entity.seasons + .map((season) => season.seasonNumber) + .join(', '), + }, + ], + request: entity, + }); + } catch (e) { + logger.error('Something went wrong sending media notification(s)', { + label: 'Notifications', + errorMessage: e.message, + mediaId: entity.id, + }); + } } public async sendToRadarr(entity: MediaRequest): Promise {