Exemple #1
0
        private async Task GetEpisodes(PlexServers settings, Directory section)
        {
            var currentPosition = 0;
            var resultCount     = settings.EpisodeBatchSize == 0 ? 150 : settings.EpisodeBatchSize;
            var currentEpisodes = _repo.GetAllEpisodes();
            var episodes        = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition, resultCount);

            _log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Total Epsiodes found for {episodes.MediaContainer.librarySectionTitle} = {episodes.MediaContainer.totalSize}");

            // Delete all the episodes because we cannot uniquly match an episode to series every time,
            // see comment below.

            // 12.03.2017 - I think we should be able to match them now
            //await _repo.ExecuteSql("DELETE FROM PlexEpisode");

            await ProcessEpsiodes(episodes?.MediaContainer?.Metadata ?? new Metadata[] { }, currentEpisodes);

            currentPosition += resultCount;

            while (currentPosition < episodes.MediaContainer.totalSize)
            {
                var ep = await _api.GetAllEpisodes(settings.PlexAuthToken, settings.FullUri, section.key, currentPosition,
                                                   resultCount);

                await ProcessEpsiodes(ep?.MediaContainer?.Metadata ?? new Metadata[] { }, currentEpisodes);

                _log.LogInformation(LoggingEvents.PlexEpisodeCacher, $"Processed {resultCount} more episodes. Total Remaining {episodes.MediaContainer.totalSize - currentPosition}");
                currentPosition += resultCount;
            }

            // we have now finished.
            _log.LogInformation(LoggingEvents.PlexEpisodeCacher, "We have finished caching the episodes.");
            await _repo.SaveChangesAsync();
        }
Exemple #2
0
        public async Task Start(NewsletterSettings settings, bool test)
        {
            if (!settings.Enabled)
            {
                return;
            }
            var template = await _templateRepo.GetTemplate(NotificationAgent.Email, NotificationType.Newsletter);

            if (!template.Enabled)
            {
                return;
            }

            var emailSettings = await _emailSettings.GetSettingsAsync();

            if (!ValidateConfiguration(emailSettings))
            {
                return;
            }

            var customization = await _customizationSettings.GetSettingsAsync();

            // Get the Content
            var plexContent = _plex.GetAll().Include(x => x.Episodes).AsNoTracking();
            var embyContent = _emby.GetAll().Include(x => x.Episodes).AsNoTracking();

            var addedLog              = _recentlyAddedLog.GetAll();
            var addedPlexMovieLogIds  = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).Select(x => x.ContentId);
            var addedEmbyMoviesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent).Select(x => x.ContentId);

            var addedPlexEpisodesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode).Select(x => x.ContentId);
            var addedEmbyEpisodesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode).Select(x => x.ContentId);

            // Filter out the ones that we haven't sent yet
            var plexContentMoviesToSend = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && !addedPlexMovieLogIds.Contains(x.Id));
            var embyContentMoviesToSend = embyContent.Where(x => x.Type == EmbyMediaType.Movie && !addedEmbyMoviesLogIds.Contains(x.Id));

            var plexEpisodesToSend = _plex.GetAllEpisodes().Include(x => x.Series).Where(x => !addedPlexEpisodesLogIds.Contains(x.Id)).AsNoTracking();
            var embyEpisodesToSend = _emby.GetAllEpisodes().Include(x => x.Series).Where(x => !addedEmbyEpisodesLogIds.Contains(x.Id)).AsNoTracking();

            var body = string.Empty;

            if (test)
            {
                var plexm = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie).OrderByDescending(x => x.AddedAt).Take(10);
                var embym = embyContent.Where(x => x.Type == EmbyMediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10);
                var plext = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10);
                var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10);
                body = await BuildHtml(plexm, embym, plext, embyt);
            }
            else
            {
                body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend);

                if (body.IsNullOrEmpty())
                {
                    return;
                }
            }

            if (!test)
            {
                // Get the users to send it to
                var users = await _userManager.GetUsersInRoleAsync(OmbiRoles.RecievesNewsletter);

                if (!users.Any())
                {
                    return;
                }
                var emailTasks = new List <Task>();
                foreach (var user in users)
                {
                    if (user.Email.IsNullOrEmpty())
                    {
                        continue;
                    }

                    var messageContent = ParseTemplate(template, customization, user);
                    var email          = new NewsletterTemplate();

                    var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);

                    emailTasks.Add(_email.Send(
                                       new NotificationMessage {
                        Message = html, Subject = messageContent.Subject, To = user.Email
                    },
                                       emailSettings));
                }

                // Now add all of this to the Recently Added log
                var recentlyAddedLog = new HashSet <RecentlyAddedLog>();
                foreach (var p in plexContentMoviesToSend)
                {
                    recentlyAddedLog.Add(new RecentlyAddedLog
                    {
                        AddedAt     = DateTime.Now,
                        Type        = RecentlyAddedType.Plex,
                        ContentType = ContentType.Parent,
                        ContentId   = p.Id
                    });
                }

                foreach (var p in plexEpisodesToSend)
                {
                    recentlyAddedLog.Add(new RecentlyAddedLog
                    {
                        AddedAt     = DateTime.Now,
                        Type        = RecentlyAddedType.Plex,
                        ContentType = ContentType.Episode,
                        ContentId   = p.Id
                    });
                }

                foreach (var e in embyContentMoviesToSend)
                {
                    if (e.Type == EmbyMediaType.Movie)
                    {
                        recentlyAddedLog.Add(new RecentlyAddedLog
                        {
                            AddedAt     = DateTime.Now,
                            Type        = RecentlyAddedType.Emby,
                            ContentType = ContentType.Parent,
                            ContentId   = e.Id
                        });
                    }
                }

                foreach (var p in embyEpisodesToSend)
                {
                    recentlyAddedLog.Add(new RecentlyAddedLog
                    {
                        AddedAt     = DateTime.Now,
                        Type        = RecentlyAddedType.Emby,
                        ContentType = ContentType.Episode,
                        ContentId   = p.Id
                    });
                }
                await _recentlyAddedLog.AddRange(recentlyAddedLog);

                await Task.WhenAll(emailTasks.ToArray());
            }
            else
            {
                var admins = await _userManager.GetUsersInRoleAsync(OmbiRoles.Admin);

                foreach (var a in admins)
                {
                    if (a.Email.IsNullOrEmpty())
                    {
                        continue;
                    }
                    var messageContent = ParseTemplate(template, customization, a);

                    var email = new NewsletterTemplate();

                    var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);

                    await _email.Send(
                        new NotificationMessage { Message = html, Subject = messageContent.Subject, To = a.Email },
                        emailSettings);
                }
            }
        }
Exemple #3
0
        private async Task ProcessTv(IQueryable <ChildRequests> tv)
        {
            var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series);

            foreach (var child in tv)
            {
                var useImdb = false;
                var useTvDb = false;
                if (child.ParentRequest.ImdbId.HasValue())
                {
                    useImdb = true;
                }

                if (child.ParentRequest.TvDbId.ToString().HasValue())
                {
                    useTvDb = true;
                }

                var tvDbId = child.ParentRequest.TvDbId;
                var imdbId = child.ParentRequest.ImdbId;
                IQueryable <PlexEpisode> seriesEpisodes = null;
                if (useImdb)
                {
                    seriesEpisodes = plexEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString());
                }
                if (useTvDb && (seriesEpisodes == null || !seriesEpisodes.Any()))
                {
                    seriesEpisodes = plexEpisodes.Where(x => x.Series.TvDbId == tvDbId.ToString());
                }

                if (seriesEpisodes == null)
                {
                    continue;
                }

                if (!seriesEpisodes.Any())
                {
                    // Let's try and match the series by name
                    seriesEpisodes = plexEpisodes.Where(x =>
                                                        x.Series.Title.Equals(child.Title, StringComparison.CurrentCultureIgnoreCase) &&
                                                        x.Series.ReleaseYear == child.ParentRequest.ReleaseDate.Year.ToString());
                }

                foreach (var season in child.SeasonRequests)
                {
                    foreach (var episode in season.Episodes)
                    {
                        if (episode.Available)
                        {
                            continue;
                        }
                        var foundEp = await seriesEpisodes.FirstOrDefaultAsync(
                            x => x.EpisodeNumber == episode.EpisodeNumber &&
                            x.SeasonNumber == episode.Season.SeasonNumber);

                        if (foundEp != null)
                        {
                            episode.Available = true;
                        }
                    }
                }

                // Check to see if all of the episodes in all seasons are available for this request
                var allAvailable = child.SeasonRequests.All(x => x.Episodes.All(c => c.Available));
                if (allAvailable)
                {
                    // We have fulfulled this request!
                    child.Available = true;
                    _backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions
                    {
                        DateTime         = DateTime.Now,
                        NotificationType = NotificationType.RequestAvailable,
                        RequestId        = child.Id,
                        RequestType      = RequestType.TvShow,
                        Recipient        = child.RequestedUser.Email
                    }));
                }
            }

            await _tvRepo.Save();
        }
Exemple #4
0
        public async Task Start(NewsletterSettings settings, bool test)
        {
            if (!settings.Enabled)
            {
                return;
            }
            var template = await _templateRepo.GetTemplate(NotificationAgent.Email, NotificationType.Newsletter);

            if (!template.Enabled)
            {
                return;
            }

            var emailSettings = await _emailSettings.GetSettingsAsync();

            if (!ValidateConfiguration(emailSettings))
            {
                return;
            }

            try
            {
                var customization = await _customizationSettings.GetSettingsAsync();

                // Get the Content
                var plexContent   = _plex.GetAll().Include(x => x.Episodes).AsNoTracking();
                var embyContent   = _emby.GetAll().Include(x => x.Episodes).AsNoTracking();
                var lidarrContent = _lidarrAlbumRepository.GetAll().Where(x => x.FullyAvailable).AsNoTracking();

                var addedLog              = _recentlyAddedLog.GetAll();
                var addedPlexMovieLogIds  = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).Select(x => x.ContentId).ToHashSet();
                var addedEmbyMoviesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent).Select(x => x.ContentId).ToHashSet();
                var addedAlbumLogIds      = addedLog.Where(x => x.Type == RecentlyAddedType.Lidarr && x.ContentType == ContentType.Album).Select(x => x.AlbumId).ToHashSet();

                var addedPlexEpisodesLogIds =
                    addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode);
                var addedEmbyEpisodesLogIds =
                    addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Episode);


                // Filter out the ones that we haven't sent yet
                var plexContentMoviesToSend   = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && x.HasTheMovieDb && !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId)));
                var embyContentMoviesToSend   = embyContent.Where(x => x.Type == EmbyMediaType.Movie && x.HasTheMovieDb && !addedEmbyMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId)));
                var lidarrContentAlbumsToSend = lidarrContent.Where(x => !addedAlbumLogIds.Contains(x.ForeignAlbumId)).ToHashSet();
                _log.LogInformation("Plex Movies to send: {0}", plexContentMoviesToSend.Count());
                _log.LogInformation("Emby Movies to send: {0}", embyContentMoviesToSend.Count());
                _log.LogInformation("Albums to send: {0}", lidarrContentAlbumsToSend.Count());

                var plexEpisodesToSend =
                    FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).Where(x => x.Series.HasTvDb).AsNoTracking(), addedPlexEpisodesLogIds);
                var embyEpisodesToSend = FilterEmbyEpisodes(_emby.GetAllEpisodes().Include(x => x.Series).Where(x => x.Series.HasTvDb).AsNoTracking(),
                                                            addedEmbyEpisodesLogIds);

                _log.LogInformation("Plex Episodes to send: {0}", plexEpisodesToSend.Count());
                _log.LogInformation("Emby Episodes to send: {0}", embyEpisodesToSend.Count());
                var plexSettings = await _plexSettings.GetSettingsAsync();

                var embySettings = await _embySettings.GetSettingsAsync();

                var body = string.Empty;
                if (test)
                {
                    var plexm  = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie).OrderByDescending(x => x.AddedAt).Take(10);
                    var embym  = embyContent.Where(x => x.Type == EmbyMediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10);
                    var plext  = _plex.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet();
                    var embyt  = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
                    var lidarr = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet();
                    body = await BuildHtml(plexm, embym, plext, embyt, lidarr, settings, embySettings, plexSettings);
                }
                else
                {
                    body = await BuildHtml(plexContentMoviesToSend, embyContentMoviesToSend, plexEpisodesToSend, embyEpisodesToSend, lidarrContentAlbumsToSend, settings, embySettings, plexSettings);

                    if (body.IsNullOrEmpty())
                    {
                        return;
                    }
                }

                if (!test)
                {
                    // Get the users to send it to
                    var users = await _userManager.GetUsersInRoleAsync(OmbiRoles.ReceivesNewsletter);

                    if (!users.Any())
                    {
                        return;
                    }

                    foreach (var emails in settings.ExternalEmails)
                    {
                        users.Add(new OmbiUser
                        {
                            UserName = emails,
                            Email    = emails
                        });
                    }

                    var messageContent = ParseTemplate(template, customization);
                    var email          = new NewsletterTemplate();

                    var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);

                    var bodyBuilder = new BodyBuilder
                    {
                        HtmlBody = html,
                    };

                    var message = new MimeMessage
                    {
                        Body    = bodyBuilder.ToMessageBody(),
                        Subject = messageContent.Subject
                    };

                    foreach (var user in users)
                    {
                        // Get the users to send it to
                        if (user.Email.IsNullOrEmpty())
                        {
                            continue;
                        }
                        // BCC the messages
                        message.Bcc.Add(new MailboxAddress(user.Email, user.Email));
                    }

                    // Send the email
                    await _email.Send(message, emailSettings);

                    // Now add all of this to the Recently Added log
                    var recentlyAddedLog = new HashSet <RecentlyAddedLog>();
                    foreach (var p in plexContentMoviesToSend)
                    {
                        recentlyAddedLog.Add(new RecentlyAddedLog
                        {
                            AddedAt     = DateTime.Now,
                            Type        = RecentlyAddedType.Plex,
                            ContentType = ContentType.Parent,
                            ContentId   = StringHelper.IntParseLinq(p.TheMovieDbId),
                        });
                    }

                    foreach (var p in plexEpisodesToSend)
                    {
                        recentlyAddedLog.Add(new RecentlyAddedLog
                        {
                            AddedAt       = DateTime.Now,
                            Type          = RecentlyAddedType.Plex,
                            ContentType   = ContentType.Episode,
                            ContentId     = StringHelper.IntParseLinq(p.Series.TvDbId),
                            EpisodeNumber = p.EpisodeNumber,
                            SeasonNumber  = p.SeasonNumber
                        });
                    }
                    foreach (var e in embyContentMoviesToSend)
                    {
                        if (e.Type == EmbyMediaType.Movie)
                        {
                            recentlyAddedLog.Add(new RecentlyAddedLog
                            {
                                AddedAt     = DateTime.Now,
                                Type        = RecentlyAddedType.Emby,
                                ContentType = ContentType.Parent,
                                ContentId   = StringHelper.IntParseLinq(e.TheMovieDbId),
                            });
                        }
                    }

                    foreach (var p in embyEpisodesToSend)
                    {
                        recentlyAddedLog.Add(new RecentlyAddedLog
                        {
                            AddedAt       = DateTime.Now,
                            Type          = RecentlyAddedType.Emby,
                            ContentType   = ContentType.Episode,
                            ContentId     = StringHelper.IntParseLinq(p.Series.TvDbId),
                            EpisodeNumber = p.EpisodeNumber,
                            SeasonNumber  = p.SeasonNumber
                        });
                    }
                    await _recentlyAddedLog.AddRange(recentlyAddedLog);
                }
                else
                {
                    var admins = await _userManager.GetUsersInRoleAsync(OmbiRoles.Admin);

                    foreach (var a in admins)
                    {
                        if (a.Email.IsNullOrEmpty())
                        {
                            continue;
                        }
                        var messageContent = ParseTemplate(template, customization);

                        var email = new NewsletterTemplate();

                        var html = email.LoadTemplate(messageContent.Subject, messageContent.Message, body, customization.Logo);

                        await _email.Send(
                            new NotificationMessage { Message = html, Subject = messageContent.Subject, To = a.Email },
                            emailSettings);
                    }
                }
            }
            catch (Exception e)
            {
                _log.LogError(e, "Error when attempting to create newsletter");
                throw;
            }
        }
Exemple #5
0
        private async Task ProcessTv(List <ChildRequests> tv)
        {
            var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series);

            foreach (var child in tv)
            {
                var useImdb = false;
                var useTvDb = false;
                if (child.ParentRequest.ImdbId.HasValue())
                {
                    useImdb = true;
                }

                if (child.ParentRequest.TvDbId.ToString().HasValue())
                {
                    useTvDb = true;
                }

                var tvDbId = child.ParentRequest.TvDbId;
                var imdbId = child.ParentRequest.ImdbId;
                IQueryable <PlexEpisode> seriesEpisodes = null;
                if (useImdb)
                {
                    seriesEpisodes = plexEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString());
                }
                if (useTvDb && (seriesEpisodes == null || !seriesEpisodes.Any()))
                {
                    seriesEpisodes = plexEpisodes.Where(x => x.Series.TvDbId == tvDbId.ToString());
                }

                if (seriesEpisodes == null)
                {
                    continue;
                }

                if (!seriesEpisodes.Any())
                {
                    // Let's try and match the series by name
                    seriesEpisodes = plexEpisodes.Where(x =>
                                                        x.Series.Title == child.Title &&
                                                        x.Series.ReleaseYear == child.ParentRequest.ReleaseDate.Year.ToString());
                }

                var availableEpisode = new List <AvailabilityModel>();
                foreach (var season in child.SeasonRequests)
                {
                    foreach (var episode in season.Episodes)
                    {
                        if (episode.Available)
                        {
                            continue;
                        }
                        var foundEp = await seriesEpisodes.AnyAsync(
                            x => x.EpisodeNumber == episode.EpisodeNumber &&
                            x.SeasonNumber == episode.Season.SeasonNumber);

                        if (foundEp)
                        {
                            availableEpisode.Add(new AvailabilityModel
                            {
                                Id            = episode.Id,
                                EpisodeNumber = episode.EpisodeNumber,
                                SeasonNumber  = episode.Season.SeasonNumber
                            });
                            episode.Available = true;
                        }
                    }
                }

                if (availableEpisode.Any())
                {
                    await _tvRepo.Save();
                }

                // Check to see if all of the episodes in all seasons are available for this request
                var allAvailable = child.SeasonRequests.All(x => x.Episodes.All(c => c.Available));
                if (allAvailable)
                {
                    child.Available         = true;
                    child.MarkedAsAvailable = DateTime.UtcNow;
                    _log.LogInformation("[PAC] - Child request {0} is now available, sending notification", $"{child.Title} - {child.Id}");
                    // We have ful-fulled this request!
                    await _tvRepo.Save();

                    await _notificationService.Notify(new NotificationOptions
                    {
                        DateTime         = DateTime.Now,
                        NotificationType = NotificationType.RequestAvailable,
                        RequestId        = child.Id,
                        RequestType      = RequestType.TvShow,
                        Recipient        = child.RequestedUser.Email
                    });
                }
                else if (availableEpisode.Any())
                {
                    var notification = new NotificationOptions
                    {
                        DateTime         = DateTime.Now,
                        NotificationType = NotificationType.PartiallyAvailable,
                        RequestId        = child.Id,
                        RequestType      = RequestType.TvShow,
                        Recipient        = child.RequestedUser.Email,
                    };
                    notification.Substitutes.Add("Season", availableEpisode.First().SeasonNumber.ToString());
                    notification.Substitutes.Add("Episodes", string.Join(", ", availableEpisode.Select(x => x.EpisodeNumber)));
                    await _notificationService.Notify(notification);
                }
            }

            await _tvRepo.Save();
        }
Exemple #6
0
        private async Task ProcessTv()
        {
            var tv           = _tvRepo.GetChild().Where(x => !x.Available);
            var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series);

            foreach (var child in tv)
            {
                var useImdb = false;
                var useTvDb = false;
                if (child.ParentRequest.ImdbId.HasValue())
                {
                    useImdb = true;
                }

                if (child.ParentRequest.TvDbId.ToString().HasValue())
                {
                    useTvDb = true;
                }

                var tvDbId = child.ParentRequest.TvDbId;
                var imdbId = child.ParentRequest.ImdbId;
                IQueryable <PlexEpisode> seriesEpisodes = null;
                if (useImdb)
                {
                    seriesEpisodes = plexEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString());
                }
                if (useTvDb)
                {
                    seriesEpisodes = plexEpisodes.Where(x => x.Series.TvDbId == tvDbId.ToString());
                }
                foreach (var season in child.SeasonRequests)
                {
                    foreach (var episode in season.Episodes)
                    {
                        var foundEp = await seriesEpisodes.FirstOrDefaultAsync(
                            x => x.EpisodeNumber == episode.EpisodeNumber &&
                            x.SeasonNumber == episode.Season.SeasonNumber);

                        if (foundEp != null)
                        {
                            episode.Available = true;
                        }
                    }
                }

                // Check to see if all of the episodes in all seasons are available for this request
                var allAvailable = child.SeasonRequests.All(x => x.Episodes.All(c => c.Available));
                if (allAvailable)
                {
                    // We have fulfulled this request!
                    child.Available = true;
                    _backgroundJobClient.Enqueue(() => _notificationService.Publish(new NotificationOptions
                    {
                        DateTime         = DateTime.Now,
                        NotificationType = NotificationType.RequestAvailable,
                        RequestId        = child.ParentRequestId,
                        RequestType      = RequestType.TvShow,
                        Recipient        = child.RequestedUser.Email
                    }));
                }
            }

            await _tvRepo.Save();
        }
Exemple #7
0
        private async Task ProcessTv(IQueryable <ChildRequests> tv)
        {
            var plexEpisodes = _repo.GetAllEpisodes().Include(x => x.Series).AsNoTracking();

            foreach (var child in tv)
            {
                var useImdb = false;
                var useTvDb = false;
                if (child.ParentRequest.ImdbId.HasValue())
                {
                    useImdb = true;
                }

                if (child.ParentRequest.TvDbId.ToString().HasValue())
                {
                    useTvDb = true;
                }

                var tvDbId = child.ParentRequest.TvDbId;
                var imdbId = child.ParentRequest.ImdbId;
                IQueryable <PlexEpisode> seriesEpisodes = null;
                if (useImdb)
                {
                    seriesEpisodes = plexEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString());
                }
                if (useTvDb && (seriesEpisodes == null || !seriesEpisodes.Any()))
                {
                    seriesEpisodes = plexEpisodes.Where(x => x.Series.TvDbId == tvDbId.ToString());
                }

                if (seriesEpisodes == null)
                {
                    continue;
                }

                if (!seriesEpisodes.Any())
                {
                    // Let's try and match the series by name
                    seriesEpisodes = plexEpisodes.Where(x =>
                                                        x.Series.Title.Equals(child.Title, StringComparison.InvariantCultureIgnoreCase) &&
                                                        x.Series.ReleaseYear.Equals(child.ParentRequest.ReleaseDate.Year.ToString(), StringComparison.InvariantCultureIgnoreCase));
                }

                var availableEpisode = new List <AvailabilityModel>();
                foreach (var season in child.SeasonRequests)
                {
                    foreach (var episode in season.Episodes)
                    {
                        if (episode.Available)
                        {
                            continue;
                        }
                        var foundEp = await seriesEpisodes.FirstOrDefaultAsync(
                            x => x.EpisodeNumber == episode.EpisodeNumber &&
                            x.SeasonNumber == episode.Season.SeasonNumber);

                        if (foundEp != null)
                        {
                            availableEpisode.Add(new AvailabilityModel
                            {
                                Id = episode.Id
                            });
                            episode.Available = true;
                        }
                    }
                }

                //TODO Partial avilability notifications here
                foreach (var c in availableEpisode)
                {
                    await _tvRepo.MarkEpisodeAsAvailable(c.Id);
                }

                // Check to see if all of the episodes in all seasons are available for this request
                var allAvailable = child.SeasonRequests.All(x => x.Episodes.All(c => c.Available));
                if (allAvailable)
                {
                    _log.LogInformation("[PAC] - Child request {0} is now available, sending notification", $"{child.Title} - {child.Id}");
                    // We have ful-fulled this request!
                    await _tvRepo.MarkChildAsAvailable(child.Id);

                    await _notificationService.Notify(new NotificationOptions
                    {
                        DateTime         = DateTime.Now,
                        NotificationType = NotificationType.RequestAvailable,
                        RequestId        = child.Id,
                        RequestType      = RequestType.TvShow,
                        Recipient        = child.RequestedUser.Email
                    });
                }
            }

            await _tvRepo.Save();
        }